import { LasalRuntimeSigElement, SigPolymer } from '../../sigmatek/sig-element/sig-element.js';

/****************************************************************************************************
 * @export
 * @class LasalRuntimeSigControlMenuInput
 * @extends {LasalRuntimeSigElement}
****************************************************************************************************/
export class LasalRuntimeSigControlMenuInput extends LasalRuntimeSigElement {
    
    /****************************************************************************************************
     * Returns the component's registered tag name.
     *
     * @readonly
     * @static
     * @returns {String} The control's tag name.
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    static get is() {
        return "sig-control-menu-input";
    }

    /****************************************************************************************************
     * Returns the import path URL used by Polymer.
     *
     * @readonly
     * @static
     * @returns {String} The import path URL.
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    static get importMeta() { return import.meta; }

    /****************************************************************************************************
     * Returns the HTML literal of the component.
     *
     * @readonly
     * @static
     * @returns {HTMLLIElement} The template literal of the component.
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    static get template() {
        return SigPolymer.html`
        <style include="sig-element-css">
            :host {
                color: var(--theme-sig-control-menu-input-color, rgba(42, 42, 42, 1));
                background-color: var(--theme-sig-control-menu-input-background-color, rgba(215, 215, 215, 1));

                border-width: var(--theme-sig-control-menu-input-border-width, 0px);
                border-color: var(--theme-sig-control-menu-input-border-color, transparent);
                border-style: var(--theme-sig-control-menu-input-border-style, none);

                border-top-left-radius: var(--theme-sig-control-menu-input-border-radius-tl, var(--theme-sig-control-menu-input-border-radius, 0));
                border-top-right-radius: var(--theme-sig-control-menu-input-border-radius-tr, var(--theme-sig-control-menu-input-border-radius, 0));
                border-bottom-right-radius: var(--theme-sig-control-menu-input-border-radius-br, var(--theme-sig-control-menu-input-border-radius, 0));
                border-bottom-left-radius: var(--theme-sig-control-menu-input-border-radius-bl, var(--theme-sig-control-menu-input-border-radius, 0));

                display: var(--theme-sig-control-menu-input-display, block);
                position: var(--theme-sig-control-menu-input-position, absolute);

                padding: var(--theme-sig-control-menu-input-padding, 0);
                overflow: var(--theme-sig-control-menu-input-overflow, hidden);
                margin: 0;
                text-overflow: ellipsis;
            }

            :host * {    
                @apply --notextselect;
                margin: 0;
                padding: 0;
            }

            .clearfix:after {
                @apply --clearfix;
            }

            .sig-control-menu-input-element {    
                position: relative;
                width: 100%;
                height: 100%;
                cursor: pointer;
                overflow: hidden;
                text-decoration: inherit;

                display: flex;
                justify-content: center;
                align-items: center;

                border: none;
                border-top-left-radius: calc((var(--theme-sig-control-menu-input-border-radius-tl, var(--theme-sig-control-menu-input-border-radius, 0)) - var(--theme-sig-control-menu-input-border-width, 0)));
                border-top-right-radius: calc((var(--theme-sig-control-menu-input-border-radius-tr, var(--theme-sig-control-menu-input-border-radius, 0)) - var(--theme-sig-control-menu-input-border-width, 0)));
                border-bottom-right-radius: calc((var(--theme-sig-control-menu-input-border-radius-br, var(--theme-sig-control-menu-input-border-radius, 0)) - var(--theme-sig-control-menu-input-border-width, 0)));
                border-bottom-left-radius: calc((var(--theme-sig-control-menu-input-border-radius-bl, var(--theme-sig-control-menu-input-border-radius, 0)) - var(--theme-sig-control-menu-input-border-width, 0)));

                background-color: var(--theme-sig-control-menu-input-background-color, rgba(255, 255, 255, 1));
                background-image: linear-gradient(var(--theme-sig-control-menu-input-background-color-direction, to bottom),
                var(--theme-sig-control-menu-input-background-color, rgba(255, 255, 255, 1)),
                var(--theme-sig-control-menu-input-background-color-stop, var(--theme-sig-control-menu-input-background-color)));
            }

            #activeoption {
                width: 100%;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
                background-color: var(--theme-sig-control-menu-input-activeoption-background-color, transparent);
                color: var(--theme-sig-control-menu-input-activeoption-color, inherit);
                text-align: var(--theme-sig-control-menu-input-activeoption-text-align, center);
                align-self: var(--theme-sig-control-menu-input-activeoption-text-align-vertical, center);
                text-decoration: inherit;

                position: relative;
                display:flex;
                align-items: center;
            }

            :host(:not([showicon])) .imageWrapper {
                display:none;
            }

            .imageWrapper {
                display:inline-block;
                width: var(--theme-sig-control-menu-input-icon-width, 25px); 
                margin: 0px var(--theme-sig-control-menu-input-icon-margin-right,5px);
                flex-shrink: 0;
            }

            .imageWrapper img {
                display:inline-block;
                width: 100%;
                height: var(--theme-sig-control-menu-input-icon-height, auto);
                vertical-align: middle;
                max-height: var(--theme-sig-element-height, 100%);
                object-fit: contain;
            }
        
            .textWrapper {
                flex-grow:1;
                height: 100%;
                display:inline-block;
                overflow:hidden;
                text-overflow:ellipsis;
                padding: var(--theme-sig-control-menu-input-activeoption-text-padding, 0px 2px);
            }

            :host([showicon])  .textWrapper  {
                margin-right:var(--theme-sig-control-menu-input-icon-margin-right,5px);
            }

            /* caret container styling */
            #caretcontainer {
                position: relative;
                flex: 0 0 var(--theme-sig-control-menu-input-caretdown-width, 30px);
                height: 100%;
                overflow: hidden;
                background-color: var(--theme-sig-control-menu-input-caretdown-background-color, inherit);
                box-sizing: border-box;
            }
    
            /* caret container active styling */
            :host([menuvisible]) #caretcontainer {
                background-color: var(--theme-sig-control-menu-input-caretdown-pressed-background-color, var(--theme-sig-control-menu-input-caretdown-background-color, inherit));
            }
    
            /* caret images styling (inactive/active) */
            .caret {
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                position: absolute;
                box-sizing: border-box;
                width: var(--theme-sig-control-menu-input-caret-width, 16px);
                height: 100%;
                object-fit: contain;
                visibility: hidden;
                margin: auto;
            }
    
            :host([menuvisible]) #caretimageactive {
                visibility: visible;
            }
    
            :host(:not([menuvisible])) #caretimage {
                visibility: visible;
            }
    
            /* menu-input border color applied in active state, when bordergradient is inactive  */
            :host([menuvisible]) {
                border-color: var(--theme-sig-control-menu-input-pressed-border-color, var(--theme-sig-control-menu-input-border-color));
            }
            
            :host(:not([isdesignmode])[menuvisible]) {
                border-color: var(--theme-sig-control-menu-input-pressed-border-color, var(--theme-sig-control-menu-input-border-color));
            }

            /* remove border when bordergradient is active */
            :host([bordergradient]:not([menuvisible])),
            :host([bordergradientpressed][menuvisible]) {
                border-width: 0px;
            }
    
            .sig-control-menu-input-container {
                width: 100%;
                height: 100%;
                box-sizing: border-box;
                text-decoration: inherit;                
            }

            :host([bordergradient][isdesignmode]) .sig-control-menu-input-container,
            :host([bordergradient]:not([menuvisible])) .sig-control-menu-input-container {
                width: 100%;
                background-image: linear-gradient(var(--theme-sig-control-menu-input-border-color-direction, to bottom), var(--theme-sig-control-menu-input-border-color), var(--theme-sig-control-menu-input-border-color-stop, var(--theme-sig-control-menu-input-border-color)));
                padding: var(--theme-sig-control-menu-input-border-width, 1px);
            }

            :host([bordergradientpressed][menuvisible]) .sig-control-menu-input-container {
                width: 100%;
                background-image: linear-gradient(var(--theme-sig-control-menu-input-pressed-border-color-direction, to bottom), var(--theme-sig-control-menu-input-pressed-border-color, var(--theme-sig-control-menu-input-border-color)), var(--theme-sig-control-menu-input-pressed-border-color-stop, var(--theme-sig-control-menu-input-border-color-stop)));
                padding: var(--theme-sig-control-menu-input-border-width, 1px);
            }

            :host([menuvisible]) .sig-control-menu-input-element {
                background-color: var(--theme-sig-control-menu-input-pressed-background-color, var(--theme-sig-control-menu-input-background-color, rgba(215, 215, 215, 1)));
                color: var(--theme-sig-control-menu-input-pressed-color, var(--theme-sig-control-menu-input-color, rgba(42, 42, 42, 1)));
				background-size: contain;
                background-image: linear-gradient(var(--theme-sig-control-menu-input-pressed-background-color-direction, to bottom),
                var(--theme-sig-control-menu-input-pressed-background-color, rgba(215, 215, 215, 1)),
                var(--theme-sig-control-menu-input-pressed-background-color-stop, var(--theme-sig-control-menu-input-pressed-background-color)));
            }

            #boxshadowcontainer {
                position: absolute;
                display: none;
                background-color: transparent;
                width: 100%;
                height: 100%;
            }

            :host([shadowactive]:not([menuvisible])) #boxshadowcontainer {
                display: block;
                box-shadow: inset 0 0 var(--theme-sig-control-menu-input-shadow-size, 0px) var(--theme-sig-control-menu-input-shadow-color, rgba(0, 0, 0, 1));
            }

            :host([shadowpressedactive][menuvisible]) #boxshadowcontainer {
                display: block;
                box-shadow: inset 0 0 var(--theme-sig-control-menu-input-pressed-shadow-size, 0px) var(--theme-sig-control-menu-input-pressed-shadow-color, rgba(0, 0, 0, 1));
            }
        </style> 
        <div class="sig-control-menu-input-container clearfix" on-tap="_toggleMenu">
            <div class="sig-control-menu-input-element clearfix">
                <div id="activeoption">
                <span class="imageWrapper" id="iconwrapper">
                    <img src="[[iconsrc]]" id="activeicon"/>
                </span>
                <span class="textWrapper">[[activeoption]]</span>
                </div>
                <div id="caretcontainer">
                    <!-- we create img for for both images to increase first rendering performance when list is opened -->
                    <img id="caretimage" src=[[caretimage]] class="caret">
                    <img id="caretimageactive" src=[[caretimageactive]] class="caret">
                </div>
                <div id="boxshadowcontainer"></div>
            </div>
        </div>
        `;
    }

    /****************************************************************************************************
     * Method gets called by runtime to fetch polymer properties
     *
     * @readonly
     * @static
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    static get properties() {
        // property names should always be lower case so we
        // can use them directly on the element as an attribute
        let props = {
            value: {
                type: Number,
                value: undefined,
                observer: '_updateValue',
                notify: true
            },
            defaulttext: {
                type: String,
                value: '',
                observer: '_defaultTextChanged'
            },
            direction: {
                type: String,
                value: ''
            },
            //computed needed cause menu is working with numeric values but we want to configure strings like 10px
            offsetx: {
                type: String,
                value: "0px",
                computed: '_computeOffset(offsetx)'
            },
            offsety: {
                type: String,
                value: "0px",
                computed: '_computeOffset(offsety)'
            },
            menuvisible: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            shadowactive: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            shadowpressedactive: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            bordergradient: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            bordergradientpressed: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            },
            menuref: {
                type: String,
                value: ''
            },
            ignoreminwidth: {
                type: Boolean,
                value: false
            },
            showicon: {
                type: Boolean,
                value: false,
                reflectToAttribute: true,
                observer: '_toggleIcon'
            },
            defaultimageurl: {
                type: String,
                value: '',
                observer: '_toggleDefaultIcon'
            },
            showdefaulticon: {
                type: Boolean,
                value: false
            },
            previewtext: {
                type: String,
                value: '-- Menu Input --',
                observer: '_defaultTextChanged'
            }            
        }
        return props;
    }

    /****************************************************************************************************
     * Creates an instance of LasalRuntimeSigControlMenuInput.
     * 
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    constructor() {
        super();

        // initialize variables
        this.currentMenuItem = null;
        this.currentMenuItemObs = null;

        this.updateActiveOptionToDefaultText = true;

        this.activeoption = '';

        this.caretimage = `${this.importPath}caret_down.svg`;
        this.caretimageactive = `${this.importPath}caret_up.svg`;

        this.offsetx = 0;
        this.offsety = 0;

        // get reference to api
        this.menuApi = (sigApi.menuManager) ? sigApi.menuManager : null;
        this.dsApi = (window.sigApi.defaultStyleManager) ? window.sigApi.defaultStyleManager : null;

        // Needs to be true to dispatch value-changed event, because by default, runtime updates the value, not component itself.
        this.dispatchAllInternalEvents = true;
     
        this.addMandatoryCloneProperty('activeoption');

        // add required property for value
        this.sigAddRequiredProperty('value');

        // add observers which are only used in designmode
        if (this.isdesignmode) {
            // in designer, set the default images to the correct path
            this._createMethodObserver('_designerOnCaretImageChanged(caretimage, caretimageactive)', true);
        }        
    }

    /********************************************************************************************************************************
     * Called in the designer when a caret image is set.
     *
     * @memberof LasalRuntimeSigControlMenuInput
     ********************************************************************************************************************************/
     _designerOnCaretImageChanged() {
        if (this.caretimage === 'default') this.caretimage = `${this.importPath}caret_down.svg`;
        if (this.caretimageactive === 'default') this.caretimageactive = `${this.importPath}caret_up.svg`;
    }
    
    
    /****************************************************************************************************
     * Called if required properties are ready
     *
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    sigOnRequiredPropertiesReady() {
        super.sigOnRequiredPropertiesReady();

        // run update of selected value
        SigPolymer.afterNextRender(this, () => {
            this.requiredPropertiesReady = true;
            this._updateValue(this.value);
        });
    }

    /****************************************************************************************************
     * Gets called if element was connected to dom
     *
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    connectedCallback() {
        super.connectedCallback();

        // add eventlistener in case menue is used in a window
        if (this.context && this.context.instanceId && this.context.type === 'window') {
            const jsPanelContent = document.getElementById(this.context.instanceId).querySelector('.jsPanel-content');
            if (jsPanelContent) {
                this.sigAddEventListener('scroll', () => {
                    if (this.menuvisible && this.menuApi) {
                        this.menuApi.cancel();
                    }
                }, 'jsEvent', jsPanelContent);
            }
        }
    }

    /****************************************************************************************************
     * Method is called if offsets change. Menu is awaiting numeric values for offsets but we want
     * to configure them as e.g. 10px.
     *
     * @param {String} value - String value which needs to be converted to number
     * @return {*} 
     * @memberof LasalRuntimeSigControlMenuInput
     ****************************************************************************************************/
    _computeOffset(value) {
        return value !== undefined ? parseFloat(value) : value;
    }

    /****************************************************************************************************
     * Gets called if control gets disconnected from the DOM
     *
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    disconnectedCallback() {
        super.disconnectedCallback();
        this.currentMenuItem = null;
        this.menuApi = null;
        this.dsApi = null;
    }

    /****************************************************************************************************
     * Observer for property showicon
     *
     * @param {*} newVal new value of the property
     * @param {*} oldVal old value of the property
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    _toggleIcon(newVal, oldVal) {
        if (newVal) {
            this._setIcon(this.defaultimageurl);
        }
    }

    /****************************************************************************************************
     * Observer for property defaultimageurl
     *
     * @param {*} newVal new value of the property
     * @param {*} oldVal old value of the property
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    _toggleDefaultIcon(newVal, oldVal) {
        if (this.showicon) {
            this._setIcon(newVal);
        }
    }

    /****************************************************************************************************
     * Method to set the icon for the actual selected element
     *
     * @param {string} [iconUrl=''] path to the icon
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    _setIcon(iconUrl = '') {

        // for designer a default icon is used
        if (!this.isdesignmode) {

            // show selected icon
            if (iconUrl && iconUrl !== '' && this.showicon) {
                this.iconsrc = iconUrl;
                this.$.activeicon.style.display = 'inline-block';

            // show default icon
            } else {
                if (this.showdefaulticon && this.defaultimageurl && this.showicon) {
                    this.iconsrc = this.defaultimageurl;
                    this.$.activeicon.style.display = 'inline-block';
                }

                // show no icon
                else {
                    this.$.activeicon.style.display = 'none';
                    this.iconsrc = '';
                }
            }

        } else {
            this.iconsrc = (iconUrl !== '') ? iconUrl : '/res/components/user/sig-control-menu-input/image.svg';
        }
    }

    /****************************************************************************************************
     * Eventlistener for on-down  to open / close menue
     *
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    _toggleMenu() {
        if (!this.isdesignmode) {
            const menuVisible = document.getElementById('lvdsigcontrolmenu');

            // open menue
            //-------------------------------------------------------------------------------------------
            if (!this.menuvisible && menuVisible && !menuVisible.isVisible) {

                // get scaling and bounds
                const scaleFactors = this.getScaleFactor(this, this.realrotation);
                const position = this.getBoundingClientRect();

                const minimalWidth = (this.ignoreminwidth) ? null : this.offsetWidth;
                const property = (this.value !== undefined) ? 'value' : null;

                // check if api is available and show menue
                if (this.menuApi) {
                    this.menuApi.show(
                        this.menuref,
                        this, property,
                        position.left, position.top + position.height, 
                        scaleFactors.x, scaleFactors.y, 
                        this.realrotation, 
                        minimalWidth, null, 
                        null, null, 
                        this.direction).then((opened) => {
                            if (opened) this.menuvisible = true;
                        }).catch((error) => {
                            if (error.errortxt) this._log('_toggleMenu(): ' + error.errortxt, 'ERROR');
                            else this._log('_toggleMenu(): ' + error, 'ERROR');
                        });
                }

            // close menue
            //-------------------------------------------------------------------------------------------
            } else {
                if (this.menuApi) {
                    this.menuApi.cancel();
                }
                this.menuvisible = false;
            }
        }
    }
    
    /****************************************************************************************************
     * Method is called by runtime for updating value
     *
     * @param {*} menuItem - selected menu item
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
     updateItem(menuItem) {
        //only update item if not set via datapoint
        if ((!this.isdesignmode) && (this.value === undefined)) {
            //set menu item
            this._setMenuItem(menuItem);
        }
    }


    /****************************************************************************************************
     * method is used to set the given menu item as the current item
     *
     * @param {*} menuItem - menu item which should be set as the current item
     * @memberof LasalRuntimeSigControlMenuInput
     ****************************************************************************************************/
    _setMenuItem(menuItem) {
        //remove the observer of the current itme
        if(this.currentMenuItemObs) this.currentMenuItem.removeObserver(this.currentMenuItemObs);
        //check if menu item valid
        if (menuItem) {
            //it is a valid item so text needs to be updated if it changes
            this.updateActiveOptionToDefaultText = false;
            //get text property of menu item
            menuItem.getPropertyValue('text').then((value) => {
                this.activeoption = value;
                this.currentMenuItem = menuItem;
                this.currentMenuItemObs = this.currentMenuItem.addObserver('text', (text) => {
                    this._menuitemObs(text);
                } )
            }).catch(() => {
                this._log('_setMenuItem(): getPropertyValue failed', 'ERROR');
            });

            //get icon if it needs to be shown
            if (this.showicon) {
                menuItem.getPropertyValue('icon').then((icon) => {
                    if (icon) this._setIcon(icon);
                    else this._setIcon('');
                }).catch(() => this._log('_setMenuItem(): getPropertyValue("icon") failed', 'ERROR'));
            }
        }
        else {
            //not a valid item so display default text
            this.updateActiveOptionToDefaultText = true;
            this.activeoption = this.defaulttext;
        }
    }

    /****************************************************************************************************
     * Observer for property value
     *
     * @param {*} newVal new value of the property
     * @param {*} oldVal old value of the property
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    _updateValue(newVal, oldVal) {
        if (this.requiredPropertiesReady) {
            this._updateTextFromDatapoint(newVal);
            if (oldVal !== undefined) {
                this._dispatchEvent('value-changed');
            }            
        }
    }

    /****************************************************************************************************
     *  Method to update text of selected item
     *
     * @param {*} value
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    _updateTextFromDatapoint(value) {
        if (!this.isdesignmode && value !== undefined) {
            // check if menue api is available
            if (this.menuApi) {
                // get menue item for actual selected value
                this.menuApi.getMenuItemFromValue(value, this.menuref).then((item) => {
                    let menuItem;
                    if (item) {
                        menuItem = this.menuApi.getMenuItemFromId(item.instanceId);
                    }
                    else {
                        this._log('_updateTextFromDatapoint(): invalid menu item', 'INFO');
                    }
                    // set menu item
                    this._setMenuItem(menuItem);
                // error handling
                }).catch((error) => {
                    this._log('_updateTextFromDatapoint(): API call getmenuitemFromValue() failed: ' + error, 'ERROR');
                });
            }
        }
    }

    /****************************************************************************************************
     * Method to change text of active element
     *
     * @param {*} text
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    _menuitemObs(text) {
        this.activeoption = text;
    }

    /****************************************************************************************************
     * Method is called in case of Drag & Drop to close the menue
     *
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    onComponentDragDropEnabled() {
        super.onComponentDragDropEnabled();
        if (this.menuvisible && this.menuApi) {
            this.menuApi.cancel();
        }
    }

    /****************************************************************************************************
     * Observer for property defaulttext
     *
     * @param {*} newVal new value of the property
     * @param {*} oldVal old value of the property
     * @memberof LasalRuntimeSigControlMenuInput
    ****************************************************************************************************/
    _defaultTextChanged(newVal, oldVal) {
        if (newVal !== undefined && !this.isdragClone) {
            if (this.updateActiveOptionToDefaultText) {
                this.activeoption = newVal;

                if ((this.isdesignmode) && (this.activeoption === '')) {
                    // run after rendering to get the current preview text
                    SigPolymer.afterNextRender(this, () => {
                        this.activeoption = this.previewtext; 
                    });
                }        
            }
        }
    }
}
customElements.define(LasalRuntimeSigControlMenuInput.is, LasalRuntimeSigControlMenuInput);
