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

/**
 * @class
 * @classdesc Implements and exports the ght-group-content control.
 * @version 01.00.000
 * @extends LasalRuntimeSigElement
 * @property {String}   idvalue     - The value of the group id. Default is undefined.
 * @property {String}   actvalue    - The value of the actual value. Default is undefined.
 * @property {String}   setvalue    - The value of the set value. Default is undefined.
 * @property {String}   unittext    - The unit text of the value. Default is undefined.
 */
export class LasalRuntimeGroupContentElement extends LasalRuntimeSigElement {
    /**
     * Returns the component's registered tag name
     * @readonly
     * @static
     * @returns {String} The control's tag name.
     * @memberof LasalRuntimeGroupContentElement
     */
    static get is() {
        return "ght-group-content";
    }

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

    /**
     * Returns the HTML literal of the component.
     * @readonly
     * @static
     * @returns {HTMLLIElement} The template literal of the component.
     * @memberof LasalRuntimeGroupContentElement
     */
    static get template() {
        return SigPolymer.html`
        <style include="sig-element-css">
            :host {
                /* background-color: var(--ght-group-content-background-color, inherit); */
                border-width: var(--ght-group-content-border-width, 0px);
                border-color: var(--ght-group-content-border-color, inherit);
                border-style: var(--ght-group-content-border-style, none);
                border-radius: var(--ght-group-content-border-radius, 0px);

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

            :host * {
                /* Reset margin and paddings for child elements and turn of selection */
                margin: 0;
                padding: 0;
            }

            .clearfix:after {
                @apply --clearfix
            }

            /* the height is automatically set by number of zones in content */
            :host(:not([isdesignmode])) {
                height: auto !important;
            }

            .group-container {
                display: flex;
                flex-wrap: wrap;
                padding: var(--theme-ght-group-content-padding, 5px 0px);
                position: relative;
                gap: var(--theme-ght-group-content-gap, 5px 10px);
            }            

            ::slotted(.center) {
                position: relative !important;
            }
        </style>
        <div class="group-container clearfix" id="zoneContainer" >
            <template is="dom-if" if="[[isdesignmode]]">
                <img src="res/components/user/ght-group-content/zonePreview.svg">
                <img src="res/components/user/ght-group-content/zonePreview.svg">
                <img src="res/components/user/ght-group-content/zonePreview.svg">
                <img src="res/components/user/ght-group-content/zonePreview.svg">
                <img src="res/components/user/ght-group-content/zonePreview.svg">
                <img src="res/components/user/ght-group-content/zonePreview.svg">
            </template>
        </div>`;
    }

    /**
     * Returns the defined Polymer properties of the component.
     * @readonly
     * @static
     * @returns {Object} The defined Polymer properties.
     * @memberof LasalRuntimeGroupContentElement
     * 
    */
    static get properties() {
        const props = {
            groupid: {
                type: Number,
                observer: '_groupIDChanged',
                default: undefined
            }
        }
        return props;
    }


    /****************************************************************************************************
     * constructor
     * @memberof LasalRuntimeGroupContentElement
     ****************************************************************************************************/
    constructor() {
        super();
		if (this.isdesignmode) return;
        //request instance of group manager
        this.GHTGroupManager = codemoduleFactory.GlobalModules.requestInstances('ght_group_manager');
        if (this.GHTGroupManager) {
            //there should be at least one instance so access first entry
            this.GHTGroupManager = this.GHTGroupManager[0];
            //add group id as required property
            this.sigAddRequiredProperty('groupid');            
        }
        else {
            this._log('constructor(): invalid instance of group manager', 'ERROR');
        }
    }

    /****************************************************************************************************
     * gets called if default values are loaded
     *
     * @memberof LasalRuntimeGroupContentElement
     ****************************************************************************************************/
    ready() {
        super.ready();
        //as the height of the parent composite is calculated an translated later init it's size with 0
        if (this.parentNode.tagName === 'SIG-COMPOSITE-CONTROL') {
            this.parentNode.style.setProperty('--theme-sig-element-height', '0px'); 
        }
        //register for group change event
        if (!this.isdesignmode) {
            this.sigAddEventListener('GHT-ZONE-GROUP-CHANGED', (evt) => {
                //check for detail
                if (evt.detail) {
                    //check if group is effected
                    if ((this.groupid === evt.detail.oldValue) || (this.groupid === evt.detail.newValue)) {
                        //check if already initialized
                        if ((this.requiredPropsReady) && (this.isReady)) {
                            //reinitialize
                            this._reInit();
                        }
                    }
                }
            }, 'jsEvent', window);
        }

        this.isReady = true;
        if ((this.requiredPropsReady) && (this.groupid !== undefined)) {
            //initialize
            this.init();
        }
    }

    /****************************************************************************************************
     * gets called if required properties are ready
     *
     * @memberof LasalRuntimeGroupContentElement
     ****************************************************************************************************/
    sigOnRequiredPropertiesReady() {
        super.sigOnRequiredPropertiesReady();
        //set required properties ready info
        this.requiredPropsReady = true;
        if (this.isReady) {
            this.init();
        }
    }

    /****************************************************************************************************
     * method is used to initialize component
     *
     * @memberof LasalRuntimeGroupContentElement
     ****************************************************************************************************/
    async init() {
        //get cc prop
        const ccProp = window.sigApi.properties.getProperty(this.id, 'compositecontrol');
        if (ccProp) {
            //get parent viewmodel
            this.parentVM = window.sigApi.vm.getVmById(this.id);
            if (this.parentVM) {
                //get the ccprop value
                this.ccValue = ccProp.getValue();
                if (this.ccValue) {
                    //get name of the cc
                    this.ccName = this.ccValue.getName();
                    if (this.ccName) {
                        //check if instance of codemodule valid
                        if (this.GHTGroupManager) {
                            //get zones configured in this group
                            const zones = this.GHTGroupManager.getZones(this.groupid);
                            if ((zones) && (zones.length > 0)) {
                                for (let i=0;i<zones.length;i++) {
                                    //create slot to render cc
                                    let slot = document.createElement('slot');
                                    slot.zoneRef = zones[i];
                                    slot.name = 'slot-zone' + window.sigApi.sigUtils.getUID();
                                    //append slot to container
                                    this.$.zoneContainer.appendChild(slot);
                                    //append cc to slot
                                    window.sigApi.vm.appendNewCC(this.parentVM, this.ccName, slot.name, zones[i]);
                                }
                                //get children to set class
                                const children = this.parentVM.getChildren();
                                if ((children) && (children.length > 0)) {
                                    this.vmList = [];
                                    for (let i=0;i<children.length;i++) {
                                        if (children[i].getSlot().startsWith('slot-zone')) {
                                            children[i].getDomRef().classList.add('center');
                                            //add vm to list
                                            this.vmList.push(children[i]);
                                        }                                    
                                    }
                                }
                            }
                            //set height of the parent composite control
                            this._setHeight(zones.length);                          
                        }

                    }
                    else {
                        this._log('init(): failed to get cc name', 'ERROR');
                    } 
                } 
                else {
                    this._log('init(): failed to get cc value', 'ERROR');
                }
            }   
            else {
                this._log('init(): failed to get parent viewmodel', 'ERROR');
            }
        }
        else {
            this._log('init(): failed to get composite control', 'ERROR');
        }
    }

    /****************************************************************************************************
     * check configurations and reconfig zones
     *
     * @memberof LasalRuntimeGroupContentElement
     ****************************************************************************************************/
    _reInit() {
        if (this.GHTGroupManager) {
            //get configured zones
            const zones = this.GHTGroupManager.getZones(this.groupid);
            if ((this.vmList) && (this.vmList.length > 0)) {
                //go through vm list and overload them if neccessary
                for (let i=0;i<this.vmList.length;i++) {
                    //get slot
                    const slot = this.shadowRoot.querySelector(`slot[name="${this.vmList[i].getSlot()}"]`);
                    if (slot) {
                        //check if zone available for vm
                        if (zones.length > i) {
                            //check if slot needs to be overloaded
                            if (zones[i] !== slot.zoneRef) {
                                this.vmList[i].overload(zones[i]);
                                //change slot id
                                slot.zoneRef = zones[i];
                            }
                        }
                        else {
                            //remove vm
                            window.sigApi.vm.removeCC(this.parentVM, slot.name);
                            //remove slot
                            slot.remove();
                            //remove from list
                            this.vmList.splice(i, 1);
                            //manipulate i as entry was removed
                            i --;
                        }                        
                    }
                    else {
                        this._log('_reInit(): failed to get slot' + i, 'ERROR');
                    }
                }
            }    
            else {
                //init vm list
                this.vmList = [];
            }
            //check if vm needs to be added
            if (zones.length > this.vmList.length) {
                for(let i=this.vmList.length;i<zones.length;i++) {
                    //create slot to render cc
                    let slot = document.createElement('slot');
                    slot.zoneRef = zones[i];
                    slot.name = 'slot-zone' + window.sigApi.sigUtils.getUID();
                    //append slot to container
                    this.$.zoneContainer.appendChild(slot);
                    //append cc to slot
                    window.sigApi.vm.appendNewCC(this.parentVM, this.ccName, slot.name, zones[i]);
                }
                //get children to set class
                const children = this.parentVM.getChildren();
                if ((children) && (children.length > 0)) {
                    this.vmList = [];
                    for (let i=0;i<children.length;i++) {
                        if (children[i].getSlot().startsWith('slot-zone')) {
                            children[i].getDomRef().classList.add('center');
                            //add vm to list
                            this.vmList.push(children[i]);
                        }                                    
                    }
                }                        
            }
            //set height of containing composite
            this._setHeight(zones.length);            
        }
        else {
            this._log('_reInit(): invalid group manager instance', 'ERROR');
        }
    }

    /****************************************************************************************************
      * gets called if the group id changes
      *
      * @memberof LasalRuntimeGroupContentElement
      ****************************************************************************************************/
    _groupIDChanged() {
        if ((this.groupid !== undefined) && (this.isReady) && (this.requiredPropsReady)) {
            //reinitialize component
            this._reInit();
        }
    }

    /****************************************************************************************************
     * method is used to calculate and set the height of the parent composite control
     *
     * @memberof LasalRuntimeGroupContentElement
     ****************************************************************************************************/
    _setHeight(noOfZones) {
        if ((noOfZones > 0) && (this.parentNode.tagName === 'SIG-COMPOSITE-CONTROL')) {
            //get gap and padding settings of container
            const compStyle = getComputedStyle(this.$.zoneContainer);
            const padding = {
                top: parseFloat(compStyle.getPropertyValue('padding-top')),
                left: parseFloat(compStyle.getPropertyValue('padding-left')),
                right: parseFloat(compStyle.getPropertyValue('padding-right')),
                bottom: parseFloat(compStyle.getPropertyValue('padding-bottom'))
            };
            const gap = {
                column: parseFloat(compStyle.getPropertyValue('column-gap')),
                row: parseFloat(compStyle.getPropertyValue('row-gap'))
            };
            //get boundings of component
            const controlBounds = this.getControlBounds();
            //calculate width of content
            const width = controlBounds.width - padding.left - padding.right;
            //get dimensions of zone cc
            const controlJSON = this.ccValue.getControlsJson();
            const zoneDimensions = {
                height: parseFloat(controlJSON.props['--theme-sig-element-height'].value),
                width: parseFloat(controlJSON.props['--theme-sig-element-width'].value)
            }
            //calculate how many zones fit in row
            //we don't care if gap doesn't fit anymore in line
            const rest = width % (zoneDimensions.width + gap.column);
            const noOfZonesPerRow = Math.floor(width/(zoneDimensions.width + gap.column));
            //check if less or equal the gap size stops us from adding one more zone
            if (rest <= gap.column) {
                noOfZonesPerRow += 1;
            }
            //calculate number of lines
            const noOfLines = Math.ceil(noOfZones/noOfZonesPerRow);
            //calculate height
            const height = padding.top + (zoneDimensions.height * noOfLines) + ((noOfLines-1) * gap.row) + padding.bottom;
            //set height at composite control parent
            //now that we are initialized we can set the height of or parent cc
            this.parentNode.style.setProperty('--theme-sig-element-height', height + 'px');                        
        }
    }
}
customElements.define(LasalRuntimeGroupContentElement.is, LasalRuntimeGroupContentElement);
