#!/usr/bin/env ruby
#
# Generates bindings and implementions for test cde.
#
# This file is a bit of a mess frankly and you may need
# to alternate between running this and genhello.sh
# a few times to get new types to compile cleanly.
#

types = ["boolean", "byte", "char", "short", "int", "long", "float", "double", "String", "TestListener"];

swiftTypes = {
    'boolean' => 'Bool',
    'byte' => 'Int8',
    'char' => 'UInt16',
    'short' => 'Int16',
    'int' => 'Int',
    'long' => 'Int64',
    'float' => 'Float',
    'double' => 'Double',
    'String' => 'String',
    'TestListener' => 'SwiftHelloTest_TestListener'
}

arrayException = {
    'int' => 'Int32'
}

referenceException = {
    'boolean' => 'true',
    'String' => '"123"',
    'TestListener' => 'SwiftTestListener()'
}

referenceExceptionJava = {
    'boolean' => 'true',
    'String' => '"123"',
    'TestListener' => 'new SwiftTestListener()'
}

java = File.open( "src/org/swiftjava/SwiftTest.java", "w" )
java2 = File.open( "src/com/johnholdsworth/swiftbindings/SwiftHelloTest.java", "w" )

java.puts( <<JAVA )

package org.swiftjava;

// auto generated by ../../../gentests.rb

import com.johnholdsworth.swiftbindings.SwiftHelloTest.TestListener;

public class SwiftTest {

    public TestListener loopback;

    public SwiftTest() {
    }

JAVA
    
java2.puts( <<JAVA )

// auto generated by ../../../../gentests.rb

package com.johnholdsworth.swiftbindings;

import com.johnholdsworth.swiftbindings.SwiftHelloTypes.TextListener;
import com.johnholdsworth.swiftbindings.SwiftHelloTypes.ListenerMap;
import com.johnholdsworth.swiftbindings.SwiftHelloTypes.ListenerMapList;

public interface SwiftHelloTest {

    public interface TestListener {

        public void setLoopback( TestListener loopback );

JAVA
        

swift = File.open( "org_swiftjava/test_body.swift", "w" )
swift2 = File.open( "com_johnholdsworth/Sources/SwiftHelloTestImpl.swift", "w" )

swift2.puts( <<SWIFT )

// auto generated by ../../gentests.rb

import java_swift
import Foundation

public class SwiftTestListener: SwiftHelloTest_TestListenerBase {

    var loopback: SwiftHelloTest_TestListener?

SWIFT

for type in types

    java.puts( <<JAVA )
    public static #{type} #{type}FieldStatic;
    public #{type} #{type}Field;

    public static #{type} #{type}MethodStatic( #{type} arg ) {
        return arg;
    }

    public #{type} #{type}Method( #{type} arg ) {
        return loopback != null ? loopback.#{type}Method( arg ) : arg;
    }

    public static #{type} #{type}ArrayFieldStatic[];
    public #{type} #{type}ArrayField[];

    public static #{type}[] #{type}ArrayMethodStatic( #{type} arg[] ) {
        return arg;
    }

    public #{type}[] #{type}ArrayMethod( #{type} arg[] ) {
        return loopback != null ? loopback.#{type}ArrayMethod( arg ) : arg;
    }

    public static #{type} #{type}2dArrayFieldStatic[][];
    public #{type} #{type}2dArrayField[][];

    public static #{type}[][] #{type}2dArrayMethodStatic( #{type} arg[][] ) {
        return arg;
    }

    public #{type}[][] #{type}2dArrayMethod( #{type} arg[][] ) {
        return loopback != null ? loopback.#{type}2dArrayMethod( arg ) : arg;
    }

JAVA

    java2.puts( <<JAVA )
        public #{type} #{type}Method( #{type} arg );
        public #{type}[] #{type}ArrayMethod( #{type} arg[] );
        public #{type}[][] #{type}2dArrayMethod( #{type} arg[][] );

JAVA

    swift.puts( <<SWIFT )

        if true {
            let reference: #{swiftTypes[type]} = #{referenceException[type] || '123'}
            let referenceArray = [#{arrayException[type] || ''}(reference)]
            let reference2dArray = [referenceArray]

            SwiftTest.#{type}FieldStatic = reference
            XCTAssertEqual( SwiftTest.#{type}FieldStatic, reference )
//            instance.#{type}Field = reference
//            XCTAssertEqual( instance.#{type}Field, reference )

            SwiftTest.#{type}ArrayFieldStatic = referenceArray
            XCTAssertEqual( SwiftTest.#{type}ArrayFieldStatic, referenceArray )
//            instance.#{type}ArrayField = referenceArray
//            XCTAssertEqual( instance.#{type}ArrayField, referenceArray )

            SwiftTest.#{type}2dArrayFieldStatic = reference2dArray
            XCTAssertEqual( SwiftTest.#{type}2dArrayFieldStatic[0], reference2dArray[0] )
//            instance.#{type}2dArrayField = reference2dArray
//            XCTAssertEqual( instance.#{type}2dArrayField[0], reference2dArray[0] )

//            XCTAssertEqual( SwiftTest.#{type}MethodStatic( reference ), reference )
            XCTAssertEqual( instance.#{type}Method( reference ), reference )

//            XCTAssertEqual( SwiftTest.#{type}ArrayMethodStatic( referenceArray ), referenceArray )
            XCTAssertEqual( instance.#{type}ArrayMethod( referenceArray ), referenceArray )

//            XCTAssertEqual( SwiftTest.#{type}2dArrayMethodStatic( reference2dArray )[0], reference2dArray[0] )
            XCTAssertEqual( instance.#{type}2dArrayMethod( reference2dArray )[0], reference2dArray[0] )
        }
SWIFT

    opt = type == "String" || type == "TestListener" ? "?" : ""
    atype = arrayException[type] || swiftTypes[type]
    swift2.puts( <<SWIFT )
    override public func #{type}Method( arg: #{swiftTypes[type]}#{opt} ) -> #{swiftTypes[type]}#{opt} {
        return loopback?.#{type}Method( arg: arg ) ?? arg
    }

    override public func #{type}ArrayMethod( arg: [#{atype}]? ) -> [#{atype}]? {
        return loopback?.#{type}ArrayMethod( arg: arg ) ?? arg
    }

    override public func #{type}2dArrayMethod( arg: [[#{atype}]]? ) -> [[#{atype}]]? {
        return loopback?.#{type}2dArrayMethod( arg: arg ) ?? arg
    }

SWIFT
end

java2.puts( <<JAVA )
        public ListenerMap testMap( ListenerMap arg );
        public ListenerMapList testMapList( ListenerMapList arg );

    }

    public static class TestResponderAdapter implements TestListener {

        public TestListener loopback;

        public void setLoopback( TestListener loopback ) {
            this.loopback = loopback;
        }

JAVA

swift2.puts( <<SWIFT )
}

public class SwiftTestResponder {

    static var tcount = 0

    public func respond( to responder: SwiftHelloTest_TestListener ) {
        SwiftTestResponder.tcount += 1
        NSLog("Swift -> Java \\(SwiftTestResponder.tcount)...")
SWIFT

for type in types
    java2.puts( <<JAVA )
        public #{type} #{type}Method( #{type} arg ) {
            return loopback != null ? loopback.#{type}Method( arg ) : arg;
        }

        public #{type}[] #{type}ArrayMethod( #{type} arg[] ) {
            return loopback != null ? loopback.#{type}ArrayMethod( arg ) : arg;
        }

        public #{type}[][] #{type}2dArrayMethod( #{type} arg[][] ) {
            return loopback != null ? loopback.#{type}2dArrayMethod( arg ) : arg;
        }

JAVA

    swift2.puts( <<SWIFT )

        if true {
            let reference: #{swiftTypes[type]} = #{referenceException[type] || '123'}
            let referenceArray = [#{arrayException[type] || ''}(reference)]
            let reference2dArray = [referenceArray]

            let response = responder.#{type}Method( arg: reference )
            let responseArray = responder.#{type}ArrayMethod( arg: referenceArray )!
            _ = responder.#{type}2dArrayMethod( arg: reference2dArray )
SWIFT

    if swiftTypes[type] != "SwiftHelloTest_TestListener" then
        swift2.puts( <<SWIFT )

            if response != reference {
                NSLog("#{swiftTypes[type]}: \\(String(describing: response)) != \\(reference)")
            }
            if responseArray != referenceArray {
                NSLog("#{swiftTypes[type]}: \\(responseArray) != \\(referenceArray)")
            }
SWIFT
    end
    swift2.puts( <<SWIFT )
        }

SWIFT
end

java2.puts( <<JAVA )
        public ListenerMap testMap( ListenerMap arg ) {
            return loopback != null ? loopback.testMap( arg ) : arg;
        }

        public ListenerMapList testMapList( ListenerMapList arg ) {
            return loopback != null ? loopback.testMapList( arg ) : arg;
        }

    }

    public static class SwiftTestListener extends TestResponderAdapter {

        static int tcount = 0;

        public void respond( TestListener responder ) {
            tcount += 1;
            System.out.println("Java -> Swift "+tcount+"...");

JAVA

for type in types
    java2.puts( <<SWIFT )

            if ( true ) {
                #{type} reference = #{referenceExceptionJava[type] || '123'};
                #{type} referenceArray[] = new #{type} [] {reference};
                #{type} reference2dArray[][] = new #{type} [][] {referenceArray};

                #{type} response = responder.#{type}Method( reference );
                #{type} responseArray[] = responder.#{type}ArrayMethod( referenceArray );
                #{type} response2dArray[][] = responder.#{type}2dArrayMethod( reference2dArray );
SWIFT
    if swiftTypes[type] != "SwiftHelloTest_TestListener" && type != "String" then
        java2.puts( <<SWIFT )

                if ( response != reference ) {
                    System.out.println("#{swiftTypes[type]}: "+response+" != "+reference);
                }
                if ( responseArray[0] != referenceArray[0] ) {
                    System.out.println("#{swiftTypes[type]}: "+responseArray[0]+" != "+referenceArray[0]);
                }
                if ( response2dArray[0][0] != reference2dArray[0][0] ) {
                    System.out.println("#{swiftTypes[type]}: "+response2dArray[0][0]+" != "+reference2dArray[0][0]);
                }
SWIFT
    end
    java2.puts( <<SWIFT )
            }
SWIFT
end

swift2.puts( "    }\n\n}\n" )
swift2.close()
swift.close()

java2.puts( "       }\n\n    }\n\n}\n" )
java2.close()

java.puts( "}\n" )
java.close()

system( "./genjar.sh && ./genswift.sh org/swiftjava/SwiftTest swiftjava.jar" );
