// Import the Lasal Runtime base element into your component
// Import SigPolymer to use Polymer methods: html, afterNextRender, beforeNextRender, debouncer, timeOut
// or if your component's getter template() returns a HTML literal
import { LasalRuntimeSigElement, SigPolymer } from '../../sigmatek/sig-element/sig-element.js';



/****************************************************************************************************
 * @class LasalRuntimeSigControlProgressBarBasic
 * @extends {LasalRuntimeSigElement}
 ****************************************************************************************************/
export class LasalRuntimeSigControlProgressBarBasic extends LasalRuntimeSigElement {
    
    /****************************************************************************************************
     * When the element is loaded, importMeta() assigns reference to the path from 
     * which an element was imported to its importPath property. 
     * Relative URLs in styles are automatically re-written to be relative to the importPath property. 
     * You can use [[importPath]] in your component to load url resources
     * 
     * @readonly
     * @static
     ****************************************************************************************************/
    static get importMeta() {
        return import.meta;
    }

    /****************************************************************************************************
     * Return the component style and template as a template literal
     *
     * @readonly
     * @static
     ****************************************************************************************************/
    static get template() {
        return SigPolymer.html`
            <style include="sig-element-css">
            :host {
                display: block;
                position: absolute;

                /* Basic styling of the borders */
                border-style: var(--theme-sig-control-progress-bar-basic-border-style, none);
                border-width: var(--theme-sig-control-progress-bar-basic-border-width, 1px);
                border-color: var(--theme-sig-control-progress-bar-basic-border-color, inherit);
                border-radius: var(--theme-sig-control-progress-bar-basic-border-radius, 3px);

                overflow: hidden;

                font-size: 14px;
            }

            #baron {
                overflow: hidden;
                position: absolute;
                height: 100%;
                /* The background color of the active part of the bar */
                background-color: var(--theme-sig-control-progress-bar-basic-baron-background-color, rgba(174, 200, 26, 1));
            }

            #baroff {
                position: absolute;
                width: 100%;
                height: 100%;
                /* The background color of the inactive part of the bar */
                background-color: var(--theme-sig-control-progress-bar-basic-baroff-background-color, rgba(64, 66, 72, 1));
            }

            .sig-control-progress-bar-basic {
                position: relative;
                height: 100%;
                width: 100%;
                background-color: var(--theme-sig-control-progress-bar-basic-baroff-background-color, rgba(64, 66, 72, 1));
                text-decoration: inherit;
            }

            .baron-background {
                height: 100%;
                background-color: var(--theme-sig-control-progress-bar-basic-baron-background-color, rgba(174, 200, 26, 1));
            }

            #barContainer {
                height: 100%;
                width: 100%;
            }

            .baronimage {
                /* the background image of the active part of the bar */
                background-image: var(--theme-sig-control-progress-bar-basic-baron-background-image, none);
                /* The background size is calculated and set so the image gets revealed, otherwise it would just stretch */
                background-size: var(--theme-sig-control-progress-bar-basic-baron-background-width, 100%) var(--theme-sig-control-progress-bar-basic-baron-background-height, 100%);
                background-repeat: no-repeat;
            }

            .baroffimage {
                background-image: var(--theme-sig-control-progress-bar-basic-baroff-background-image, none);
                background-size: var(--theme-sig-control-progress-bar-basic-baron-background-width, 100%) var(--theme-sig-control-progress-bar-basic-baron-background-height, 100%);
                background-repeat: no-repeat;
            }

            :host([showstripes]) .candy-stripes .baron-background:after {
                content: "";
                position: absolute;
                top: 0;
                left: 0;
                bottom: 0;
                right: 0;
                /* the gradient for the candy stripes */
                background-image: linear-gradient(-45deg,
                        var(--theme-sig-control-progress-bar-basic-candy-stripes-color, inherit) 25%,
                        transparent 26%,
                        transparent 49%,
                        var(--theme-sig-control-progress-bar-basic-candy-stripes-color, inherit) 50%,
                        var(--theme-sig-control-progress-bar-basic-candy-stripes-color, inherit) 75%,
                        transparent 76%,
                        transparent);
                z-index: 1;
                background-size: 50px 50px;
                overflow: hidden;
            }

            :host([animatestripes]) .animate-candy-stripes.candy-stripes .baron-background:after {
                animation: move 2s linear infinite;
            }

            @keyframes move {
                0% {
                    background-position: 0 0;
                }

                100% {
                    background-position: 50px 50px;
                }
            }

            .text {
                top: var(--theme-sig-control-progress-bar-basic-text-offset-top, 50%);
                left: var(--theme-sig-control-progress-bar-basic-text-offset-left, 50%);
                transform: translate(-50%, -50%);
                color: var(--theme-sig-control-progress-bar-basic-text-color, inherit);
                z-index: 1;
                text-decoration: inherit;
            }

            .text,
            .value,
            .unit {
                display: none;
            }


            :host([showvalue]) .text,
            :host([showunit]) .text {
                display: initial;
                position: absolute;
                white-space: nowrap;
            }

            :host([showvalue]) .value {
                display: initial;
            }

            :host([showunit]) .unit {
                display: initial;
            }
        </style>
        <div class="sig-control-progress-bar-basic clearfix" id="container">
            <div class="bar" id="baroff"></div>
            <div class="bar candy-stripes animate-candy-stripes" id="baron">
                <div class="baron-background"></div>
            </div>
            <div class="text" id="text">
                <span class="value">[[value]]</span>
                <span class="unit">[[unittext]]</span>
            </div>
        </div>
            `;
    }

    /****************************************************************************************************
     * define the custom tag name
     *
     * @readonly
     * @static
     ****************************************************************************************************/
    static get is() {
        return "sig-control-progress-bar-basic";
    }

    /****************************************************************************************************
     * define the main properties of the component
     * reflected property names should always be lower case so it can be used directly on the element as an attribute
     *
     * @readonly
     * @static
     ****************************************************************************************************/
    static get properties() {
        return {
            valueuc: {
                type: Number,
                value: '',
                observer: '_realValueChanged'
            },
            minvalueuc: {
                type: Number,
                value: 0,
                observer: '_realValueChanged'
            },
            maxvalueuc: {
                type: Number,
                value: 100,
                observer: '_realValueChanged'
            },             
            bgcolorvalue: {
                type: String,
                value: 'rgba(175, 200, 26, 1)'
            },
            bgcolorhide: {
                type: String,
                value: 'rgba(165, 171, 176, 1)'
            },
            imgvalue: {
                type: String,
                value: 'none'
            },
            imghide: {
                type: String,
                value: 'none'
            },
            cbackgroundvalue: {
                type: String,
                computed: '_cBackground(bgcolorvalue, imgvalue, "value")'
            },
            cbackgroundhide: {
                type: String,
                computed: '_cBackground(bgcolorhide, imghide, "hide")'
            },
            showvalue: {
                type: Boolean,
                value: true,
                reflectToAttribute: true
            },
            showunit: {
                type: Boolean,
                value: true,
                reflectToAttribute: true
            },
            showstripes: {
                type: Boolean,
                value: true,
                reflectToAttribute: true
            },
            animatestripes: {
                type: Boolean,
                value: true,
                reflectToAttribute: true
            }
        }
    }

    /****************************************************************************************************
     *called when the element has been created, but before property values are set and local DOM is initalized
     *Creates an instance of LasalRuntimeSigControlProgressBarBasic.
     ****************************************************************************************************/
    constructor() {
        super();

        //get needed apis
        this.vmApi = window.sigApi.vm;
        this.propApi = window.sigApi.properties;
        this.sigConst = window.sigApi.SIG_CONST;

        //set default value
        this.unittext = "[Unit]";
        //used in progress bar stepper to provide full bar display in designmode
        this.setdesigndefault = true;

        this.barValueWidthSet = false;
        this.totalBarWidth = 0;

        this.addPredefProps([
            {
                src: 'value',
                dest: 'unittext',
                type: this.sigConst.PROP_PREDEF_PROPS_TYPE_UNIT_TEXT
            },
            {
                src: 'value',
                dest: 'valueuc',
                type: this.sigConst.PROP_PREDEF_PROPS_TYPE_UNCONVERTED_VALUE
            }, 
            {
                src: 'minvalue',
                dest: 'minvalueuc',
                type: this.sigConst.PROP_PREDEF_PROPS_TYPE_UNCONVERTED_VALUE
            }, 
            {
                src: 'maxvalue',
                dest: 'maxvalueuc',
                type: this.sigConst.PROP_PREDEF_PROPS_TYPE_UNCONVERTED_VALUE
            }             
        ])

        this.sigAddRequiredProperty('valueuc');
        this.sigAddRequiredProperty('minvalueuc');
        this.sigAddRequiredProperty('maxvalueuc');
    }

    /****************************************************************************************************
     * Gets called if required properties are ready
     *
     ****************************************************************************************************/
     sigOnRequiredPropertiesReady () {
        super.sigOnRequiredPropertiesReady();
        
        if (this.isReady) {
            this._setBarBackgroundSize();
            this._updateBar();
        } 
        //set required properties ready flag
        this.reqPropsReady = true;
    }

    /****************************************************************************************************
     * called after property default values are set and local DOM is initialized 
     ****************************************************************************************************/
    ready() {
        super.ready();
        
        // wait for next render in designer, for getting control bounds
        if (this.isdesignmode) {
            SigPolymer.afterNextRender(this, function () {
                this._setBarBackgroundSize();
                this._updateBar();
            });

        // no designer, get control bounds immediately
        } else {
            if (this.reqPropsReady) {
                this._setBarBackgroundSize();
                this._updateBar();
            }  
        }
        //to check if a width from the divs in the component is available
        this.isReady = true;
    }

    /****************************************************************************************************
     * sets the background sizes for the bars
     * if the background size isn't set, the background image isn't revealed as the bar gets bigger,
     * but it stretches
     ****************************************************************************************************/
    _setBarBackgroundSize() {
        const barOffBounds = this.getControlBounds();

        this._getBorderWidth();

        this.totalBarWidth = barOffBounds.width - this.borderLeftWidth - this.borderRightWidth;

        this.updateStyles({
            '--theme-sig-control-progress-bar-basic-baron-background-height': String(barOffBounds.height - this.borderTopWidth - this.borderBottomWidth) + 'px',
            '--theme-sig-control-progress-bar-basic-baron-background-width': String(this.totalBarWidth) + 'px'
        });
    }

    /****************************************************************************************************
     * Calculates how far the bar is currently filled
     * 
     * @param {Number} value - the value of the bar
     * @return {Number} - the relative fill of the bar in percent
     ****************************************************************************************************/
    _getPercent(value) {
        // in designmode use preview values
        if ((this.isdesignmode) && (this.setdesigndefault)) {
            // In the designmode, make sure the bar is always half empty
            //setdesigndefault used by progress bar stepper to show bars full in designmode            
            return 0.5;
        }
        else {
            //The whole value range
            const length = this.maxvalueuc - this.minvalueuc;

            //The Position of this.value within that range
            const val = value - this.minvalueuc;

            let percent = (val / length);

            if (percent < 0) {
                //Make sure the bar is at lease 0% filled
                percent = 0;
            } else if (percent > 1) {
                //Make sure the bar is at most 100 % filled
                percent = 1;
            }
            //avoid calculating with NaN
            if(isNaN(percent)) {
                percent = 0;
            }        
            return percent;
        } 
    }

    /****************************************************************************************************
     * Calculates the background
     * 
     * @param {String} color - the background color
     * @param {String} img - the image url as string
     * @param {String} target - 'value' or 'hide' determines if the styles should be updated for the foreground or background
     ****************************************************************************************************/
    _cBackground(color, img, target) {
        if (!img || img === 'none') {
            //If there is no image, set the color
            if (target === 'hide') {
                this.updateStyles({ '--theme-sig-control-progress-bar-basic-baroff-background-color': color })
                this.$.baroff.classList.remove('baroffimage');
            } else {
                this.updateStyles({ '--theme-sig-control-progress-bar-basic-baron-background-color': color })
                this.$.baron.querySelector('.baron-background').classList.remove('baronimage')
            }
        } else {
            // set the color first
            if (target === 'hide') {
                this.updateStyles({ '--theme-sig-control-progress-bar-basic-baroff-background-color': color })
            } else {
                this.updateStyles({ '--theme-sig-control-progress-bar-basic-baron-background-color': color })
            }


            //If there is an image, set the image

            
            //there needs to be an extra case for the design mode, because in the design mode 
            //urls contain \ for some reason, which are escape characters.
            //So they need to be replaced.
            let imgurl = '';
            if (this.isdesignmode) {
                imgurl = `url('${img.replace(/\\/g, '/')}')`
            } else {
                imgurl = `url('${img}')`
            }

            if (target === 'hide') {
                this.$.baroff.classList.add('baroffimage');
                this.updateStyles({ '--theme-sig-control-progress-bar-basic-baroff-background-image': imgurl })
            } else {
                this.$.baron.querySelector('.baron-background').classList.add('baronimage')
                this.updateStyles({ '--theme-sig-control-progress-bar-basic-baron-background-image': imgurl })
            }
        }
    }

    /****************************************************************************************************
     * Handles value changes during runtime
     *
     * @param {Number} newValue - the value of the component
     ****************************************************************************************************/
     _realValueChanged(newValue) {
        //check if not in designmode and component was initialized already
        if (!this.isdesignmode) {
            this._updateBar();              
        }     
    }

    /****************************************************************************************************
     * this method is used to draw the bar
     ****************************************************************************************************/
     _updateBar() {
        // calculate the relative width of the bar
        const percent = this._getPercent(this.valueuc);

        /* rounding to full pixels avoid jerky image animation that could otherwise occur in most browsers */
        this.$.baron.style.width = `${Math.round(this.totalBarWidth * percent)}px`;
    }  

    /****************************************************************************************************
     * Redraw the component after a designer resize
     *so that the size of the bar is correct again
     ****************************************************************************************************/
     designerOnBoundsChanged() {
        if (this.isdesignmode) {
            // Use the renderCallback because the control doesn't have the correct bounds yet
            SigPolymer.afterNextRender(this, () => {
                this._setBarBackgroundSize();
                this._updateBar();
            })
        }
    }    

    /****************************************************************************************************
     * Overriding the default sigApplyCSSValue function
     * needed because the component needs to be redrawn on some css changes
     *
     * @param {Object} cssObj
     * @param {Boolean} [doBoundsCheck=false]
     * @memberof LasalRuntimeSigControlProgressBarBasic
    ****************************************************************************************************/
     sigApplyCSSValue(cssObj, doBoundsCheck = false) {
        super.sigApplyCSSValue(cssObj, doBoundsCheck);

        // value only changes in design mode
        if(this.isdesignmode) {
            // if there are more than one change, it is the inital load, and the component gets drawn correctly anyway
            const cssObjLength = Object.keys(cssObj).length;
            if((cssObjLength === 1) && 
              ((cssObj.hasOwnProperty('--theme-sig-control-progress-bar-basic-border-width'))||
               (cssObj.hasOwnProperty('--theme-sig-control-progress-bar-basic-border-style')))) {
                this._setBarBackgroundSize();
                this._updateBar();
            }
        }
    }

    /****************************************************************************************************
    * Method to get all the border width elements independent of the used shorthand style
    ****************************************************************************************************/
    _getBorderWidth() {
        const borderStyle = this.style.getPropertyValue('--theme-' + this.tagName.toLowerCase() + '-border-style');

        if ((borderStyle === "none") || (borderStyle === "")) {
            this.borderTopWidth = this.borderRightWidth = this.borderBottomWidth = this.borderLeftWidth = 0;
            return;
        }

        let borderWidth = this.style.getPropertyValue('--theme-' + this.tagName.toLowerCase() + '-border-width');

        if (borderWidth === "") {
            this.borderTopWidth = this.borderRightWidth = this.borderBottomWidth = this.borderLeftWidth = 0;            
        } else {
            let values = borderWidth.split(' ');
        
            switch (values.length) {
                case 1: // "5px"
                    this.borderTopWidth = this.borderRightWidth = this.borderBottomWidth = this.borderLeftWidth = parseInt(values[0]);
                    break;
                case 2: // "1px 5px"
                    this.borderTopWidth = this.borderBottomWidth = parseInt(values[0]);
                    this.borderRightWidth = this.borderLeftWidth = parseInt(values[1]);
                    break;
                case 3: // "1px 5px 10px"
                    this.borderTopWidth = parseInt(values[0]);
                    this.borderRightWidth = this.borderLeftWidth = parseInt(values[1]);
                    this.borderBottomWidth = parseInt(values[2]);
                    break;
                case 4: // "1px 5px 10px 15px"
                    this.borderTopWidth = parseInt(values[0]);
                    this.borderRightWidth = parseInt(values[1]);
                    this.borderBottomWidth = parseInt(values[2]);
                    this.borderLeftWidth = parseInt(values[3]);
                    break;
                default: // invalid format => use no border
                    this.borderTopWidth = this.borderRightWidth = this.borderBottomWidth = this.borderLeftWidth = 0;
                    break;
            }
        }
    }       
}
customElements.define(LasalRuntimeSigControlProgressBarBasic.is, LasalRuntimeSigControlProgressBarBasic);
