function set_chart() {

    let chartCounter = 0;

    $('.LimitlessLineChart').each(function() {

        chartCounter++;
        let elementChart = $(this);
        elementChart.attr('id', 'LimitlessLineChart' + chartCounter);

        init_chart(elementChart[0].id);

    });

}

// main function
function init_chart(chartId) {

    // Define element
    let lineChartElement = document.getElementById(chartId);

    if (lineChartElement) {

        let elementObject = $(lineChartElement);
        let numberOfCharts = elementObject.attr('charts') ?? 1;
        let multichart = (numberOfCharts > 1);

        let rawData = elementObject.attr('raw') ? JSON.parse(elementObject.attr('raw')) : null;

        console.log('raw', rawData);

        console.log(numberOfCharts);
        console.log(multichart);

        // adjust container height before initialising the chart.
        if (multichart) {
            let height = (numberOfCharts * 240); // (chart height = 160 | charts spacing = 80)
            lineChartElement.style.height = height + 'px';
            console.log('adjusted container height', height + 'px');
        }

        let lineChart = echarts.init(lineChartElement);

        lineChart.showLoading({
            text: 'LADE DATEN',
            maskColor: '#353f53',
            color: '#fff',
            textColor: '#fff',
            fontSize: 15
        });

        set_data(elementObject, multichart, numberOfCharts, rawData, function(options) {
            lineChart.hideLoading();
            lineChart.setOption(options);
            setResizeEvent(lineChartElement, lineChart);
        })
    }
}

function set_data(elementObject, multichart, numberOfCharts, rawData, callback) {

    setTimeout(function() {

        let options;
        const defaultColors = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#a1887f', '#ffb980', '#2ec7c9','#b6a2de','#5ab1ef', '#d87a80', '#ea7ccc'];

        if(rawData == null) {

            // variables (this will be set by user)
            let titles = JSON.parse(elementObject.attr('titles')) ?? [];
            let colors = JSON.parse(elementObject.attr('colors')) ?? defaultColors;

            let showPointValues = (elementObject.attr('point-values') == 'true' || elementObject.attr('point-values') == true); // default false
            let boundaryGap = (elementObject.attr('boundary-gap') == 'true' || elementObject.attr('boundary-gap') == true); // default true
            let inverted = (elementObject.attr('inverted') == 'true' || elementObject.attr('inverted') == true); // default false
            let showDataZoom = (elementObject.attr('data-zoom') == 'true' || elementObject.attr('data-zoom') == true); // default false
            let stacked = (elementObject.attr('stacked') == 'true' || elementObject.attr('stacked') == true); // default false
            let isArea = (elementObject.attr('is-area') == 'true' || elementObject.attr('is-area') == true); // default false

            let animationDuration = elementObject.attr('animation-duration') ?? 750;
            // ex '{value} users'  - https://echarts.apache.org/en/option.html#yAxis.axisLabel.formatter
            let yAxisLabelValueFormat = elementObject.attr('y-axis-label-value-format') ?? null;
            // min | max | average
            let markLine = elementObject.attr('mark-line') ?? null;
            let categories = JSON.parse(elementObject.attr('categories')) ?? null;

            let series = JSON.parse(elementObject.attr('series')) ?? null;
            let seriesNames = series && series.map(function(item){ return item.name });
            let seriesObject = setSeries(series, showPointValues, markLine, stacked, isArea);

            console.log('titles', titles);
            console.log('colors', colors);
            console.log('point-values', showPointValues);
            console.log('boundary-gap', boundaryGap);
            console.log('inverted', inverted);
            console.log('data-zoom', showDataZoom);
            console.log('stacked', stacked);
            console.log('is-area', isArea);
            console.log('animation-duration', animationDuration);
            console.log('y-axis-label-value-format', yAxisLabelValueFormat);
            console.log('mark-line', markLine);
            console.log('categories', categories);
            console.log('series', series);
            console.log('series names', seriesNames);
            console.log('series object', seriesObject);


            // Options
            options = {

                // Chart title
                title: setTitles(titles, numberOfCharts),

                // Define colors
                color: colors,

                // Global text styles
                textStyle: setGlobalTextStyle(),

                // Chart animation duration
                animationDuration: animationDuration,

                // Setup grid
                grid: setGrid(showDataZoom, numberOfCharts),

                // Add legend
                legend: setLegend(seriesNames, multichart),

                // Add tooltip
                tooltip: setTooltip(),

                // Horizontal axis
                xAxis: inverted ? setYAxis(yAxisLabelValueFormat, numberOfCharts) : setXAxis(categories, boundaryGap, numberOfCharts),

                // Vertical axis
                yAxis: inverted ? setXAxis(categories, boundaryGap, numberOfCharts) : setYAxis(yAxisLabelValueFormat, numberOfCharts),

                // Axis pointer
                axisPointer: setAxisPointer(multichart),

                // Add series
                series: seriesObject
            };

            if(showDataZoom == true) {
                options.dataZoom = setDataZoom(showDataZoom, multichart);
            }

        } else {
            options = rawData;
        }


        callback(options);

    }, 1000);

}

// sub functions
function setSeries(seriesData, showPointValues  = false, markLineDataType = null, stack = false, isArea = false) {

    // uses series options if available else use global options.
    let seriesArray = [];

    if(!seriesData || seriesData.length == 0) return [];

    for(let i = 0; i < seriesData.length; i++) {

        let series = {
            name: seriesData[i].name,
            type: seriesData[i].type ?? 'line',
            data: seriesData[i].data,
            stack: seriesData[i].stack ?? stack,
            smooth: true,
            symbol: 'circle',
            symbolSize: 7,
            label: {
                normal: {
                    show: seriesData[i].showPointValues ?? showPointValues
                }
            },
            itemStyle: {
                normal: {
                    borderWidth: 2
                }
            },
            xAxisIndex: seriesData[i].index ?? 0,
            yAxisIndex: seriesData[i].index ?? 0
        }

        if(seriesData[i].markline != undefined && ['min', 'max', 'average'].includes(markLineDataType)) {

            series.markLine = {
                data: [{
                    type: seriesData[i].markline,
                    name: seriesData[i].markline[0].toUpperCase() + seriesData[i].markline.substring(1),
                }]
            };

        } else if(markLineDataType != null && ['min', 'max', 'average'].includes(markLineDataType)) {

            series.markLine = {
                data: [{
                    type: markLineDataType,
                    name: markLineDataType[0].toUpperCase() + markLineDataType.substring(1),
                }]
            };

        }

        let area = seriesData[i].isArea ?? isArea;

        if(area == true) {
            series.areaStyle = {};
        }

        seriesArray.push(series);

    }

    return seriesArray;
}

function setXAxis(categories, boundaryGap = true, numberOfCharts = 1) {

    let xAxisArray = [];
    for (let i = 0; i < numberOfCharts; i++) {

        let x = {
            type: 'category',
            boundaryGap: boundaryGap,
            axisLabel: {
                color: '#fff'
            },
            axisLine: {
                lineStyle: {
                    color: 'rgba(255,255,255,0.25)'
                }
            },
            splitLine: {
                lineStyle: {
                    color: 'rgba(255,255,255,0.1)'
                }
            },
            gridIndex: i
        };

        if(categories != null) {
            x.data = categories;
        }

        xAxisArray.push(x);
    }

    console.log('xaxisarray', xAxisArray);

    return xAxisArray;
}

function setYAxis(yAxisLabelValueFormat,  numberOfCharts = 1) {

    let yAxisArray = [];
    for (let i = 0; i < numberOfCharts; i++) {

        let y = {
            type: 'value',
            axisLabel: {
                formatter: yAxisLabelValueFormat,
                color: '#fff'
            },
            axisLine: {
                lineStyle: {
                    color: 'rgba(255,255,255,0.25)'
                }
            },
            splitLine: {
                lineStyle: {
                    color: 'rgba(255,255,255,0.1)'
                }
            },
            splitArea: {
                show: true,
                areaStyle: {
                    color: ['rgba(255,255,255,0.01)', 'rgba(0,0,0,0.01)']
                }
            },
            gridIndex: i
        };

        yAxisArray.push(y);
    }

    return yAxisArray;
}

// disabled when multichart is true
function setLegend(legendData, multichart = false) {
    return multichart ? null : {
        data: legendData,
        itemHeight: 8,
        itemGap: 20,
        textStyle: {
            color: '#fff'
        }
    }
}

function setTitles(titles, numberOfCharts = 1) {

    // if not array.
    if(!Array.isArray(titles)) {
        let temp = titles;
        titles = [];
        titles.push(temp);
    }

    let arrayTitles = [];

    for(i = 0; i < numberOfCharts; i++) {

        let title = {
            text: titles[i],
        };

        // if single else multichart
        if(i == 0 && numberOfCharts == 1) {
            title.textStyle = {
                color: '#fff'
            };
        } else {
            title.textStyle = {
                fontSize: 15,
                fontWeight: 500,
                color: '#fff'
            };
            title.left = 'center';
            title.top = 240 * i; //  (chart height = 160 | charts spacing = 80) * index
        }

        arrayTitles.push(title);
    }

    console.log('titles', arrayTitles);

    return arrayTitles;
}

// disabled when multichart is true
function setDataZoom(show, multichart = false) {
    return multichart ? null : [
        {
            type: 'inside',
            start: 30,
            end: 70
        },
        {
            show: show,
            type: 'slider',
            start: 30,
            end: 70,
            height: 40,
            bottom: 0,
            borderColor: 'rgba(255,255,255,0.1)',
            fillerColor: 'rgba(0,0,0,0.1)',
            handleStyle: {
                color: '#585f63'
            },
            textStyle: {
                color: '#fff'
            },
            handleStyle: {
                color: '#8893a9'
            },
            dataBackground: {
                areaStyle: {
                    color: 'rgba(0,0,0,0.5)'
                }
            }
        }
    ]
}

function setTooltip() {
    return {
        trigger: 'axis',
        backgroundColor: 'rgba(255,255,255,0.9)',
        padding: [10, 15],
        textStyle: {
            color: '#222',
            fontSize: 13,
            fontFamily: 'Roboto, sans-serif'
        }
    }
}

function setGrid(showDataZoom = false, numberOfCharts = 1) {

    let arrayGrids = [];
    for (let i = 0; i < numberOfCharts; i++) {

        let grid = {
            left: 0,
            containLabel: true
        };

        // if single else multichart
        if(i == 0 && numberOfCharts == 1) {
            grid.right = 40;
            grid.top = 50;
            grid.bottom = showDataZoom ? 60 : 0;
        } else {
            grid.right = 20;
            grid.top = (i == 0) ? 40 : (arrayGrids[i-1].top + 240); // previous top + chart height = 160 + charts spacing = 80
            grid.height = 160;
        }

        arrayGrids.push(grid);
    }

    console.log('grids', arrayGrids);

    return arrayGrids;
}

function setGlobalTextStyle() {
    return {
        fontFamily: 'Roboto, Arial, Verdana, sans-serif',
        fontSize: 13
    };
}

function setAxisPointer(multichart = false) {
    let pointer =  {
        lineStyle: {
            color: 'rgba(255,255,255,0.25)'
        }
    };

    if(multichart) {
        pointer.link = {
            xAxisIndex: 'all'
        };
    }

    return pointer;
}

function setResizeEvent(lineChartElement, lineChart) {
    // Resize function
    let triggerChartResize = function() {
        lineChartElement && lineChart.resize();
    };

    // On sidebar width change
    let sidebarToggle = document.querySelector('.sidebar-control');
    sidebarToggle && sidebarToggle.addEventListener('click', triggerChartResize);

    // On window resize
    let resizeCharts;
    window.addEventListener('resize', function() {
        clearTimeout(resizeCharts);
        resizeCharts = setTimeout(function () {
            triggerChartResize();
        }, 200);
    });
}


$(document).ready(function() {

    if (typeof echarts == 'undefined') {
        console.warn('Warning - echarts.min.js is not loaded.');
        return;
    }

    set_chart();
});