import {commonSettings,globalSettings} from "./commonSettings";
import {ControllerEnum} from "./yoctopuce_plugin";


export class PI_handler
{
    private    websocket      : WebSocket | null = null;
    private    uuid           : string = "";
    private    actionInfo     : any = {};
    protected  deviceSettings : commonSettings;
    protected  hubSettings    : globalSettings;
    protected  get settings() : any {return null}
    private    controllertype : ControllerEnum ;



    constructor(inPort: string, inUUID: string, inRegisterEvent: any, inInfo:any,inActionInfo:string, settings:commonSettings)
    {   this.deviceSettings = settings;
        this.hubSettings    = new  globalSettings();
        // this is our global websocket, used to communicate from/to Stream Deck software
        // and some info about our plugin, as sent by Stream Deck software
        this.uuid = inUUID;
        // please note: the incoming arguments are of type STRING, so
        // in case of the inActionInfo, we must parse it into JSON first
        this.actionInfo = JSON.parse(inActionInfo); // cache the info
        this.websocket = new WebSocket('ws://localhost:' + inPort);
        this.websocket.onmessage =  (evt :MessageEvent ) =>{this.onMessage(this,evt)};

        let actionInfo = JSON.parse(inActionInfo);
        this.controllertype  =ControllerEnum.KEYPAD;
        if ( "payload" in  actionInfo)
           if (  "controller" in actionInfo["payload"])
             {  this.controllertype =  actionInfo["payload"]['controller'] == "Encoder" ? ControllerEnum.ENCODER :ControllerEnum.KEYPAD;
             }


        // if connection was established, the websocket sends
        // an 'onopen' event, where we need to register our PI
        this.websocket.onopen =  () =>
        {
            var json = {
                event:  inRegisterEvent,
                uuid:   inUUID
            };
            // register property inspector to Stream Deck
            this.websocket?.send(JSON.stringify(json));
            this.getGlobalSettings();
            this.getSettings();

        }
    }

    public get controller() {return this.controllertype}

    protected getGlobalSettings()
    {  var json = {  "event": "getGlobalSettings","context": this.uuid };
        this.websocket?.send(JSON.stringify(json));

    }

    protected getSettings()
    {  var json = {  "event": "getSettings","context": this.uuid };
        this.websocket?.send(JSON.stringify(json));
    }

    protected saveSettings(settings :any)
    {   var json = { "event": "setSettings", "context": this.uuid,  "payload": settings }
        this.websocket?.send(JSON.stringify(json));
    }

    protected saveGlobalSettings(settings :any)
    {   console.log("save gloval settings")
        var json = { "event": "setGlobalSettings", "context": this.uuid,  "payload": this.hubSettings }
        this.websocket?.send(JSON.stringify(json));
    }

    private onMessage(source :PI_handler ,evt:MessageEvent)
    {   let jsonObj = JSON.parse(evt.data);
        let event   = jsonObj['event'];
        let action  = jsonObj['action'];
        let context = jsonObj['context'];
        let jsonPayload = jsonObj['payload'] || {};
        console.log("received "+event.toString())
        switch (event)
        {  case "didReceiveSettings" :
               this.didReceiveSettings(context,jsonPayload["settings"]);
               break;
           case "didReceiveGlobalSettings":
               this.didReceiveGlobalSettings(context,jsonPayload["settings"]);
               break;
           case "sendToPropertyInspector":
               this.sendToPropertyInspector(context,jsonPayload["type"], jsonPayload["data"])
               break
        }
    }


    protected didReceiveGlobalSettings(context: any,unknownSettings: any)
    {  let global = new globalSettings()
       if (!global.set(unknownSettings)) return ;
       let HubAddr :HTMLInputElement |null = document.getElementById("HubAddr") as HTMLInputElement;
       HubAddr.value = global.hubAddrList;

    }

    protected didReceiveSettings(context: any,unknownSettings: any) :boolean
    {   if (!this.settings.set(unknownSettings)) return false;
        let deviceList :HTMLSelectElement |null = document.getElementById("deviceList") as HTMLSelectElement;

        deviceList.value = this.settings.hwdName;

        if (deviceList==null) return true;
        let options : HTMLOptionsCollection = deviceList.options;
        let found :boolean = false;
        for (let option   of options) if (option.value == this.settings.hwdName) found=true;
        if (!found)
        { let option : HTMLOptionElement = document.createElement("OPTION") as HTMLOptionElement;
            option.value = this.settings.hwdName;
            option.label = this.settings.friendlyName;
            deviceList.options.add(option);
        }
        deviceList.value = this.settings.hwdName;
        deviceList.disabled=false;
        return true;
    }

    protected updatedeviceList(data : any)
    {
        let select :HTMLSelectElement  = document.getElementById("deviceList") as HTMLSelectElement;
        if (select==null) return;
        let options : HTMLOptionsCollection = select.options;
        for (let i=0;i<data.length;i++)   // quadratic loop !
        {  let found :boolean = false;
            for (let option   of options)
                if (option.value == data[i]["hwdName"])
                { option.label =  data[i]["friendlyname"]+ (data[i]["online"] ? "" : " (OFFLINE)");
                    found=true;
                }
            if (!found)
            {  let option : HTMLOptionElement = document.createElement("OPTION") as HTMLOptionElement;
                option.value = data[i]["hwdName"]
                option.label = data[i]["friendlyname"] + (data[i]["online"]?"":" (OFFLINE)");
                select.options.add(option);
                select.disabled=false;
            }
        }
    }

    /*******************************
     * called when a Properties inpector field has changed
     *******************************/

    protected inspectorValueHasChanged(source: HTMLInputElement | HTMLSelectElement)
    {
        switch (source.id)
        {
            case  'HubAddr':
                //this.deviceSettings.hubAddr = source.value;
                //this.saveSettings(this.deviceSettings);
                this.hubSettings.hubAddrList = source.value;
                this.saveGlobalSettings(this.hubSettings);
                break;
            case  'deviceList':
                this.deviceSettings.hwdName = source.value;
                this.deviceSettings.friendlyName = (source as HTMLSelectElement).options[(source as HTMLSelectElement).selectedIndex].label
                this.saveSettings(this.deviceSettings);
                break;
        }
    }


    protected   sendToPropertyInspector(context:any,dataname:string,data:any)
    {   switch (dataname)
         {  case "devList" :
               console.log("received devices list, length="+data.length);
               this.updatedeviceList(data);
                break;
        }
    }


}