// 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 * as moment from './moment/min/moment-with-locales.js';
import '../sig-control-button/sig-control-button.js'
import '../sig-control-button/sig-control-button-css.js'

import '../sig-control-cylinder-select/sig-control-cylinder-select.js';
import '../sig-control-cylinder-select/sig-control-cylinder-select-css.js';

/****************************************************************************************************
 * @class LasalRuntimeSigTimepickerCylinderPickerElement
 * @extends {LasalRuntimeSigElement}
 ****************************************************************************************************/
export class LasalRuntimeSigTimepickerCylinderPickerElement 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
     ****************************************************************************************************/
    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">
                :host {
                    /* Basic box model settings */
                    display: block;
                    position: absolute;
                    background-color: var(--theme-sig-control-timepicker-wrapper-background-color, rgba(255,255,255,1));
                }

                #wrapper {
                    position: absolute;
                }

                :host([visible]) {
                    display: block;
                }

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

                .clearfix:after {
                    @apply --clearfix
                }
                
                sig-control-button {
                    /** the variables from the css.js file are set here instead of importing
                        because otherwise i cannot override them */
                    --theme-sig-control-button-font-size: 11px;
                    --theme-sig-control-button-color: rgba(160, 160, 160, 1);
                    --theme-sig-control-button-background-color: rgba(64, 66, 72, 1);
                    --theme-sig-control-button-border-color: #000;
                    --theme-sig-control-button-pressed-background-color: rgba(174, 200, 26, 1);
                    --theme-sig-control-button-pressed-color: rgba(42, 42, 42, 1);
                    --theme-sig-control-button-led-border-width: 1px;
                    --theme-sig-control-button-led-border-color: rgba(0, 0, 0, 1);
                    --theme-sig-control-button-led-border-style: solid;
                    --theme-sig-control-button-led-background-color: rgba(204, 204, 204, 1);
                    --theme-sig-control-button-led-pressed-background-color: rgba(0, 119, 0, 1);


                    position:relative;
                    top: 0;
                    left: 0;
                    height: var(--theme-sig-control-timepicker-wrapper-button-height, 50px);
                    width: var(--theme-sig-control-timepicker-wrapper-button-width, 100px);
                    --theme-sig-control-button-border-radius: var(--theme-sig-control-timepicker-wrapper-button-border-radius, 3px);
                    --theme-sig-control-button-border-width: var(--theme-sig-control-timepicker-wrapper-button-border-width, 0px);
                    --theme-sig-control-button-border-color: var(--theme-sig-control-timepicker-wrapper-button-border-color, transparent);
                    --theme-sig-control-button-border-style: var(--theme-sig-control-timepicker-wrapper-button-border-style, none);
                    --theme-sig-control-button-background-color: var(--theme-sig-control-timepicker-wrapper-button-background-color, rgba(40,50,45,1));
                    --theme-sig-control-button-pressed-background-color: var(--theme-sig-control-timepicker-wrapper-button-pressed-background-color, rgba(175,200,26,1));
                    --theme-sig-control-button-pressed-color: var(--theme-sig-control-timepicker-wrapper-button-pressed-color, rgba(255,255,255,1));
                    --theme-sig-control-button-color: var(--theme-sig-control-timepicker-wrapper-button-color, rgba(255,255,255,1));
                    display: inline-block;
                    box-shadow: none;
                }

                sig-control-cylinder-select {
                    display: inline-block;
                    position: relative;
                    top: 0;
                    left: 0;

                    --theme-sig-control-cylinder-select-background-color: var(--theme-sig-control-timepicker-wrapper-cylinder-background-color,transparent);
                    --theme-sig-control-cylinder-select-background-image: var(--theme-sig-control-timepicker-wrapper-cylinder-background-image);
                    --theme-sig-control-cylinder-select-background-size: var(--theme-sig-control-timepicker-wrapper-cylinder-background-size);
                    --theme-sig-control-cylinder-select-background-position: var(--theme-sig-control-timepicker-wrapper-cylinder-background-position, initial);
                    --theme-sig-control-cylinder-select-background-repeat: var(--theme-sig-control-timepicker-wrapper-cylinder-background-repeat, no-repeat);
                    --theme-sig-control-cylinder-select-border-width: var(--theme-sig-control-timepicker-wrapper-cylinder-border-width);
                    --theme-sig-control-cylinder-select-border-style: var(--theme-sig-control-timepicker-wrapper-cylinder-border-style);
                    --theme-sig-control-cylinder-select-border-color: var(--theme-sig-control-timepicker-wrapper-cylinder-border-color,transparent);
                    --theme-sig-control-cylinder-select-border-radius: var(--theme-sig-control-timepicker-wrapper-cylinder-border-radius);
                    --theme-sig-control-cylinder-select-select-wrap-color: var(--theme-sig-control-timepicker-wrapper-cylinder-select-wrap-color,rgba(165, 171, 176, 1));
                    --theme-sig-control-cylinder-select-highlight-background-color: var(--theme-sig-control-timepicker-wrapper-cylinder-highlight-background-color,rgba(175,200,26,1));
                    --theme-sig-control-cylinder-select-highlight-border-color: var(--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-color,transparent);
                    --theme-sig-control-cylinder-select-highlight-border-width: var(--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-width);
                    --theme-sig-control-cylinder-select-highlight-border-style: var(--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-style);
                    --theme-sig-control-cylinder-select-highlight-border-top-width: var(--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-top-width);
                    --theme-sig-control-cylinder-select-highlight-border-top-style: var(--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-top-style);
                    --theme-sig-control-cylinder-select-highlight-border-top-color: var(--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-top-color,rgba(0,197,255,1));
                    --theme-sig-control-cylinder-select-highlight-border-bottom-width: var(--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-bottom-width);
                    --theme-sig-control-cylinder-select-highlight-border-bottom-style: var(--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-bottom-style);
                    --theme-sig-control-cylinder-select-highlight-border-bottom-color: var(--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-bottom-color,rgba(0,197,255,1));
                    --theme-sig-control-cylinder-select-highlight-border-radius: var(--theme-sig-control-timepicker-wrapper-cylinder-highlight-border-radius);
                    --theme-sig-control-cylinder-select-highlight-color: var(--theme-sig-control-timepicker-wrapper-cylinder-highlight-color,rgba(0, 0, 0, 1));
                    --theme-sig-control-cylinder-select-button-height: var(--theme-sig-control-timepicker-wrapper-cylinder-button-height, 20px);
                    --theme-sig-control-cylinder-select-button-background-color: var(--theme-sig-control-timepicker-wrapper-cylinder-button-background-color,transparent);
                    --theme-sig-control-cylinder-select-button-background-image: var(--theme-sig-control-timepicker-wrapper-cylinder-button-background-image);
                    --theme-sig-control-cylinder-select-button-down-background-image: var(--theme-sig-control-timepicker-wrapper-cylinder-button-down-background-image);
                    --theme-sig-control-cylinder-select-select-wrap-color: var(--theme-sig-control-timepicker-wrapper-cylinder-color,rgba(165, 171, 176, 1));
                    font-size: var(--theme-sig-control-timepicker-cylinder-wrapper-font-size, 14px);
                }

                #cylinderContainer {
                    white-space: nowrap;
                    display:flex;
                    justify-content: var(--theme-sig-control-timepicker-wrapper-cylinder-justify,space-between);
                }

                #controlContainer {
                    white-space: nowrap;
                }

                .sig-control-timepicker-cylinder-picker {
                    font-size: var(--theme-sig-control-timepicker-cylinder-wrapper-font-size, 14px);
                    font-family: var(--theme-sig-control-timepicker-cylinder-wrapper-font-family, inherit);
                }
            </style>
            <div class="sig-control-timepicker-cylinder-picker" id="wrapper">
            </div>
        `;
    }

    /****************************************************************************************************
     * define the custom tag name 
     ****************************************************************************************************/
    static get is() {
        return 'sig-control-timepicker-cylinder-picker-wrapper'
    }

    /****************************************************************************************************
     * 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() {
        return {
            timepickerid: {
                type: String,
                value: undefined
            },
            visible: {
                type: Boolean,
                value: false,
                reflectToAttribute: true
            }
        }
    }

    /****************************************************************************************************
     * called when the element has been created, but before property values are set and local DOM is initialized
     ****************************************************************************************************/
    constructor() {
        super();
        this.timepicker = undefined;
        this.options = {};
        this.windowContainerClass = 'jsPanel-content';
    }

    /****************************************************************************************************
     *  called after property default values are set and local DOM is initialized
     ****************************************************************************************************/
    ready() {
        super.ready();
    }

    /****************************************************************************************************
     *adds the timepicker to the wrapper
     *
     ****************************************************************************************************/
    _addTimepicker() {
        //const timepicker = document.querySelector(`#${this.timepickerid}`);
        if (this.timepicker) {
            this.$.wrapper.appendChild(this.timepicker);
        }

    }

    /****************************************************************************************************
     * Set Position
     * From sig-control-enum-list.html
     * @param {*} position
     ****************************************************************************************************/
    _setPosition(position) {
        if (this.parent instanceof HTMLElement) {
            //Opacity to 0.01 so that the component isn't visible
            //NOT display: none or opacity 0 because then the control bounds would be 0
            this.style.opacity = '0.01';

            SigPolymer.afterNextRender(this, function (params) {
                let rotation = 0;
                let scaleFactorApp = {
                    x: 1,
                    y: 1
                };
                let scaleFactorParent = {
                    x: 1,
                    y: 1
                };
                let windowOffset = {
                    x: 0,
                    y: 0
                };

                //We need to use getBoundingClientRect(); no other performant way to get position relative to the viewport!
                const parentBounds = this.parent.getBoundingClientRect();
                if (this.isdesignmode) {
                    // In designmode we need to calculate the real rotation 
                    rotation = this._getRealRotation(parseInt(this._getPathRotation(this.parent, this.parent.rotation, 10)));
                } else {
                    // In the normal runtime we get the precalculated value
                    rotation = this._getRealRotation(parseInt(this.parent.realrotation, 10));
                }
                this._log("Real Rotation: " + rotation);

                // It seems that getBoundingClientRect() does not take the scaling
                // into account. So we need to calulcate the scalingfactor of the 
                // container in which the enum list is created to normalize the position!
                // No need to calculate this in the designer runtime, there is no scaling applied
                if (!this.isdesignmode) {
                    scaleFactorApp = this._getScaleFactor(this.parent, rotation);
                    // If we run inside the window context we need to caluclate the window offset
                    if (this.parent.context.type === "window") {
                        const window = document.querySelector(`#${this.parent.context.instanceId} .${this.windowContainerClass}`);
                        if (window instanceof HTMLElement) {
                            const windowBounds = window.getBoundingClientRect();
                            windowOffset.x = (windowBounds.left / scaleFactorApp.x) - window.scrollLeft;
                            windowOffset.y = (windowBounds.top / scaleFactorApp.y) - window.scrollTop;
                        }
                    }
                }

                // We nedd to calculate the absolute scale factor of the enum parent control
                // so we can scale the enum optiolist entries
                // No need to calculate this in the designer runtime, there is no scaling applied
                if ((!this.isdesignmode) && (this.scalelist)) {
                    scaleFactorParent = this._getScaleFactor(this.parent, rotation);
                    this.$.list.style.transform = `scale( 1, ${scaleFactorParent.y})`;
                    this.$.list.style.transformOrigin = `0 0`;
                }

                // We need to remove the css vars for height/width while positioning the list, or the
                // container will get caluclated wrong if the options are updated while the list is visible!
                // This may cause some flickering on real slow devices :-(
                if (!this.hidden) {
                    this._removeDimension();
                }
                let hideAgain = false;
                const thisBounds = this.getControlBounds();
                //const pickerBounds = this.getControlBounds(this.$.wrapper.querySelector('.datepickerContainer'));
                let picker = this.$.wrapper.querySelector('.datepickerContainer');
                let top = 0,
                    left = 0,
                    height = picker.offsetHeight + 2*thisBounds.border, //this.offsetHeight * scaleFactorParent.y,
                    width = picker.offsetWidth +2*thisBounds.border; //this.offsetWidth * scaleFactorParent.x;

                const pTop = parentBounds.top / scaleFactorApp.y;
                const pLeft = parentBounds.left / scaleFactorApp.x;
                const pHeight = parentBounds.height / scaleFactorApp.y;
                const pWidth = parentBounds.width / scaleFactorApp.x;
                const pBottom = parentBounds.bottom / scaleFactorApp.y;
                const pRight = parentBounds.right / scaleFactorApp.x;

                const offsetX = 1;
                const offsetY = 1;

                switch (position) {
                    case 'top':
                        if (rotation === 90) {
                            if (width < pHeight) {
                                width = pHeight;
                            }
                            left = pRight + offsetY;
                            top = pTop;
                        } else if (rotation === 180) {
                            if (width < pWidth) {
                                width = pWidth;
                            }
                            left = pLeft - (width - pWidth);
                            top = pBottom + offsetY;
                        } else if (rotation === 270) {
                            if (width < pHeight) {
                                width = pHeight;
                            }
                            left = pLeft - height - offsetY;
                            top = pTop - (width - pHeight);
                        } else { // all other angles
                            if (width < pWidth) {
                                width = pWidth;
                            }
                            left = pLeft;
                            top = pTop - height - offsetY;
                        }
                        break;
                    case 'left':
                        if (rotation === 90) {
                            left = pRight - height;
                            top = pTop - width - offsetX;
                        } else if (rotation === 180) {
                            left = pRight + offsetX;
                            top = pBottom - height;
                        } else if (rotation === 270) {
                            left = pLeft;
                            top = pBottom + offsetX;
                        } else { // all other angles
                            left = pLeft - width - offsetX;
                            top = pTop;
                        }
                        break;
                    case 'right':
                        if (rotation === 90) {
                            left = pRight - height;
                            top = pBottom + offsetX;
                        } else if (rotation === 180) {
                            left = pLeft - width - offsetX;
                            top = pBottom - height;
                        } else if (rotation === 270) {
                            left = pLeft;
                            top = pTop - width - offsetX;
                        } else { // all other angles
                            left = pRight + offsetX;
                            top = pTop;
                        }
                        break;
                    default: // bottom
                        if (rotation === 90) {
                            if (width < pHeight) {
                                width = pHeight;
                            }
                            left = pLeft - height - offsetY;
                            top = pTop;
                        } else if (rotation === 180) {
                            if (width < pWidth) {
                                width = pWidth;
                            }
                            left = pLeft - (width - pWidth);
                            top = pTop - height - offsetY;
                        } else if (rotation === 270) {
                            if (width < pHeight) {
                                width = pHeight;
                            }
                            left = pRight + offsetY;
                            top = pTop - (width - pHeight);
                        } else {
                            if (width < pWidth) {
                                width = pWidth;
                            }
                            left = pLeft
                            top = pBottom + offsetY;
                            break;
                        }
                }

                this.$.wrapper.style.width = width + 'px';
                // We need to correct the position if the viewport is scrolled
                // or the context is window and we have a windows offset
                left += window.pageXOffset - windowOffset.x;
                top += window.pageYOffset - windowOffset.y;

                if (top < 0) {
                    top = 0;
                }
                if (left < 0) {
                    left = 0;
                }
                //const screenBounds = this.closest('sig-app').getControlBounds();
                //const screenBounds = document.querySelector('sig-app').getControlBounds();
                let screenEl = this.closest('.jsPanel-content');
                if(!screenEl) {
                    screenEl = this.closest('sig-app');
                }
                let screenBounds = {
                    height: screenEl.offsetHeight,
                    width: screenEl.offsetWidth
                }
                if (top > screenBounds.height) {
                    top = screenBounds.height - height;
                }
                if (left + width > screenBounds.width) {
                    left = screenBounds.width - width;
                }

                switch (rotation) {
                    case 0:
                    case 180:
                        if (top + height > screenBounds.height) {
                            top = screenBounds.height - height;
                        }
                        if (left + width > screenBounds.width) {
                            left = screenBounds.width - width;
                        }
                        break;
                    case 90:
                    case 270:
                        if (top > screenBounds.height) {
                            top = screenBounds.height - width;
                        }
                        if (left + height > screenBounds.width) {
                            left = screenBounds.width - height;
                        }
                        break;
                }
                // We only apply the rotation if it has changed
                // This is needed to make sure the translate gets updated 
                // correctly and avoid double paints
                if (rotation === this.oldRotation) {
                    this._setBounds(top, left, height, width);
                } else {
                    this._setBounds(top, left, height, width, rotation);
                }
                this._log(`Set bounds of "${this.id}" to "T: ${top}, L: ${left}, H: ${height}, W:${width}, R: ${rotation}deg"`);
                this.oldRotation = rotation;
                this.style.opacity = '1';
                if (hideAgain) {
                    this.$.wrapper.querySelector('.dtp').classList.add('hidden');
                }
            });
        }
    }

    /****************************************************************************************************
     * calculates the scale factor
     *
     * @param {*} [control=this]
     * @param {number} [rotation=0]
     * @returns
     ****************************************************************************************************/
    _getScaleFactor(control = this, rotation = 0) {
        let scaleFactor = { x: 1, y: 1 };
        if (control instanceof HTMLElement) {
            if (rotation === 90 || rotation === 270) {
                scaleFactor.y = control.getBoundingClientRect().height / control.offsetWidth;
                scaleFactor.x = control.getBoundingClientRect().width / control.offsetHeight;
            } else {
                scaleFactor.y = control.getBoundingClientRect().height / control.offsetHeight;
                scaleFactor.x = control.getBoundingClientRect().width / control.offsetWidth;
            }
        }
        this._log(`Calculated scale factor for rotateion ${rotation} is X = "${scaleFactor.x}" Y = "${scaleFactor.y}`);
        return scaleFactor;
    }

    /****************************************************************************************************
     * returns the rotation
     * @param {number} [rotation=0]
     * @returns
     ****************************************************************************************************/
    _getRealRotation(rotation = 0) {
        return (rotation % 360 + 360) % 360;
    }

    /****************************************************************************************************
     * Removes the sig-element-width and -heigth
     ****************************************************************************************************/
    _removeDimension() {
        // We need to remove the applied the css vars to fallback default width
        this.style.removeProperty('--theme-sig-element-width');
        this.style.removeProperty('--theme-sig-element-height');
    }

    /****************************************************************************************************
     * If the element isn't visible, this function makes it visible
     ****************************************************************************************************/
    _makeVisible() {
        // We delay making the list visible till the first positioning is done. 
        // This avoids that the unpositioned list pops up for a second.
        if (this.style.visibility === 'hidden' && !this.isVisible) {
            this.sigSetTimeout(() => {
                this.style.removeProperty('visibility');
                this.isVisible = true;
            }, this.setVisibleDelay);
        }
    }

    /****************************************************************************************************
     * Gets the rotation for the element + the parents rotation
     * @param {*} control
     * @param {*} pathRotation
     * @returns
     ****************************************************************************************************/
    _getPathRotation(control, pathRotation) {
        let parent = control.parentNode;
        if (parent.tagName.toLowerCase() !== 'sig-composite-control') {
            return pathRotation;
        }
        let isCompositeContainer = true;
        let rotation = pathRotation;
        while (isCompositeContainer) {
            if (parent.tagName.toLowerCase() === 'sig-composite-container') {
                rotation += parseInt(parent.rotation, 10);
                this._log(`Parent: ${parent.id}: ${parent.rotation} / GES: ${rotation}`);
                parent = parent.parentNode;
            } else {
                isCompositeContainer = false;
            }
        }
        return rotation;
    }

    /****************************************************************************************************
     * Sets the control position inside a window
     * which should always be top: 0, left 0
     ****************************************************************************************************/
    _setControlPositionWindow() {
        this.updateStyles({
            '--theme-sig-element-top': 0 + 'px',
            '--theme-sig-element-left': 0 + 'px'
        });
        // Control Bounds of the Control itself
        //const cControlBounds = this.getControlBounds(this.$.wrapper);
        const cControlBounds = {
            height: this.$.wrapper.offsetHeight,
            width: this.$.wrapper.offsetWidth,
            left: this.$.wrapper.offsetLeft,
            top: this.$.wrapper.offsetTop
        }
        // If the colorpicker is opened in window mode, 
        // there is no need for special positioning
        if (this.options.type === 'window') {
            this._sizeWindow(cControlBounds);
            this._setWindowPosition();
            this.style.position = 'relative';
            this.style.height = '100%';
            this.style.width = '100%';
        }

    }

    /****************************************************************************************************
     * If the colorpicker is shown in a window, 
     * set the window size correctly
     * @param {*} controlBounds
     ****************************************************************************************************/
    _sizeWindow(controlBounds) {
        const containerWindowContent = this.closest('.jsPanel-content')
        const containerWindow = this.closest('.jsPanel');
        // Height of the window content
        containerWindowContent.style.height = controlBounds.height + 1 + 'px';
        // Width of the window
        containerWindow.style.width = controlBounds.width + 1 + 'px';
        containerWindow.style.height = '';
        containerWindow.resize();
    }

    /****************************************************************************************************
     * If the colorpicker is shown in a window
     * make sure the window is inside the bounds of the display
     ****************************************************************************************************/
    _setWindowPosition() {
        const window = this.closest('.jsPanel');
       // const windowBounds = this.getControlBounds(window);
       const screenBounds = document.querySelector('html').querySelector('sig-app'); //TODO
       // const wTop = windowBounds.top;
       // const wLeft = windowBounds.left;
       // const width = windowBounds.width;
       // const height = windowBounds.height;
       const wTop = window.offsetTop;
       const wLeft = window.offsetLeft;
       const width = window.offsetWidth;
       const height = window.offsetHeight;
        let top = wTop;
        let left = wLeft;

        if (top + height > screenBounds.height) {
            top = screenBounds.height - height;
        }
        if (left + width > screenBounds.width) {
            left = screenBounds.width - width;
        }
        if (top < 0) {
            top = 0;
        }
        if (left < 0) {
            left = 0;
        }

        window.style.top = top + 'px';
        window.style.left = left + 'px';
    }

    /****************************************************************************************************
     * Sets the control position
     * Makes sure the control isn#t out of bounds
     * For dropdowns it also makes sure the dropdown isnt covering the input
     ****************************************************************************************************/
    _setControlPosition() {
        this.updateStyles({
            '--theme-sig-element-top': 0 + 'px',
            '--theme-sig-element-left': 0 + 'px'
        });
        //Check if the colorpicker is a window or dropdown, and call the correct function
        if (this.options.type === 'window') {
            this._setControlPositionWindow();
        } else {
            this._setControlPositionDropdown();
        }
    }

    /****************************************************************************************************
     * Sets the Control Position depending on how the control is rotated
     ****************************************************************************************************/
    _setControlPositionDropdown() {
        this._setPosition();
    }

    /****************************************************************************************************
     * 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();

        if(this.timepicker instanceof HTMLElement) {
            this.timepicker.remove();
            this.timepicker = null;
        }
    }
}
customElements.define(LasalRuntimeSigTimepickerCylinderPickerElement.is, LasalRuntimeSigTimepickerCylinderPickerElement);