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

/****************************************************************************************************
 * @class LasalRuntimeControlBarRound
 * @extends {LasalRuntimeSigElement}
 ****************************************************************************************************/
export class LasalRuntimeControlBarRound extends LasalRuntimeSigElement {
    /****************************************************************************************************
     * define the custom tag name 
     ****************************************************************************************************/
    static get is() {
        return "sig-control-bar-round";
    }

   /****************************************************************************************************
    * 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 styling of the component */
                background-color: var(--theme-sig-control-bar-round-background-color, inherit);

                border-width: var(--theme-sig-control-bar-round-border-width, inherit);
                border-color: var(--theme-sig-control-bar-round-border-color, inherit);
                border-style: var(--theme-sig-control-bar-round-border-style, none);
                border-radius: var(--theme-sig-control-bar-round-border-radius, 0);

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

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

            .clearfix:after {
                @apply --clearfix
            }

            .sig-control-bar-round {
                position: relative;
                width: 100%;
                height: 100%;
            }

            #actval {
                position: relative;
                height: 100%;
                width: 100%;
            }
        </style>
        <div class="sig-control-bar-round clearfix" controlCustomFont>
            <div id="actval"></div>
        </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() {
        let props =
        {
            // ---------- value ----------
            actvalueuc:
            {
                type: Number,
                value: 0,
                observer: "_redraw",
            },
            limitlowuc:
            {
                type: Number,
                value: 0,
                observer: "_draw",
            },
            limithighuc:
            {
                type: Number,
                value: 100,
                observer: "_draw",
            },
            mincolorlimituc: {
                type: Number,
                value: '',
                observer: "_draw"
            },
            maxcolorlimituc: {
                type: Number,
                value: '',
                observer: "_draw"
            },
            // ---------- sizes ------------
            startangle: {
                type: Number,
                value: 90,
                observer: '_initObs'
            },
            endangle: {
                type: Number,
                value: 270,
                observer: '_initObs'
            },
            progresscounterclockwise: {
                type: Boolean,
                value: false,
                observer: '_draw'
            },
            arcwidth:
            {
                type: Number,
                value: 25,
                observer: "_draw"
            },
            // ---------- color ----------
            arccolorbg:
            {
                type: String,
                value: "rgba(165,171,176,1)",
                observer: "_draw"
            },
            arccolorfill: {
                type: String,
                value: "rgba(175,200,26,1)",
                observer: "_draw"
            },
            arccolorfillstop:
            {
                type: String,
                value: "",
                observer: "_draw"
            },
            previewvalue: {
                type: Number,
                value: 50,
                observer: '_redraw'
            },
            previewmin: {
                type: Number,
                value: 0,
                observer: '_draw'
            },
            previewmax: {
                type: Number,
                value: 100,
                observer: '_draw'
            },
            previewminlimit: {
                type: Number,
                value: '',
                observer: '_draw'
            },            
            previewmaxlimit: {
                type: Number,
                value: '',
                observer: '_draw'
            },            
            mincolorlimit: {
                type: Number,
                value: '',
                observer: "_draw"
            },
            maxcolorlimit: {
                type: Number,
                value: '',
                observer: "_draw"
            },
            bgcolorrangeminvalue: {
                type: String,
                value: 'rgba(0,64,255,1)',
                observer: "_draw"
            },
            bgcolorrangemaxvalue: {
                type: String,
                value: 'rgba(168,0,0,1)',
                observer: "_draw"
            }
        };
        return props;
    }

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

        // add predef properties to avoid recalculations during drawing
        this.addPredefProps([
            {
                src: 'actvalue',
                dest: 'actvalueuc',
                type: window.sigApi.SIG_CONST.PROP_PREDEF_PROPS_TYPE_UNCONVERTED_VALUE
            }, 
            {
                src: 'limitlow',
                dest: 'limitlowuc',
                type: window.sigApi.SIG_CONST.PROP_PREDEF_PROPS_TYPE_UNCONVERTED_VALUE
            }, 
            {
                src: 'limithigh',
                dest: 'limithighuc',
                type: window.sigApi.SIG_CONST.PROP_PREDEF_PROPS_TYPE_UNCONVERTED_VALUE
            },
            {
                src: 'mincolorlimit',
                dest: 'mincolorlimituc',
                type: window.sigApi.SIG_CONST.PROP_PREDEF_PROPS_TYPE_UNCONVERTED_VALUE
            },
            {
                src: 'maxcolorlimit',
                dest: 'maxcolorlimituc',
                type: window.sigApi.SIG_CONST.PROP_PREDEF_PROPS_TYPE_UNCONVERTED_VALUE
            }
        ]);

        // add required properties
        this.sigAddRequiredProperty('actvalueuc');
        this.sigAddRequiredProperty('limitlowuc');
        this.sigAddRequiredProperty('limithighuc');
    }


    /****************************************************************************************************
     * called after property default values are set and local DOM is initialized
     *
     * @memberof LasalRuntimeControlBarRound
    ****************************************************************************************************/
    ready() {
        super.ready();
        this.isReady = true;

        // wait for next render in designer, for getting control bounds
        if (this.isdesignmode) {
            this.propsReady = true; 
            SigPolymer.afterNextRender(this, function () {
                this._draw();
            });

        // no designer, get control bounds immediately
        } else {
            if (this.propsReady) {
                this._draw();
            }  
        }
    }

     /****************************************************************************************************
      * called when values are ready
      *
      * @memberof LasalRuntimeControlBarRound
     ****************************************************************************************************/
     sigOnRequiredPropertiesReady() {
        super.sigOnRequiredPropertiesReady();
        this.propsReady = true; 

        if (this.isReady) {
            this._draw();
        }
    }

    /****************************************************************************************************
     * function is called if component gets resized in designmode
     *
     * @memberof LasalRuntimeControlBarRound
    ****************************************************************************************************/
    designerOnBoundsChanged() {
        if (this.drawed) {
            SigPolymer.afterNextRender(this, () => {
                this._draw();
            })
        }
    }

    /****************************************************************************************************
     * function to calculate factor for drawing and draw bar
     *
     * @memberof LasalRuntimeControlBarRound
    ****************************************************************************************************/
    _initObs () {
        if (this.drawed) {
            this._draw();
        }
    }

   /****************************************************************************************************
     * function to calculate factor for drawing and draw bar
     *
     * @memberof LasalRuntimeControlBarRound
    ****************************************************************************************************/
    _getFactor() {

        // get bound of control
        this.bounds = this.getControlBounds();

        //correct angles for calculation
        let startAngle = (this.startangle - 270);
        let endAngle = (this.endangle - 270);

        // adjust the angles if the start angle is too low (-90° to 90° for example)
        if (startAngle <= -360) {
            startAngle += 360;
            endAngle += 360;
        }

        //check for crossing the axes
        const cross0 = (startAngle <= 0) && (endAngle >= 0);
        const cross90 = (startAngle <= 90) && (endAngle >= 90);
        const cross180 = ((startAngle <= -180) && (endAngle >= -180)) || ((startAngle <= 180) && (endAngle >= 180));
        const cross270 = ((startAngle <= -90) && (endAngle >= -90)) || ((startAngle <= 270) && (endAngle >= 270));

        // calculate maximum dimensions
        const xStart = Math.cos(startAngle * Math.PI / 180);
        const xEnd = Math.cos(endAngle * Math.PI / 180);
        const yStart = Math.sin(startAngle * Math.PI / 180);
        const yEnd = Math.sin(endAngle * Math.PI / 180);

        // get maximums and minimums for bound calculation
        const xMinFactor = Math.min(xStart, xEnd);
        const xMaxFactor = Math.max(xStart, xEnd);
        const yMinFactor = Math.min(yStart, yEnd);
        const yMaxFactor = Math.max(yStart, yEnd);

        // calculate outer bounds
        const left = cross180 ? -1 : xMinFactor;
        const right = cross0 ? 1 : xMaxFactor;
        const top = cross90 ? 1 : yMaxFactor;
        const bottom = cross270 ? -1 : yMinFactor;

        this._getBorderWidth();

        // we need to manipulate control width as the arcwidth needs to be evaluated too
        // this is only needed if positions are on same side which is the case if the sign is the same
        let controlWidth = (this.bounds.width - this.borderLeftWidth - this.borderRightWidth);
        let controlHeight = (this.bounds.height - this.borderTopWidth - this.borderBottomWidth);

        let majorWidth = this.arcwidth;
        if ((majorWidth === "") || (majorWidth === undefined)) {
            majorWidth = 10; // set to default (10px)
        }

        // check if controlwidth needs to be compensated
        if ((left < 0) === (right < 0)) {
            //we have to compensate the arcwidth for control width
            if (Math.abs(left) < Math.abs(right)) {
                controlWidth -= majorWidth * Math.abs(left);
            }
            else {
                controlWidth -= majorWidth * Math.abs(right);
            }
        }

        // check if controlHeight needs to be compensated
        if ((top < 0) === (bottom < 0)) {
            //we have to compensate the arcwidth for control width
            if (Math.abs(top) < Math.abs(bottom)) {
                controlHeight -= majorWidth * Math.abs(top);
            }
            else {
                controlHeight -= majorWidth * Math.abs(bottom);
            }
        }

        // calculate factor
        let widthFactor =  controlWidth / Math.abs(left - right);
        let heightFactor = controlHeight / Math.abs(top - bottom);
        this.radius = (heightFactor < widthFactor ? heightFactor : widthFactor);

        // start calculating position of arc
        // calculation is done angles given by the user - y coordinates are inverted
        let midAngleRad;    
        // get a good midpoint - determine midangle
        if (Math.abs(startAngle - endAngle) < 90) {
            midAngleRad = ((90 + endAngle) % 360) * Math.PI / 180;
        }
        else {
            midAngleRad = (((startAngle + endAngle) / 2) % 360) * Math.PI / 180;
        }

        let midX   = Math.cos(midAngleRad);
        let midY   = Math.sin(midAngleRad);

        // Scale the coordinates to the controlWidth and controlHeight.
        let minX = Math.min(xStart, xEnd);
        let minY = Math.min(-yStart, -yEnd);
        let maxX = Math.max(xStart, xEnd);
        let maxY = Math.max(-yStart, -yEnd);

        // check if any of the perpendicular angles are inside the range
        if (cross270) {
            maxY = Math.max(maxY, 1);   // inversion, because of coordinates given in image coordinates here
        }
        if (cross180) {
            minX = Math.min(minX, -1);
        }
        if (cross90) {
            minY = Math.min(minY, -1);  // inversion, because of coordinates given in image coordinates here
        }
        if (cross0) {
            maxX = Math.max(maxX, 1);
        }

        let scaledStartX;
        let scaledStartY;
        let scaledEndX;
        let scaledEndY;
        let scaledMidX;
        let scaledMidY;
        let minScaledX = 0;
        let maxScaledX = 0;
        let minScaledY = 0;
        let maxScaledY = 0;

        scaledStartX = (xStart * this.radius);
        scaledEndX = (xEnd * this.radius);
        scaledMidX = (midX * this.radius);

        scaledStartY = (yStart * this.radius);
        scaledEndY = (yEnd * this.radius);
        scaledMidY = (midY * this.radius);

        // define temporary variables to shorten the equation to calculate the circle midpoint
        let dist12X = scaledStartX - scaledEndX;
        let dist12Y = scaledStartY - scaledEndY;
        let dist13X = scaledStartX - scaledMidX;
        let dist13Y = scaledStartY - scaledMidY;
        let dist1_2 = scaledStartX*scaledStartX + scaledStartY*scaledStartY;
        let dist2_2 = scaledEndX*scaledEndX     + scaledEndY*scaledEndY;
        let dist3_2 = scaledMidX*scaledMidX     + scaledMidY*scaledMidY;

        // treat special case of angles with identical x position between start and end
        // to avoid division by zero in below formula                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
        if (Math.abs(dist12X) < 0.000001) {
            minScaledX    = Math.min(scaledStartX, scaledEndX, minX * this.radius, maxX * this.radius);
            maxScaledX    = Math.max(scaledStartX, scaledEndX, minX * this.radius, maxX * this.radius);

            // shift is given by half of the controlwidth - minScaledX - (maxScaledX - minScaledX)/2
            this.pivotX = controlWidth / 2 - (maxScaledX + minScaledX) / 2;
            this.pivotY = controlHeight / 2;
        }
        else {
            // A - scaledStartX*B - scaledStartY*C = -relStart2
            // B - scaledEndX*B   - scaledMidY*C = -relEnd2
            // C - scaledMidX*B   - scaledMidY*C = -relMid2
            // A = midPointX^2 + midPointY^2 - r^2 (A is not calculated since it is not needed (the radius is known))
            // midPointX = B/2
            // midPointY = C/2
            let midPointY = (dist1_2 - dist3_2 - dist13X / dist12X * (dist1_2 - dist2_2)) / (dist13Y - dist12Y * dist13X / dist12X) / 2;
            let midPointX = ((dist1_2 - dist2_2) / dist12X - 2*midPointY*dist12Y/dist12X) / 2;
            let pivShiftX = 0;
            let pivShiftY = 0;

            // move the complete circle into window of view
            scaledStartX = midPointX + scaledStartX;
            scaledStartY = midPointY - scaledStartY;
            scaledEndX   = midPointX + scaledEndX;
            scaledEndY   = midPointY - scaledEndY;

            minScaledX    = Math.min(scaledStartX, scaledEndX, midPointX + minX * this.radius);
            minScaledY    = -Math.max(scaledStartY, scaledEndY, midPointY + maxY * this.radius);
            maxScaledX    = Math.max(scaledStartX, scaledEndX, midPointX + maxX * this.radius);
            maxScaledY    = -Math.min(scaledStartY, scaledEndY, midPointY + minY * this.radius);

            scaledStartX  = scaledStartX - minScaledX;
            scaledEndX    = scaledEndX - minScaledX;
            scaledStartY  = scaledStartY - minScaledY;
            scaledEndY    = scaledEndY - minScaledY;

            // check if middle shift must be done
            if (Math.abs(maxScaledX - minScaledX) < controlWidth) {
                pivShiftX = minScaledX - (controlWidth - Math.abs(maxScaledX - minScaledX))/2;
            }
            else {
                pivShiftX = minScaledX;
            }
            if (Math.abs(maxScaledY - minScaledY) < controlHeight) {
                pivShiftY = minScaledY - (controlHeight - Math.abs(maxScaledY - minScaledY))/2;
            }
            else {
                pivShiftY = minScaledY;
            }

            this.pivotX = midPointX - pivShiftX;
            this.pivotY = midPointY - pivShiftY;
       }
    }

    /****************************************************************************************************
     * draw all the components for displaying the act value
     *
     * @memberof LasalRuntimeControlBarRound
    ****************************************************************************************************/
    _draw() {
        // only draw if everything is ready
        if ((!this.isReady) || (!this.propsReady)) return;

        if (this.startangle === this.endangle) {
            this._log("_draw(): start and end angle must not be equal!", "ERROR");
            return;
        }

        this._getFactor();

        let majorWidth = this.arcwidth;
        if ((majorWidth === "") || (majorWidth === undefined)) {
            majorWidth = 10; // set to default (10px)
        }
        // In case the end angle is smaller, switch it so that they can be compared
        while (this.startangle > this.endangle) {
            this.endangle += 2 * 180;
        }

        // remove old svg
        while(this.$.actval.firstChild) {
            this.$.actval.removeChild(this.$.actval.firstChild);
        }

        let gradientStyle;
            if (this.isdesignmode) {
                // get the style string according to the actual position and range settings
            gradientStyle = this._getGradientStyle(this.previewmin, this.previewmax, this.previewminlimit, this.previewmaxlimit);
            } else {
                // get the style string according to the actual position and range settings
            gradientStyle = this._getGradientStyle(this.limitlowuc, this.limithighuc, this.mincolorlimituc, this.maxcolorlimituc);
        }

        this.arcInnerRadius = this.radius - majorWidth;
        this.arcOuterRadius = this.radius;
        if (!this.progresscounterclockwise) {
            this.arcStartAngle  = this.startangle / 180 * Math.PI;
            this.arcEndAngle = this._getCurrentAngle() / 180 * Math.PI;
        } else {
            this.arcStartAngle = this._getCurrentAngle() / 180 * Math.PI;
            this.arcEndAngle    = this.endangle / 180 * Math.PI;
        }

        // draw arc for the bar background
        d3.select(this.$.actval).append("svg:svg")
            .attr("width", "100%")
            .attr("height", "100%")
            .style("position", "absolute")
            .append("svg:path")
                .attr("d", d3.arc()
                .innerRadius(this.arcInnerRadius)
                .outerRadius(this.arcOuterRadius)
                .startAngle(this.startangle / 180 * Math.PI)
                .endAngle(this.endangle / 180 * Math.PI)
                )
                .attr("transform", "translate(" + String(this.pivotX) + "," + String(this.pivotY) + ") rotate(180)")          
                .style("fill", this.arccolorbg);


        // append the bar to the svg
        this.body = d3.select(this.$.actval)
                .append("svg:svg")
                .attr("id", "ringSVG")
                .attr("width", "100%")
                .attr("height", "100%")
                .style("position", "absolute")
                .attr("clip-path", "url(#clipPathSVG)")
                .style("background-image", gradientStyle);

        const defs = this.body.append("defs");  
        
        defs.append("clipPath")
                    .attr("id", "clipPathSVG")
                    .append("svg:path")
                        .attr("d", d3.arc()
                        .innerRadius(this.arcInnerRadius)
                        .outerRadius(this.arcOuterRadius)
                        .startAngle(this.arcStartAngle)
                        .endAngle(this.arcEndAngle)
                        )
                        .attr("transform", "translate(" + String(this.pivotX) + "," + String(this.pivotY) + ") rotate(180)");           

        // used for updating the clipping mask in _redraw()
        this.barMask = d3.select(this.$.actval).select('#clipPathSVG');

        // first draw is done
        this.drawed = true;
    }

    /****************************************************************************************************
     * function to redraw the act value and bar
     *
     * @memberof LasalRuntimeControlBarRound
    ****************************************************************************************************/
    _redraw() {
        if(this.drawed === true) {
            if (this.barMask === undefined) {                
                // error => can't find the element
                this._log("Can't find the ring element to adjust the current angle", 'ERROR');
                return;
            }

            if (!this.progresscounterclockwise) {
                this.arcEndAngle = this._getCurrentAngle() / 180 * Math.PI;
            } else {
                this.arcStartAngle = this._getCurrentAngle() / 180 * Math.PI;
            }

            // Define the new arc using the updated start and end angles
            const newArc = d3.arc()
                .innerRadius(this.arcInnerRadius)
                .outerRadius(this.arcOuterRadius)
                .startAngle(this.arcStartAngle)
                .endAngle(this.arcEndAngle)

            // Update the 'd' attribute of the path within the clip path
            this.barMask.select("path")
                .attr("d", newArc);            
        }
    }

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

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

    /****************************************************************************************************
    * Calculates the current angle based on the position, angle range and inverse settings
    *
    * @memberof LasalRuntimeControlBarRound
    ****************************************************************************************************/
    _getCurrentAngle() {
        let percentage;

        // calculate position of bar
        if (this.isdesignmode === false) {
            if ((this.limitlowuc !== undefined) && (this.limithighuc !== undefined)){
                
                let calcValue = parseFloat(this.actvalueuc);
                let limithigh = parseFloat(this.limithighuc);
                let limitlow = parseFloat(this.limitlowuc);

            // check limits
                if (calcValue > limithigh) {
                    calcValue = limithigh;
                } else if (calcValue < limitlow) {
                    calcValue = limitlow;
            }

            // calculate position
                percentage = (calcValue - limitlow) / (limithigh - limitlow);
            
            //avoid calulating with NaN
            if(isNaN(percentage)) {
                percentage = 0;
            }
                // don't go over 100%!
            if (percentage > 1) {
                percentage = 1;
            }  
            }
            else {
                percentage = 0;
            }
        } else {
            // calc the new endpoint of the arc
            percentage = (this.previewvalue - this.previewmin) / (this.previewmax - this.previewmin);
        }
            
            let tempStartAngle = this.startangle;
            let tempEndAngle = this.endangle;
            if (this.progresscounterclockwise === true) {
                // calculate back from the end angle
                return tempEndAngle - percentage * (tempEndAngle - tempStartAngle);
            } else {
                // calculate from the start angle
                return tempStartAngle + percentage * (tempEndAngle - tempStartAngle);
            }            
        }

    /****************************************************************************************************
    * Calculates the current gradient style based on the position, inverse settings, colors and ranges
    *
    * @memberof LasalRuntimeControlBarRound
    ****************************************************************************************************/
    _getGradientStyle(min, max, minlimit, maxlimit) {
        const isValidNumber = val => typeof val === "number" && !isNaN(val);
        const startPosition = ` at ${this.pivotX}px ${this.pivotY}px`;
    
        // if the stop color is not defined => use the fill color (no gradient)
        let arcStopColor = ((this.arccolorfillstop === "inherit") || (this.arccolorfillstop === "")) ? this.arccolorfill : this.arccolorfillstop;
    
        const getAngle = (value) => {
            return this.progresscounterclockwise 
                ? this.endangle - ((value - min) / (max - min)) * (this.endangle - this.startangle)
                : ((value - min) / (max - min)) * (this.endangle - this.startangle);
        };
        
        const minAngle = getAngle(isValidNumber(minlimit) ? parseFloat(minlimit) : min);
        const maxAngle = getAngle(isValidNumber(maxlimit) ? parseFloat(maxlimit) : max);
    
        let beginning = "", mainPart = "", end = "";
    
        if (this.progresscounterclockwise) {
            if (isValidNumber(maxlimit)) {
                beginning = `${this.bgcolorrangemaxvalue} 0deg, ${this.bgcolorrangemaxvalue} ${maxAngle - this.startangle}deg, `;
            }
            mainPart = `${arcStopColor} ${maxAngle - this.startangle}deg, ${this.arccolorfill} ${minAngle - this.startangle}deg, `;
            if (isValidNumber(minlimit)) {
                end = `${this.bgcolorrangeminvalue} ${minAngle - this.startangle}deg, ${this.bgcolorrangeminvalue} ${(this.endangle - this.startangle)}deg, `;
            }
        } else {
            if (isValidNumber(minlimit)) {
                beginning = `${this.bgcolorrangeminvalue} 0deg, ${this.bgcolorrangeminvalue} ${minAngle}deg, `;
            }
            mainPart = `${this.arccolorfill} ${minAngle}deg, ${arcStopColor} ${maxAngle}deg, `;
            if (isValidNumber(maxlimit)) {
                end = `${this.bgcolorrangemaxvalue} ${maxAngle}deg, ${this.bgcolorrangemaxvalue} ${(this.endangle - this.startangle)}deg, `;
            }
        }
    
        return `conic-gradient(from ${this.startangle-180}deg${startPosition}, ${beginning}${mainPart}${end}transparent)`;
    }

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

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

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

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