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


import { YVoltageOutput } from 'yoctolib-esm/yocto_voltageoutput.js'
import {
  StreamDeckAction,
  YoctopuceDeviceHandler,
  ControllerEnum,
  PluginDispatcher
} from '../common_code/yoctopuce_plugin.js'
import { CircularGauge } from '../common_code/icons.js'
import { voltageOutputSettings } from './voltageOutput_settings.js'
import { YAPI, YFunction} from "yoctolib-esm/yocto_api";


export class  StreamDeck_YVoltageOutputSettingsAction extends StreamDeckAction
 {  public  static readonly  ManagedFunctionType = "voltageOutput"
    static  get actionUUID() : string {return "com.yoctopuce."+StreamDeck_YVoltageOutputSettingsAction.ManagedFunctionType+ ".action"; }
    public  get ManagedFunctionType() { return   StreamDeck_YVoltageOutputSettingsAction.ManagedFunctionType }
    private  currentSettings   : voltageOutputSettings = new voltageOutputSettings();
    private  voltageOutput : YVoltageOutput | null =null;
    private  lastValue : number = YVoltageOutput.CURRENTVOLTAGE_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_YVoltageOutputSettingsAction.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("voltageOutput_action.svg")
     this.lastImage = await StreamDeckAction.newImage("voltageOutput_action.svg")
   }

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

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

   protected  async functionArrival(hwdname:string)
   { if (this.voltageOutput)
   {
     this.valueChanged(this.voltageOutput, await this.voltageOutput.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.voltageOutput!=null)
       if (await this.voltageOutput.isOnline())
         switch  (this.currentSettings.action)
         {   case "MOMENTARY":  await this.voltageOutput.voltageMove(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.voltageOutput != null)
       if (await this.voltageOutput.isOnline())
         switch (this.currentSettings.action)
         {
           case "MOVE"          :
             await this.voltageOutput.voltageMove(this.currentSettings.targetmin, this.delaytotarget( this.currentSettings.targetmin));
             break;
           case "MOMENTARY"     :
             await this.voltageOutput.voltageMove(this.currentSettings.targetmax, this.delaytotarget( this.currentSettings.targetmax));
             break;
           case "TOGGLE"        :
             if (this.lastValue == YVoltageOutput.CURRENTVOLTAGE_INVALID) this.lastValue = await this.voltageOutput.get_currentVoltage();
             if  (this.lastValue != YVoltageOutput.CURRENTVOLTAGE_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.voltageOutput.voltageMove(max, this.delaytotarget(max));
               else await this.voltageOutput.voltageMove(min, this.delaytotarget(min));
             } else await this.voltageOutput.voltageMove(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 VoltageOutput value has changed
   public valueChanged(source: YVoltageOutput, value: string)
   {
     if (source == this.voltageOutput)
     {
         let fvalue: number = parseFloat(value);
         if (fvalue < 0) fvalue = 0;
         if (fvalue > 10) fvalue = 10;
         this.lastValue = fvalue;
         this.gauge.setValue(100.0 * fvalue / 10.0, fvalue.toFixed(1) );
         this.redrawIcon();



     }
   }

   /*******************************
    * redraw the action icon
    *******************************/

   protected async redrawIcon()
   {
     if (this.voltageOutput != null)
     { let online: boolean = await this.voltageOutput.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.voltageOutput = await YVoltageOutput.FindVoltageOutput(this.currentSettings.hwdName);
       await this.voltageOutput.registerValueCallback((source:YFunction,value:string)=>{this.broadcastValueChange(source,value);})
       await this.redrawIcon();
     } else  console.log("voltageOutput 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, "V")
     else
       this.gauge = new CircularGauge(72, 72, 30, 30, 12, 24, 90, 360, 0, "V")
     await this.didReceiveSettings(context, settings, coordinates)

   }

   /*******************************
    * extra stuff
    *******************************/

   private async encoderRotate(value :number)
   {

     if (value < 0) value = 0;
     if (value > 10) value = 10;
     if (this.voltageOutput != null)
       if (await this.voltageOutput.isOnline())
         await this.voltageOutput.set_currentVoltage(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_YVoltageOutputSettingsAction.registerFunctionType();
// @ts-ignore




