import is from '@pilotlab/is';
import { IAnimationEaseFunction } from '@pilotlab/animation';
import { Signal } from '@pilotlab/signals';
import RangeScale from './rangeScale';


export class RangeScaleBase {
    constructor(inputMin:number = 0, inputMax:number = 1, ease?:IAnimationEaseFunction) {
        if (is.notEmpty(inputMin)) this.p_inputMin = inputMin;
        if (is.notEmpty(inputMax)) this.p_inputMax = inputMax;
        this.p_ease = ease;
    }


    /*--------------------------------------------------------------------*
     START: Properties
     *--------------------------------------------------------------------*/
    get inputMin():number { return this.p_inputMin; }
    set inputMin(value:number) { this.p_inputMin = value; }
    protected p_inputMin:number = 0.0;


    get inputMax():number { return this.p_inputMax; }
    set inputMax(value:number) { this.p_inputMax = value; }
    protected p_inputMax:number = 1.0;

    get ease():IAnimationEaseFunction  { return this.p_ease; }
    set ease(value:IAnimationEaseFunction) { this.p_ease = value; }
    protected p_ease:IAnimationEaseFunction;


    get progress():number { return this.p_lastInputNormalized; } // 0.0 <--> 1.0
    get p():number { return this.progress; }

    protected p_lastInputRaw:number;
    protected p_lastInputNormalized:number;


    /*--------------------------------------------------------------------*
     START: Signals
     *--------------------------------------------------------------------*/
    enteredRangeFromBelow:Signal<number> = new Signal<number>();
    enteredRangeFromAbove:Signal<number> = new Signal<number>();


    /*--------------------------------------------------------------------*
     START: Public Methods
     *--------------------------------------------------------------------*/
    /**
     * Returns the relative position of the input value
     * within the min/max range as a value between 0.0 and 1.0.
     */
    normalizeInput(inputUnnormalized:number, isConstrain:boolean = true, isInvert:boolean = false):number {
        return RangeScale.normalize(inputUnnormalized, this.p_inputMin, this.p_inputMax, isConstrain, isInvert);
    }


    /**
     * Accepts a value between 0.0 and 1.0 and returns the input value at the corresponding
     * progress point within the min/max input range.
     */
    unnormalizeInput(inputNormalized:number, isConstrain:boolean = true, isInvert:boolean = false):number {
        return RangeScale.unnormalize(inputNormalized, this.p_inputMin, this.p_inputMax, isConstrain, isInvert);
    }


    /*--------------------------------------------------------------------*
     START: Private Methods
     *--------------------------------------------------------------------*/
    protected p_checkInputPreviousRaw(inputValueRaw:number):void {
        if (
            is.notEmpty(this.p_lastInputRaw)
            && (this.p_lastInputRaw < this.p_inputMin || this.p_lastInputRaw > this.p_inputMax)
            && (inputValueRaw >= this.p_inputMin && inputValueRaw <= this.p_inputMax)
        ) {
            //----- The input value just entered the allowed range, while it was previously outside the range.
            if (this.p_lastInputRaw < this.p_inputMin) {
                //----- We just entered the range from below the minimum.
                this.enteredRangeFromBelow.dispatch(inputValueRaw);
            } else if (this.p_lastInputRaw > this.p_inputMax) {
                //----- We just entered the range from above the maximum.
                this.enteredRangeFromAbove.dispatch(inputValueRaw);
            }
        }
    }
} // End class


export default RangeScaleBase;
