/*********************************************************************
 *
 *  $Id: app.ts 32624 2018-10-10 13:23:29Z seb $
 *
 *  Yoctopuce Plugin to ELGATO  StreamDeck
 *
 *
 *********************************************************************/


import { YCurrentLoopOutput } from 'yoctolib-esm/yocto_currentloopoutput.js'
import {
  StreamDeckAction,
  YoctopuceDeviceHandler,
  ControllerEnum,
  PluginDispatcher
} from '../common_code/yoctopuce_plugin.js'
import { CircularGauge } from '../common_code/icons.js'
import { currentLoopOutputSettings } from './currentLoopOutput_settings.js'
import { YAPI, YFunction} from "yoctolib-esm/yocto_api";


export class  StreamDeck_YCurrentLoopOutputSettingsAction extends StreamDeckAction
 {  public  static readonly  ManagedFunctionType = "currentLoopOutput"
    static  get actionUUID() : string {return "com.yoctopuce."+StreamDeck_YCurrentLoopOutputSettingsAction.ManagedFunctionType+ ".action"; }
    public  get ManagedFunctionType() { return   StreamDeck_YCurrentLoopOutputSettingsAction.ManagedFunctionType }
    private  currentSettings   : currentLoopOutputSettings = new currentLoopOutputSettings();
    private  currentLoopOutput : YCurrentLoopOutput | null =null;
    private  lastValue : number = YCurrentLoopOutput.CURRENT_INVALID;
    private  bg_LOOP     : HTMLImageElement = null as any;
    private  lastImage: HTMLImageElement = null as any ;
    private  gauge : CircularGauge= null as any ;
    private  lastEncoderSetTime : number =0;
    private  lastEncoderSetValue : number =0;


   /*******************************
    * notify the system which Yoctopuce function type is handled by the plugin
    *  must be called at at application start
    *******************************/

    public  static registerFunctionType()
    {
      YoctopuceDeviceHandler.registerFunctionType(StreamDeck_YCurrentLoopOutputSettingsAction.ManagedFunctionType);
    }

   /*******************************
    * constructor, auttomatically called when a new action is created
    *******************************/

    constructor(uuid:string)
    {   super(uuid);
        YoctopuceDeviceHandler.registerAction(this.ManagedFunctionType,this);
    }

   /*******************************
    * local init
    *******************************/

   public async init()
   { this.bg_LOOP = await StreamDeckAction.newImage("currentLoopOutput_action.svg")
     this.lastImage = await StreamDeckAction.newImage("currentLoopOutput_action.svg")
   }

   /*******************************
    * return actions settings
    *******************************/
   protected get settings(): currentLoopOutputSettings{return this.currentSettings; }

   /*******************************
    * called when the device linked to the action is appearing
    *******************************/

   protected  async functionArrival(hwdname:string)
   { if (this.currentLoopOutput)
   {
     this.valueChanged(this.currentLoopOutput, await this.currentLoopOutput.get_advertisedValue());
   }}

   /*******************************
    * called when the device linked to the action is disappearing
    *******************************/

   protected  async functionRemoval(hwdname:string)
   { this.redrawIcon(); }

   /*******************************
    * called when the key or rotary button is pressed down
    *******************************/

   public  async onKeyDown(context: any, settings: any, coordinates: any, userDesiredState: any)
   {
     if (this.currentLoopOutput!=null)
       if (await this.currentLoopOutput.isOnline())
         switch  (this.currentSettings.action)
         {   case "MOMENTARY":  await this.currentLoopOutput.currentMove(this.currentSettings.targetmin,this.delaytotarget( this.currentSettings.targetmin) );  break;
         }
   }

   /*******************************
    * called when the key or rotary button is pressed up
    *******************************/

   public async onKeyUp(context: any, settings: any, coordinates: any, userDesiredState: any)
   {

     if (this.currentLoopOutput != null)
       if (await this.currentLoopOutput.isOnline())
         switch (this.currentSettings.action)
         {
           case "MOVE"          :
             await this.currentLoopOutput.currentMove(this.currentSettings.targetmin, this.delaytotarget( this.currentSettings.targetmin));
             break;
           case "MOMENTARY"     :
             await this.currentLoopOutput.currentMove(this.currentSettings.targetmax, this.delaytotarget( this.currentSettings.targetmax));
             break;
           case "TOGGLE"        :
             if (this.lastValue == YCurrentLoopOutput.CURRENT_INVALID) this.lastValue = await this.currentLoopOutput.get_current();
             if  (this.lastValue != YCurrentLoopOutput.CURRENT_INVALID)
             {  let median: number = (this.currentSettings.targetmin + this.currentSettings.targetmax) / 2;
               let min: number = this.currentSettings.targetmin < this.currentSettings.targetmax ? this.currentSettings.targetmin : this.currentSettings.targetmax;
               let max: number = this.currentSettings.targetmin > this.currentSettings.targetmax ? this.currentSettings.targetmin : this.currentSettings.targetmax;
               if (this.lastValue < median) await this.currentLoopOutput.currentMove(max, this.delaytotarget(max));
               else await this.currentLoopOutput.currentMove(min, this.delaytotarget(min));
             } else await this.currentLoopOutput.currentMove(this.currentSettings.targetmin, this.delaytotarget( this.currentSettings.targetmin));
             break;
         }
   }

   /*******************************
    * called the button was turned
    *******************************/

   public async dialRotate (context: any, settings: any, coordinates: any,  ticks:number, pressed:boolean)
   { let now : number =  await YAPI.GetTickCount();
     let newValue : number;
     let inc :number = Math.sign(ticks)*(ticks*ticks)/10;
     if  ((now- this.lastEncoderSetTime)   <250)
        {  newValue  = this.lastEncoderSetValue + inc;
          this.encoderRotate(newValue)

          this.lastEncoderSetTime = now;
        }
      else
       {  newValue =  this.lastValue+inc
         this.encoderRotate(newValue)  ;
       }
     this.lastEncoderSetValue = newValue;

   }

   /*******************************
    * called the device current value has changed
    *******************************/

   // called from top whenever a CurrentLoopOutput value has changed
   public valueChanged(source: YCurrentLoopOutput, value: string)
   {
     if (source == this.currentLoopOutput)
     {
       if (value == "NOPWR")
         this.gauge.setValue(0, "NOPOWER")
       else
         {
         let fvalue: number = parseFloat(value);
         if (fvalue < 0) fvalue = 0;
         if (fvalue > 20) fvalue = 20;
         this.lastValue = fvalue;
         this.gauge.setValue(100.0 * fvalue / 20.0, fvalue.toFixed(1) )
       }
       this.redrawIcon();


     }
   }

   /*******************************
    * redraw the action icon
    *******************************/
   protected async redrawIcon()
   {
     if (this.currentLoopOutput != null)
     { let online: boolean = await this.currentLoopOutput.isOnline()

       this.lastImage = new Image();
       this.lastImage.onload = () =>
       { if (this.controller == ControllerEnum.ENCODER)
       { let image :string =   PluginDispatcher.HTMLImageElement2url( this.lastImage , null);
         PluginDispatcher.setFeedback(this.UUID, {"full-canvas": image })
       }
       else this.setBgImage(this.UUID, this.lastImage)
       }
       this.gauge.offline = !online;
       let url:string = this.gauge.asURL
       this.lastImage.src =url ;

     } else this.setBgImage(this.UUID, this. bg_LOOP )
   }

   /*******************************
    * called with local settings
    *******************************/
   public async didReceiveSettings(context: any, settings: any, coordinates: any)
   {
     super.didReceiveSettings(context, settings, coordinates)
     if (this.currentSettings.hwdName!="")
     {   console.log("name= " + this.currentSettings.hwdName + " action=" + this.currentSettings.action );
       this.currentLoopOutput = await YCurrentLoopOutput.FindCurrentLoopOutput(this.currentSettings.hwdName);
       await this.currentLoopOutput.registerValueCallback((source:YFunction,value:string)=>{this.broadcastValueChange(source,value);})
       await this.redrawIcon();
     } else  console.log("currentLoopOutput name not set");
   }

   /*******************************
    * called with global settings
    *******************************/
   public async didReceiveGlobalSettings(context: any,  settings: any){  }

   /*******************************
    * called when the action is about to be shown
    *******************************/
   public async onWillAppear(context: any, controller: ControllerEnum, settings: any, coordinates: any)
   {
     super.onWillAppear(context, controller, settings, coordinates)
     console.log("onWillAppear" + JSON.stringify(settings))
     if (this.controller == ControllerEnum.ENCODER)
       this.gauge = new CircularGauge(200, 100, 100, 68, 15, 30, 90, 360, 0, "mA")
     else
       this.gauge = new CircularGauge(72, 72, 30, 30, 12, 24, 90, 360, 0, "mA")
     await this.didReceiveSettings(context, settings, coordinates)

   }

   /*******************************
    * extra stuff
    *******************************/
   private async encoderRotate(value :number)
   {

     if (value < 4) value = 4;
     if (value > 20) value = 20;
     if (this.currentLoopOutput != null)
       if (await this.currentLoopOutput.isOnline())
         await this.currentLoopOutput.set_current(value);
   }


   public delaytotarget( targetValue:number)
   {  let distance= Math.abs(targetValue-this.lastValue)
     return  this.currentSettings.delay * distance / Math.abs(this.currentSettings.targetmax - this.currentSettings.targetmin)
   }


 }

/*******************************
 * important!
 *******************************/

StreamDeck_YCurrentLoopOutputSettingsAction.registerFunctionType();
// @ts-ignore




