/*jshint unused: false*/
"use strict" ;

import clamp from '../core/maths/clamp'
import map from '../core/maths/map'

import Signal from '../system/signals/Signal'

/**
 * This interface defined the methods to implement a progress display component.
 * @name Progress
 * @memberof molecule
 * @interface
 */
export default class Progress
{
    /**
     * @constructor
     * @param {number} [position=0] The current position of the progress object.
     * @param {number} [max=0] The maximum value of the progress object.
     * @param {number} [min=0] The minimum value of the progress object.
     */
    constructor( position = 0 , max = 0 , min = 0 )
    {
        Object.defineProperties( this ,
            {
                /**
                 * The changed signal reference.
                 */
                changed : { value : new Signal() } ,
                
                /**
                 * @private
                 */
                _max : { value : max , configurable : true , writable : true } ,
                
                /**
                 * @private
                 */
                _min : { value : min , configurable : true , writable : true } ,
                
                /**
                 * @private
                 */
                _position : { value : position , configurable : true , writable : true }
            } );
    }
    
    /**
     * The maximum value of the progress.
     * @memberof molecule.Progress
     * @default 0
     * @member
     */
    get maximum()
    {
        return this._max;
    }
    
    set maximum( value )
    {
        let tmp = this._max;
        this._max = value;
        this.setPosition( map( this._position , this._min , tmp , this._min , this._max ) );
    }
    
    /**
     * The maximum value of the progress.
     * @memberof molecule.Progress
     * @default 0
     * @member
     */
    get minimum()
    {
        return this._min;
    }
    
    set minimum( value )
    {
        let tmp = this._min;
        this._min = value;
        this.setPosition( map( this._position , tmp , this._max , this._min , this._max ) );
    }
    
    /**
     * Defines the position of the progress element.
     * @memberof molecule.Progress
     * @method
     * @param value the position value of the progress element.
     * @param noEvent (optional) this flag disabled the events of this method if this argument is <code>true</code>
     * @param flag (optional) An optional boolean flag use in the method.
     */
    get position()
    {
        return this._position
    }
    
    set position( value )
    {
        this.setPosition( value );
    }
    
    /**
     * Invoked to notify the current change of the progress element.
     */
    notifyChanged()
    {
        if( this.changed.connected() )
        {
            this.changed.emit( this );
        }
    }
    
    /**
     * Sets the position of the progress bar.
     * @memberof molecule.Progress
     * @method
     * @param value the position value of the progress bar.
     * @param noEvent (optional) this flag disabled the events of this method if this argument is <code>true</code>
     * @param flag (optional) An optional boolean flag use in the method.
     */
    setPosition( value , noEvent = false , flag = false )
    {
        let old = this._position;
        this._position = clamp( isNaN( value ) ? 0 : value , this._min , this._max );
        this.viewPositionChanged( flag );
        if( old !== this._position && (noEvent === true) )
        {
            this.notifyChanged();
        }
    }
    
    /**
     * This method is invoked when the position of this progress element is changed.
     * You can overrides this method to create your own behavior without before the 'changed' signal.
     */
    viewChanged( flag = false )
    {
        // override this method
    }
}