
// Adapted from https://github.com/bitfocus/companion-module-videohub by Keith Rocheck

import { VideohubConnection } from './Connection'
import { VideohubCommand } from './Command'
import { EventEmitter } from 'events'
import { InputInterface, VideohubConfigInterface, VideohubPort, PortStatus, PortDirection, PortLockAction } from './Types'
import { VideohubState } from './VideohubState'
import { VideohubReceiver } from './VideohubReceiver'

export class VideohubClient extends EventEmitter {

    private state: VideohubState

    private connection: VideohubConnection

    private receiver: VideohubReceiver

    constructor (host: string) {
        super()

        this.state = new VideohubState()
        this.receiver = new VideohubReceiver(this.state)

        this.connection = new VideohubConnection(host)
        this.connection.on('data', (key: string, data: string[]) => this.receiver.processData(key, data))

        this.connection.connect()
    }

    public getDevice (): string | undefined {
        return this.state.deviceName
    }

    public getName (): string | undefined {
        return this.state.name
    }

    public getConfig (): VideohubConfigInterface {
        return this.state.config
    }

    public getPortLabel (type: VideohubPort, id: number): string | null {
        const item: InputInterface[] = this.state.getItem(type)

        if (item[id] !== undefined) {
            return item[id].name
        }

        return null
    }

    public getPortStatus (type: VideohubPort, id: number): PortStatus | null {
        const item: InputInterface[] = this.state.getItem(type)

        if (item[id] !== undefined) {
            return item[id].status
        }

        return null
    }

    public getOutputRouting (id: number): number | null {
        if (!this.state.hasItem(VideohubPort.Output, id)) {
            return null
        }

        return this.state.getOutput(id).route
    }

    public getMonitoringRouting (id: number): number | null {
        if (!this.state.hasItem(VideohubPort.Monitoring, id)) {
            return null
        }

        return this.state.getMonitoringOutput(id).route
    }

    public getSerialRouting (id: number): number | null {
        if (!this.state.hasItem(VideohubPort.Serial, id)) {
            return null
        }

        return this.state.getSerial(id).route
    }

    public getSerialDirection (id: number): PortDirection | null {
        if (!this.state.hasItem(VideohubPort.Serial, id)) {
            return null
        }

        return this.state.getSerial(id).direction
    }

    public setName (name: string): void {
        const cmd = new VideohubCommand('VIDEOHUB DEVICE')
        cmd.addParameter('Friendly name', name)

        this.connection.send(cmd)
    }

    public setLabel (type: VideohubPort, id: number, label: string): void {
        let header: string | undefined
        switch (type) {
            case VideohubPort.Input:
                header = 'INPUT LABELS'
                break
            case VideohubPort.Output:
                header = 'OUTPUT LABELS'
                break
            case VideohubPort.Monitoring:
                header = 'MONITORING OUTPUT LABELS'
                break
            case VideohubPort.Serial:
                header = 'SERIAL PORT LABELS'
                break
            default:
                return
        }

        const cmd = new VideohubCommand(header)
        cmd.addParameter(id, label)

        this.connection.send(cmd)
    }

    public setLock (type: VideohubPort, id: number, lock: PortLockAction): void {
        let header: string | undefined
        switch (type) {
            case VideohubPort.Output:
                header = 'VIDEO OUTPUT LOCKS'
                break
            case VideohubPort.Monitoring:
                header = 'MONITORING OUTPUT LOCKS'
                break
            case VideohubPort.Serial:
                header = 'SERIAL PORT LOCKS'
                break
            default:
                return
        }

        const cmd = new VideohubCommand(header)
        cmd.addParameter(id, lock)

        this.connection.send(cmd)
    }

    public setRouting (type: VideohubPort, id: number, src: number): void {
        let header: string | undefined
        switch (type) {
            case VideohubPort.Output:
                header = 'VIDEO OUTPUT ROUTING'
                break
            case VideohubPort.Monitoring:
                header = 'MONITORING VIDEO OUTPUT ROUTING'
                break
            case VideohubPort.Serial:
                header = 'SERIAL PORT ROUTING'
                break
            default:
                return
        }

        const cmd = new VideohubCommand(header)
        cmd.addParameter(id, src)

        this.connection.send(cmd)
    }

    public setSerialDirection (type: VideohubPort, id: number, direction: PortDirection): void {
        let header: string | undefined
        switch (type) {
            case VideohubPort.Serial:
                header = 'SERIAL PORT DIRECTIONS'
                break
            default:
                return
        }

        const cmd = new VideohubCommand(header)
        cmd.addParameter(id, direction)

        this.connection.send(cmd)
    }
}
