/*jslint single: true, long:true, for:true, unordered:true*/
/*global ScenesCommon*/

const DynamicScene = (function () {
    const GRADIENT_STEPS = 20;

    function getName() {
        return "Dynamic";
    }

    function getIdentifier() {
        return "com.corsair.cc.sc.dynamic";
    }

    function getParameters() {
        return [
            {
                name: "color_hint",
                title: "Define up to 6 colors for your scene.",
                type: "hint"
            },
            {
                name: "colors",
                title: "Colors",
                type: "color_list",
                min: 2,
                max: 6,
                default: ["#ff0000", "#ffff00", "#ffffff", "#00ff00", "#0000ff", "#000000"]
            },
            {
                name: "duration",
                title: "Duration",
                type: "int",
                unit: "ms",
                info: "Define how long each color is shown.",
                min: 0,
                max: 60000,
                default: 1000
            },
            {
                name: "transition_speed",
                title: "Transition Speed",
                type: "int_enum",
/*jslint-disable*/
                values: {0: "Instant", 100: "Fast", 1000: "Medium", 5000: "Slow", 10000: "Very Slow"},
/*jslint-enable*/
                default: 1000
            },
            {
                name: "transition_type",
                title: "Transition",
                type: "int_enum",
/*jslint-disable*/
                values: {0: "Crossfade", 1: "Breathing"},
/*jslint-enable*/
                default: 0
            }
        ];
    }

    function getIcon() {
        return `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="0 0 16 16">
        <path id="icon" fill="#d8d8d8" fill-rule="evenodd" d="M1.881,4.133c1.311,-2.076 3.524,-3.27 5.829,-3.365l0,2.029c-1.605,0.091 -3.139,0.922 -4.072,2.351l-1.757,-1.015Zm-0.289,7.232c-1.143,-2.172 -1.07,-4.686 0,-6.73l1.757,1.014c-0.723,1.436 -0.771,3.18 -0,4.702l-1.757,1.014Zm6.118,3.867c-2.452,-0.096 -4.593,-1.416 -5.828,-3.365l1.757,-1.015c0.882,1.345 2.368,2.258 4.071,2.351l0,2.029Zm6.409,-3.365c-1.311,2.076 -3.524,3.27 -5.829,3.365l-0,-2.029c1.605,-0.091 3.139,-0.922 4.072,-2.351l1.757,1.015Zm0.289,-7.232c1.143,2.172 1.07,4.686 -0,6.73l-1.757,-1.014c0.723,-1.436 0.771,-3.18 0,-4.702l1.757,-1.014Zm-6.118,-3.867c2.452,0.096 4.593,1.416 5.828,3.365l-1.757,1.015c-0.882,-1.345 -2.368,-2.258 -4.071,-2.351l-0,-2.029Z"/>
        </svg>`;
    }

    function setColorInDataSet(numLeds, sceneDataSet, color) {
        let i = 0;
        for (i = 0; i < numLeds; i += 1) {
            ScenesCommon.pushColor(sceneDataSet.rgbArray, color);
        }
    }

    function getSceneDataSet(color, numLeds, duration) {

        // Create scene data set
        let sceneDataSet = ScenesCommon.createSceneDataSet(numLeds, duration);
        let i = 0;

        // Set colors
        for (i = 0; i < numLeds; i += 1) {
            ScenesCommon.pushColor(sceneDataSet.rgbArray, color);
        }

        return sceneDataSet;
    }

    function generateBreathingScene(sceneData, colors, duration, transitionMs) {
        const fadingNumSteps = Math.floor(parseFloat(transitionMs) / parseFloat(GRADIENT_STEPS));

        let col = 0;
        let i = 0;
        let sceneDataSet;
        let fade = {};

        for (col = 0; col < colors.length; col += 1) {

            // Get color
            let color = {
                r: parseInt(colors[col].substr(1, 2), 16),
                g: parseInt(colors[col].substr(3, 2), 16),
                b: parseInt(colors[col].substr(5, 2), 16)
            };

            // Fade in
            for (i = 0; i < fadingNumSteps; i += 1) {
                fade.r = color.r * i / fadingNumSteps;
                fade.g = color.g * i / fadingNumSteps;
                fade.b = color.b * i / fadingNumSteps;
                sceneDataSet = getSceneDataSet(fade, sceneData.ledCount, GRADIENT_STEPS);
                sceneData.sceneDatas.push(sceneDataSet);
            }

            // On
            sceneDataSet = getSceneDataSet(color, sceneData.ledCount, duration);
            sceneData.sceneDatas.push(sceneDataSet);

            // Fade out
            for (i = 0; i < fadingNumSteps; i += 1) {
                fade.r = color.r - (color.r * i / fadingNumSteps);
                fade.g = color.g - (color.g * i / fadingNumSteps);
                fade.b = color.b - (color.b * i / fadingNumSteps);
                sceneDataSet = getSceneDataSet(fade, sceneData.ledCount, GRADIENT_STEPS);
                sceneData.sceneDatas.push(sceneDataSet);
            }
        }

        return sceneData;
    }

    function generateCrossfadeScene(sceneData, parameterColors, duration, transitionMs) {
        const transitionFrameLength = 100;

        let i = 0;
        let colors = [];
        let len = parameterColors.length;

        for (i = 0; i < len; i += 1) {
            colors.push(ScenesCommon.colorFromHexString(parameterColors[i]));
        }

        let transitionColorsLen = -1;
        if (transitionMs > transitionFrameLength) {
            transitionColorsLen = Math.floor(parseFloat(transitionMs) / parseFloat(transitionFrameLength));

            let allSetsCount = (transitionColorsLen * (colors.length + 1)) + colors.length;

            if (allSetsCount > ScenesCommon.MAX_SETS) {
                transitionColorsLen = Math.floor((ScenesCommon.MAX_SETS - colors.length) / (colors.length + 1));
            }
        }

        len = colors.length;
        for (i = 0; i < len; i += 1) {

            let sceneDataSet = ScenesCommon.createSceneDataSet(sceneData.ledCount, duration);
            setColorInDataSet(sceneData.ledCount, sceneDataSet, colors[i]);
            sceneData.sceneDatas.push(sceneDataSet);

            if (transitionColorsLen > 0) {
                let nextColorIndex = i + 1;
                if (nextColorIndex >= len) {
                    nextColorIndex = 0;
                }

                let j = 0;
                let transitionColors = ScenesCommon.gradientColors(colors[i], colors[nextColorIndex], transitionColorsLen);

                for (j = 0; j < transitionColorsLen; j += 1) {
                    let transitionDataSet = ScenesCommon.createSceneDataSet(sceneData.ledCount, Math.floor(parseFloat(transitionMs) / parseFloat(transitionColorsLen)));
                    setColorInDataSet(sceneData.ledCount, transitionDataSet, transitionColors[j]);
                    sceneData.sceneDatas.push(transitionDataSet);
                }
            }
        }

        return sceneData;
    }

    function generateScene(sceneID, sceneName, numLeds, parameters) {
        const config = getParameters();
        const parameterColors = ScenesCommon.valueOrDefaultFromParameters(parameters, config, "colors");
        const duration = ScenesCommon.valueOrDefaultFromParameters(parameters, config, "duration");
        let transitionMs = ScenesCommon.valueOrDefaultFromParameters(parameters, config, "transition_speed");
        const transitionType = ScenesCommon.valueOrDefaultFromParameters(parameters, config, "transition_type");

        // Create scene data
        let sceneData = ScenesCommon.createSceneData(sceneID, numLeds, sceneName);

        if (transitionType === 1) {
            // Breathing
            transitionMs = transitionMs / 10;
            return generateBreathingScene(sceneData, parameterColors, duration, transitionMs);
        } else {
            return generateCrossfadeScene(sceneData, parameterColors, duration, transitionMs);
        }
    }

    function parametersForAIColors(parameters, colors, dynamism) {
        const config = getParameters();
        const duration = ScenesCommon.valueOrDefaultFromParameters(parameters, config, "duration");
        const transitionMs = ScenesCommon.valueOrDefaultFromParameters(parameters, config, "transition_speed");
        const transitionType = ScenesCommon.valueOrDefaultFromParameters(parameters, config, "transition_type");

        let result = {
            "colors": [],
            "duration": duration,
            "transition_speed": transitionMs,
            "transition_type": transitionType
        };

        if (colors === null) {
            colors = ScenesCommon.generateAIColorFromParameters(parameters, config);
        } else {
            colors = ScenesCommon.alterArrayForMinMaxParameterName(colors, config, "colors");
        }

        colors.forEach(function (color) {
            result.colors.push(color.colorString);
            // result.color_weights.push(color.weight);
            // result.durations.push(parseFloat(color.weight) / 100.0 * parseFloat(duration));
        });

        if (dynamism !== null) {
            let dynamismFloat = parseFloat(dynamism);

            if (dynamismFloat < ScenesCommon.DYNAMISM_SLOW) { // Slow
                result.duration = 5000;
                result.transition_speed = 5000;
                result.transition_type = 0;
            } else if (dynamismFloat < ScenesCommon.DYNAMISM_MEDIUM) { // Medium
                result.duration = 3000;
                result.transition_speed = 1000;
                result.transition_type = 0;
            } else if (dynamismFloat < ScenesCommon.DYNAMISM_FAST) { // Fast
                result.duration = 1000;
                result.transition_speed = 100;
                result.transition_type = 0;
            } else { // Fast, too
                result.duration = 1000;
                result.transition_speed = 100;
                result.transition_type = 0;
            }
        }

        return result;
    }

    return {
        name: getName,
        identifier: getIdentifier,
        parameters: getParameters,
        generate_scene: generateScene,
        icon: getIcon,
        "parametersForAIColors": parametersForAIColors
    };
}());


function getName() {
    return DynamicScene.name();
}

function getIdentifier() {
    return DynamicScene.identifier();
}

function getParameters() {
    return DynamicScene.parameters();
}

function generateScene(sceneID, sceneName, numLeds, parameters) {
    return DynamicScene.generate_scene(sceneID, sceneName, numLeds, parameters);
}

function getIcon() {
    return DynamicScene.icon();
}

function parametersForAIColors(parameters, colors, dynamism) {
    return DynamicScene.parametersForAIColors(parameters, colors, dynamism);
}
