// 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';
// Import dependencies
import './moment/min/moment-with-locales.js';
import '../sig-control-input/sig-control-input.js'
import '../sig-control-input/sig-control-input-css.js'
import './sig-control-timepicker-cylinder-picker-wrapper.js';
import {DatepickerCylinder} from './datepicker-cylinder.js';

/****************************************************************************************************
 * @class LasalRuntimeSigTimepickerCylinder
 * @extends {LasalRuntimeSigElement}
 ****************************************************************************************************/
export class LasalRuntimeSigTimepickerCylinder extends LasalRuntimeSigElement {
    /****************************************************************************************************
     * define the custom tag name 
     ****************************************************************************************************/
    static get is() {
        return 'sig-control-timepicker-cylinder';
    }

    /****************************************************************************************************
     * 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
     ****************************************************************************************************/
    static get importMeta() {
        return import.meta;
    }

    /****************************************************************************************************
     * Return the component style and template as a template literal
     ****************************************************************************************************/
    static get template() {
        return SigPolymer.html`
            <style include="sig-element-css sig-control-input-css">
             :host {
                /* Basic styling of the component */
                color: var(--theme-sig-control-timepicker-color, rgba(160, 160, 160, 1));

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

                /* Basic box model settings */
                display: block;
                position: absolute;
                overflow: hidden;
            }

            :host * {
                /* Reset margins and paddings for child elements and turn of text selection */
                @apply --notextselect;
                margin: 0;
                padding: 0;
            }

            .sig-control-timepicker-cylinder-base {
                color: inherit;
                display: table;
                width: 100%;
                height: 100%;
                position: relative;

                box-sizing: inherit;
                text-decoration: inherit;
                border: none;
                cursor: pointer;
            }

            :host .sig-control-timepicker-cylinder-base sig-control-input {
                position: absolute;
                top: 0;
                left: 0;
                height: 100%;
                width: 100%;

                --theme-sig-control-input-color: var(--theme-sig-control-timepicker-cylinder-input-color, inherit);
                --theme-sig-control-input-background-color:var(--theme-sig-control-timepicker-cylinder-input-background-color, inherit);
                --theme-sig-control-input-value-background-color:var(--theme-sig-control-timepicker-cylinder-input-value-background-color, rgba(196, 192, 192, 1));
                --theme-sig-control-input-value-active-color:var(--theme-sig-control-timepicker-cylinder-input-value-active-color, inherit);
                --theme-sig-control-input-value-active-background-color:var(--theme-sig-control-timepicker-cylinder-input-value-active-background-color, inherit);


                --theme-sig-control-input-font-size:var(--theme-sig-control-timepicker-cylinder-input-font-size, 11px);
                --theme-sig-control-input-color:var(--theme-sig-control-timepicker-cylinder-input-color, inherit);
                --theme-sig-control-input-border-color:var(--theme-sig-control-timepicker-cylinder-input-border-color, inherit);
                --theme-sig-control-input-border-width:var(--theme-sig-control-timepicker-cylinder-input-border-width, 1px);
                --theme-sig-control-input-border-style:var(--theme-sig-control-timepicker-cylinder-input-border-style, solid);
                --theme-sig-control-input-border-radius: var(--theme-sig-control-timepicker-cylinder-input-border-radius, 3px);
                --theme-sig-control-input-margin-leftright:var(--theme-sig-control-timepicker-cylinder-input-margin-leftright, 0px);
                --theme-sig-control-input-margin-top:var(--theme-sig-control-timepicker-cylinder-input-margin-top, 0px);

                --theme-sig-control-input-value-text-align: var(--theme-sig-control-timepicker-cylinder-input-unit-text-align, center);
                --theme-sig-control-input-unit-vertical-align: var(--theme-sig-control-timepicker-cylinder-input-unit-vertical-align, center);
                text-decoration: inherit;
            }
            </style>
            <div class="sig-control-timepicker-cylinder-base">
                <sig-control-input id="testInput" on-tap="_tapHandler"></sig-control-input> 
            </div>
        `;
    }

    /****************************************************************************************************
     * define the main porperties of the component
     * reflected property names should always be lower case so it can be used directly on the element as an attribute
     ****************************************************************************************************/
    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: String,
                value: "",
                notify: true,
                observer: "_valueChanged"
            },
            timepickerid: {
                type: String,
                value: undefined,
            },
            windowed: {
                type: String,
                value: 'dropdown'
            },
            timeformat: {
                type: String,
                value: 'HH:mm',
                observer: '_designModeUpdatePlacehoder'
            },
            mindate: {
                type: String,
                value: ''
            },
            maxdate: {
                type: String,
                value: ''
            },
            /*Window Settings */
            windowtop: {
                type: Number,
                value: 0
            },
            windowleft: {
                type: Number,
                value: 0
            },
            windowtitle: {
                type: String,
                value: '',
                observer: '_windowTitleChanged'
            },
            cylindershavenavbuttons: {
                type: Boolean,
                value: false
            },
            cylinderscrolltype: {
                type: String,
                value: 'normal'
            },
            timepickerfont: {
                type: Object,
                value: () => {return {}}
            },
            pickerheight: {
                type: String,
                value: '200px'
            },
            pickerwidth: {
                type: String,
                value: '50px'
            }
        }
        return props;
    }

    /****************************************************************************************************
     * Called when the element has been created,
     * but before property values are set and local DOM is initialized.
     ****************************************************************************************************/
    constructor() {
        super();

        this.wrapper = undefined;
        this.inputwindow = undefined;

        this.wmApi = window.sigApi.windowManager;
        this.timepicker = undefined;
        this.timepickerClass = undefined;

        this.propReady = undefined;
        this.renderedCB = undefined;

        this.allRendered = false;
        this.openAfterRender = false;

        window.sigApi.vm.addRenderCallback(this, () => {
            this._renderCallback();
        }, () => {
            this._errorRenderCallback();
        })
        this.sigAddRequiredProperty('windowed');

        this.wrapperProps = [
            '--theme-sig-control-timepicker-wrapper-background-color',
            '--theme-sig-control-timepicker-wrapper-cylinder-background-color',
            '--theme-sig-control-timepicker-wrapper-cylinder-background-image',
            '--theme-sig-control-timepicker-wrapper-cylinder-background-size',
            '--theme-sig-control-timepicker-wrapper-cylinder-background-position',
            '--theme-sig-control-timepicker-wrapper-cylinder-background-repeat',
            '--theme-sig-control-timepicker-wrapper-cylinder-border-width',
            '--theme-sig-control-timepicker-wrapper-cylinder-border-style',
            '--theme-sig-control-timepicker-wrapper-cylinder-border-color',
            '--theme-sig-control-timepicker-wrapper-cylinder-border-radius',
            '--theme-sig-control-timepicker-wrapper-cylinder-highlight-background-color',
            '--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-color',
            '--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-width',
            '--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-style',
            '--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-top-color',
            '--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-top-width',
            '--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-top-style',
            '--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-bottom-color',
            '--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-bottom-width',
            '--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-bottom-style',
            '--theme-sig-control-timepicker-wrapper-cylinder-highlight-color',
            '--theme-sig-control-timepicker-wrapper-cylinder-color',
            '--theme-sig-control-timepicker-wrapper-cylinder-justify',
            '--theme-sig-control-timepicker-wrapper-cylinder-button-height',
            '--theme-sig-control-timepicker-wrapper-cylinder-button-background-color',
            '--theme-sig-control-timepicker-wrapper-cylinder-button-background-image',
            '--theme-sig-control-timepicker-wrapper-cylinder-button-down-background-image',
            '--theme-sig-control-timepicker-wrapper-button-height',
            '--theme-sig-control-timepicker-wrapper-button-width',
            '--theme-sig-control-timepicker-wrapper-button-border-radius',
            '--theme-sig-control-timepicker-wrapper-button-border-width',
            '--theme-sig-control-timepicker-wrapper-button-border-color',
            '--theme-sig-control-timepicker-wrapper-button-border-style',
            '--theme-sig-control-timepicker-wrapper-button-background-color',
            '--theme-sig-control-timepicker-wrapper-button-pressed-background-color',
            '--theme-sig-control-timepicker-wrapper-button-pressed-color',
            '--theme-sig-control-timepicker-wrapper-button-color'
        ]
    }

    /****************************************************************************************************
     *called thhen the required properties are set
     *
     ****************************************************************************************************/
    sigOnRequiredPropertiesReady() {
        super.sigOnRequiredPropertiesReady();
        this.propReady = true;
        this._setupDatepicker();
    }


    /****************************************************************************************************
     *  called after property default values are set and local DOM is initialized
     ****************************************************************************************************/
    ready() {
        super.ready();
        this.$.testInput._showKeyboard = () => { return };
        this.sigAddEventListener('value-changed', () => {
            this._inputValueChanged()
        }, 'jsEvent', this.$.testInput);

        this.sigAddEventListener('LANGUAGE_CHG', () => {
            this.allRendered = false;
            this.openAfterRender = false;
            this.$.testInput.iskeyboardopen = false;

            if (this.wrapper instanceof HTMLElement) {
                this.wrapper.remove()
                this.wrapper = null;
            }
            
            if(this.inputwindow instanceof HTMLElement) {
                this.inputwindow.remove();
                this.inputwindow = null;
            }

            this._setupDatepicker();
        }, 'runtimeEvent')
    }

    /****************************************************************************************************
     * Eventhandles when the value of the input text field changes
     ****************************************************************************************************/
    _inputValueChanged() {
        if(!this.timepickerClass) {
            return
        }
        //this.value = this.timepickerClass._getUnformatedDate().format('HH:mm:ss');
    }

    /****************************************************************************************************
     * Called when the component is rendered
     ****************************************************************************************************/
    _renderCallback() {
        this.renderedCB = true;
        this._setupDatepicker();
    }

    /****************************************************************************************************
     * Initializes the timepicker
     ****************************************************************************************************/
    _setupDatepicker() {
        if(this.isdesignmode) {
            this._designModeUpdatePlacehoder();
            return;
        }
        if(!this.renderedCB || !this.propReady) {
            return;
        }
        //Initialize the date/time picker
        this.timepickerClass = new DatepickerCylinder(/* this.$.testInput */this, {
            /* allInputsRenderedCB: () => {
                this.timepickerClass._close();
                this.wrapper.style.removeProperty('visibility');
                if(this.inputwindow) {
                    this.inputwindow.close();
                    this.inputwindow.style.removeProperty('visibility');
                }
                this._setWrapperFont();
            }, */
            allInputsRenderedCB: () => {
                this.allRendered = true;
                if(this.openAfterRender) {
                    this._tapHandler();
                } else {
                    //only in window mode -> but checking the window instance before closing is more general SA66356
                    if ((this.inputwindow !== undefined) && (this.inputwindow !== null)) {
                        this.inputwindow.close();
                    } 
                }
            },
            wrapperOptions: {
                hasnavbuttons: this.cylindershavenavbuttons,
                type: this.cylinderscrolltype
            },
            dateformat: this.timeformat,
            minDate: moment(this.mindate || 0),
            maxDate: moment(this.maxdate || 10000000000000),
            language: this._getActiveLang(),
            pickerHeight: this.pickerheight,
            pickerWidth: this.pickerwidth,
            setFontFunction: () => {
                this._setWrapperFont();
            }
        })

        
        this.timepicker = this.timepickerClass.datepicker;
        this.sigAddEventListener('closed', () => {
            this._closePicker();
        }, 'jsEvent', this.timepicker);

        //add the event listener for tap outside the list
        this.sigAddEventListener('tap', (event) => {
            //check if tap wasn't done on wrapper or window or element itself
            let compPath = event.composedPath();
            let filteredPath = compPath.filter((pathElement) => {
                return (pathElement.id === this.id) | (pathElement === this.wrapper) || (pathElement === this.inputwindow)
            });
            if (filteredPath.length === 0) {
                this._closePicker(); 
            }                   
        }, 'polymerEvent', window);   

        //Set the wrapper css
        this.wrapper = document.createElement('sig-control-timepicker-cylinder-picker-wrapper');
        this.wrapper.reqNames = [];
        const wrapperCSSText = this._getWrapperCSS();
        this.wrapper.style.cssText = wrapperCSSText;
        this.wrapper.style.visibility = 'hidden';
        this._setWrapperFont();
        
        if (this.windowed === "window") {
            this._setupWindowed();
        } else {
            this._setupDropdown();
        }
        //Initialize the control with the value currently written on the datapoint
        this._valueChanged();
    }

    /****************************************************************************************************
     * closes the picker
     ****************************************************************************************************/
     _closePicker() {
        this.$.testInput.iskeyboardopen = false;
        if(this.windowed === "dropdown") {
            this.wrapper.style.display = 'none';
        }
        if(this.windowed === "window") {
            if(this.inputwindow) {
                this.inputwindow.close();
            }
        }         
    }

    /****************************************************************************************************
     * Sets the Font of the Cylinder inputs
     ****************************************************************************************************/
    _setWrapperFont() {
        const fontObjProp = window.sigApi.properties.getProperty(this.id, 'timepickerfont');
        if(fontObjProp) {
            const fontObj = fontObjProp.getValue();
            if(fontObj) {
               /*  this.wrapper.updateStyles({
                    '--theme-sig-control-timepicker-cylinder-wrapper-font-size': fontObj.size + 'px',
                    '--theme-sig-control-timepicker-cylinder-wrapper-font-family': fontObj.fontFamily ? fontObj.fontFamily : 'inherit'
                }) */
                if(this.timepicker) {
                    const cylinders = this.timepicker.querySelectorAll('sig-control-cylinder-select');
                    for(let cylinder of cylinders) {
                        cylinder.listfontobj = fontObjProp;
                        cylinder.highlightfontobj = fontObjProp;
                        cylinder._updateHighlightFont(fontObjProp);
                        cylinder._updateListFont(fontObjProp);
                    }
                }
            }
        }
    }

    /****************************************************************************************************
     * Sets the timepicker up for being opened in a window
     ****************************************************************************************************/
    _setupWindowed() {
        if(!this.inputwindow) {
            let windowId = `${this.id}-input-window`;
            //   Actually creating the window here
            //   @param top The top position
            //   @param left The left position
            //   @param width The width of the window
            //   @param height The height of the window content. The actual window should be slightly higher because there are still the close and minimize buttons
            //   @param callback Is called when the window is created, has a reference to the created window as variable
            //   @param props Properties of the window
            //   @param windowId The id of the window
            this.wmApi.createWindow(this.windowtop, this.windowleft, '100px', '100px', (win) => {

                this.inputwindow = win;
                this.inputwindow.style.visibility = 'hidden';
                this.inputwindow.headertitle.innerText = this.windowtitle;
                
                //   Disable resizing, so that the window stays the same size as its content
                this.inputwindow.resizeit('disable');

                
                //   Set the window rotation to its parents rotation
                this.inputwindow.style.transform = `rotate(${this.rotation}deg)`
                //Make sure the window is in front
                this.sigSetTimeout(this.inputwindow.front, 100);

                //   Add the Input to the Window
                if(!this.wrapper.options) {
                    this.wrapper.options = {};
                }
                this.wrapper.options.type = 'window'
                this.inputwindow.querySelector('.jsPanel-content').appendChild(this.wrapper);

                //Listen for the window closed event.
                //more reliable than the jspanelbeforeclose in the window props
                this.sigAddEventListener('jspanelclosed', (evt) => {
                    if(evt.detail === this.inputwindow.id) {
                        this.$.testInput.iskeyboardopen = false;
                    }
                }, 'jsEvent', document);
                
                window.sigApi.vm.addRenderCallback(this.wrapper, () => {
                    this._wrapperRenderCallback();
                }, () => {
                    this._wrapperErrorRenderCallback();
                });  
            }, this._getWindowProps(), windowId);
        }
    }

    /****************************************************************************************************
     * Callback when the renderCallback of the wrapper timesout
     *
     ****************************************************************************************************/
    _wrapperErrorRenderCallback() {
        window.sigApi.vm.addRenderCallback(this.wrapper, () => {
            this._wrapperRenderCallback();
        }, () => {
            this._wrapperErrorRenderCallback();
        }); 
    }

    /****************************************************************************************************
     * Render Callback for the wrapper
     *
     ****************************************************************************************************/
    _wrapperRenderCallback() {
        //After the timepicker wrapper has been renderd, add the timepicker to it, and set its position
        this.wrapper.timepickerid = this.timepickerid;
        this.wrapper.timepicker = this.timepicker;
        this.wrapper._addTimepicker();
        this.wrapper.parent = this;
        this.wrapper._setControlPosition();
    }

    /****************************************************************************************************
     * Sets the timepicker up for being opened as a dropdown
     ****************************************************************************************************/
    _setupDropdown() {
        //Get the container where the timepicker is added to
        let container = this.closest('.jsPanel-content');
        if(!container) {
            //container = this.closest('sig-app');
            container = document.querySelector('sig-app');
        }
        container.appendChild(this.wrapper);
        window.sigApi.vm.addRenderCallback(this.wrapper, () => {
            this._wrapperRenderCallback();
        }, () => {
            this._wrapperErrorRenderCallback();
        }); 
    }

    /****************************************************************************************************
     * Parses the CSS that is meant for the wrapper out of the css of the component
     * @returns
     ****************************************************************************************************/
    _getWrapperCSS() {
        if (!this.wrapper) {
            return '';
        }
        const cs = getComputedStyle(this);
        let style = [];
        for(let prop of this.wrapperProps) {
            const value = cs.getPropertyValue(prop);
            if (value) style.push(prop + ':' + value);
        }
        return style.join(';');
    }


    /****************************************************************************************************
     * Called if there was an error rendering
     ****************************************************************************************************/
    _errorRenderCallback() {
        window.sigApi.vm.addRenderCallback(this, () => {
            this._renderCallback();
        }, () => {
            this._errorRenderCallback();
        })
    }

    /****************************************************************************************************
     * Handles a tap on the input, opens the date/time picker
     ****************************************************************************************************/
    _tapHandler() {
        const timepicker = this.wrapper.$.wrapper.querySelector(`#${this.timepickerid}`);
        this.$.testInput.iskeyboardopen = true;

        if(!this.allRendered) {
            this.openAfterRender = true;
            return;
        }
        if(this.windowed === "window") {
            if(this.inputwindow) {
                this.timepickerClass.open()
                this.inputwindow.open();
                this.inputwindow.style.removeProperty('visibility');
                this.wrapper.style.removeProperty('visibility');
                this.sigSetTimeout(this.inputwindow.front, 100);
                this.wrapper._setControlPosition();
            }
        } else {
            this.wrapper.style.removeProperty('display');
            this.wrapper.style.removeProperty('visibility');
            this.timepickerClass.open()
        }
    }

    /****************************************************************************************************
     * Returns a properties object for creating a window
     * @returns
     ****************************************************************************************************/
    _getWindowProps() {
        return {
            events: {

                jspanelbeforeclose: () => {
                    this.$.testInput.iskeyboardopen = false;
                    if (!this.closinginput) {
                    }
                }
            }
        };
    }

    /****************************************************************************************************
     * called after the element is detached from the DOM
     * can be called multiple times during the lifetime of an element
     *use this to cleanup your "mess" ;-)
     ****************************************************************************************************/
    disconnectedCallback() {
        super.disconnectedCallback();

        this.timepickerClass.cleanUp();
        this.timepickerClass = null;

        if(this.timepicker instanceof HTMLElement) {
            this.timepicker.remove();
            this.timepicker = null;
        }
        if(this.wrapper instanceof HTMLElement) {
            this.wrapper.remove();
            this.wrapper = null;
        }
        if(this.inputwindow instanceof HTMLElement) {
            this.inputwindow.remove();
            this.inputwindow = null;
        }
    }

    /****************************************************************************************************
     *  Called when the time on the Datapoint changes
     * @returns
     ****************************************************************************************************/
    _valueChanged() {
        if(!this.timepicker || this.$.testInput.iskeyboardopen) {
            return;
        }
        if(!this.value) {
            return;
        }
        let time = moment(this.value, 'HH:mm:ss');
        if(!time.isValid()) {
            return;
        }
        this.timepickerClass._setDate(time);
        this.$.testInput.value = time.locale(this._getActiveLang()).format(this.timeformat);
    }

    /****************************************************************************************************
     * Is called automatically when the css values change
     * needed because we need to update the wrapper CSS when a scheme changes its value 
     * @param {*} cssObj
     * @param {boolean} [doBoundsCheck=false]
     ****************************************************************************************************/
    sigApplyCSSValue(cssObj, doBoundsCheck = false) {
        super.sigApplyCSSValue(cssObj, doBoundsCheck);
    
        if(this.wrapper) {
            let wrapperCSSText = this._getWrapperCSS();
            // Filter for inline styles that werent set via getWrapperCCSS()
            //They need to be added for correct positioning of the control
            const currentWrapperCss = this.wrapper.style.cssText;
            const currentWrapperCssArr = currentWrapperCss.split(';');
            const additionalWrapperCss = currentWrapperCssArr.filter((val) => {
                const trimmedVal = val.trim()
                return trimmedVal.indexOf('--theme-sig-control-') === -1;
            })
            wrapperCSSText += ';' +  additionalWrapperCss.join(';');
            this.wrapper.style.cssText = wrapperCSSText;

            
        }
    }

    /****************************************************************************************************
     * observer for this.windowtitle
     * updates the title of the datepicker window
     *
     ****************************************************************************************************/
    _windowTitleChanged() {
        if(this.inputwindow && this.windowtitle) {
            this.inputwindow.headertitle.innerText = this.windowtitle
        }
    }

    /**********************************************************************************************************************************************************
     * observer for this.timeformat
     * updates the input value which is the timeformat while we are in the designmode
     *
     * @memberof LasalRuntimeSigDatepickerCylinder
    ***********************************************************************************************************************************************************/
    _designModeUpdatePlacehoder() {
        if (this.isdesignmode) {
            this.$["testInput"].value = this.timeformat;
        }
    }
}

customElements.define(LasalRuntimeSigTimepickerCylinder.is, LasalRuntimeSigTimepickerCylinder);