//
//  Network.swift
//  HARKlibSample
//
//  Created by Tomoyoshi Kinoshita on 2021/04/15.
//

import Foundation
import HARKlib

class HARKNetworkDef: HARKlib.NetworkDef
{
    override func build(_ network: Network, input: DataSourceMap, output: DataSinkMap)
    {
        let hark_network = HARKNetwork(network)
        let hark_input = input
        let hark_output = output
        
        self.build(hark_network, input:hark_input, output:hark_output)
    }
    
    func build(_ network:HARKNetwork, input:HARKDataSourceMap, output:HARKDataSinkMap)
    {
        
    }
}

class HARKNode
{
    let inner: HARKlib.BaseNode
    
    init(_ node: HARKlib.BaseNode)
    {
        self.inner = node
    }
    
    @discardableResult
    func add_input(_ name: String, source: HARKDataSource) -> HARKNode
    {
        self.inner.add_input(name, source: source)
        return self
    }
    
    @discardableResult
    func add_input(_ name: String, string: String) -> HARKNode
    {
        self.inner.add_input(name, string: string)
        return self
    }
    
    @discardableResult
    func add_input(_ name: String, number: NSNumber) -> HARKNode
    {
        self.inner.add_input(name, number: number)
        return self
    }
    
    @discardableResult
    func add_input(_ name: String, boolean: Bool) -> HARKNode
    {
        self.inner.add_input(name, boolean: boolean)
        return self
    }

    @discardableResult
    func loop_condition(_ source: HARKDataSource) -> HARKNode
    {
        self.inner.loop_condition(source)
        return self
    }

    func get(_ name: String) -> HARKDataSource
    {
        self.inner.get(name)
    }
}

class HARKNetwork
{
    let inner: HARKlib.Network
    
    init(_ network: HARKlib.Network)
    {
        self.inner = network
    }

    func create<T>(_ type: T.Type) -> HARKNode where T: HARKlib.NodeDef
    {
        return HARKNode(self.inner.createNode(T(), name: "node"))
    }

    func create<T, D>(_ type: T.Type, dispatcher: D.Type) -> HARKNode where T: HARKlib.NodeDef, D: HARKlib.BaseDispatcher
    {
        return HARKNode(self.inner.createNode(T(), name: "node", dispatcher: D()))
    }

    func create<T>(_ type: T.Type, name: String) -> HARKNode where T: HARKlib.NodeDef
    {
        return HARKNode(self.inner.createNode(T(), name: name))
    }

    func create<T>(_ type: T.Type, name: String) -> HARKNetwork where T: HARKlib.NetworkDef
    {
        return HARKNetwork(self.inner.createNetwork(T(), name: name))
    }
    
    func create<T, D>(_ type: T.Type, dispatcher: D.Type, name: String) -> HARKNode where T: HARKlib.NodeDef, D: HARKlib.BaseDispatcher
    {
        return HARKNode(self.inner.createNode(T(), name: name, dispatcher: D()))
    }

    func create<T, D>(_ type: T.Type, dispatcher: D.Type, name: String) -> HARKNetwork where T: HARKlib.NetworkDef, D: HARKlib.BaseDispatcher
    {
        return HARKNetwork(self.inner.createNetwork(T(), name: name, dispatcher: D()))
    }
    
    static func create<T>(_ type: T.Type, name: String) -> HARKNetwork where T: HARKlib.NetworkDef
    {
        return HARKNetwork(HARKlib.Network.createNetwork(T(), name: name))
    }
    
    func execute()
    {
        self.inner.execute()
    }

    func stop()
    {
        self.inner.stop()
    }

    @discardableResult
    func add_input(_ name: String, source: HARKDataSource) -> HARKNetwork
    {
        self.inner.add_input(name, source: source)
        return self
    }
    
    @discardableResult
    func add_input(_ name: String, string: String) -> HARKNetwork
    {
        self.inner.add_input(name, string: string)
        return self
    }
    
    @discardableResult
    func add_input(_ name: String, number: NSNumber) -> HARKNetwork
    {
        self.inner.add_input(name, number: number)
        return self
    }
    
    @discardableResult
    func add_input(_ name: String, boolean: Bool) -> HARKNetwork
    {
        self.inner.add_input(name, boolean: boolean)
        return self
    }

    @discardableResult
    func loop_condition(_ source: HARKDataSource) -> HARKNetwork
    {
        self.inner.loop_condition(source)
        return self
    }

    func get(_ name: String) -> HARKDataSource
    {
        self.inner.get(name)
    }
    
    func query_node(_ name: String) -> HARKlib.NodeDef?
    {
        return self.inner.query_nodedef(name)
    }
}

typealias HARKDataSourceMap = HARKlib.DataSourceMap
typealias HARKDataSinkMap = HARKlib.DataSinkMap
typealias HARKDataSource = HARKlib.DataSource
typealias HARKDataSink = HARKlib.DataSink
