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

const FusionScene = (function () {
    const COLORS = [
        {
            left: {r: 255, g: 0, b: 0}, // red
            right: {r: 255, g: 165, b: 0} // orange
        },
        {
            left: {r: 255, g: 255, b: 0}, // yellow
            right: {r: 0, g: 128, b: 0} // green
        },
        {
            left: {r: 0, g: 0, b: 255}, // blue
            right: {r: 75, g: 0, b: 130} // indigo
        }
    ];
    const GRADIENT_STEPS = 20;

    function getName() {
        return "Fusion";
    }

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

    function getParameters() {
        return [
            {
                name: "color_hint",
                title: "This scene uses pre-defined colors.",
                type: "hint"
            },
            {
                name: "speed",
                title: "Speed",
                type: "int_enum",
/*jslint-disable*/
                values: {300: "Very Slow", 100: "Slow", 50: "Medium", 10: "Fast"},
/*jslint-enable*/
                default: 50
            }
        ];
    }

    function previousColorAt(previousLEDColors, led) {
        if (led < previousLEDColors.length) {
            return previousLEDColors[led];
        }

        return ScenesCommon.BLACK_COLOR;
    }

    function pushColorAndPreviousColor(arr, color, previousLEDColors, led) {
        ScenesCommon.pushColor(arr, color);
        previousLEDColors[led] = color;
    }

    function addStrikeColorsToDataSet(sceneData, speed, left, right, previousLEDColors, numLeds) {
        const middle = Math.round(parseFloat(numLeds) / 2.0);

        const middleColor = {
            r: Math.round(right.r * 0.5 + 0.5 * left.r),
            g: Math.round(right.g * 0.5 + 0.5 * left.g),
            b: Math.round(right.b * 0.5 + 0.5 * left.b)
        };

        const leftGradient = ScenesCommon.gradientColors(middleColor, right, GRADIENT_STEPS);
        const rightGradient = ScenesCommon.gradientColors(middleColor, left, GRADIENT_STEPS);
        let frame = 0;

        for (frame = 0; frame < numLeds; frame += 1) {
            let sceneDataSet = ScenesCommon.createSceneDataSet(numLeds, speed);
            let led = 0;

            for (led = 0; led < numLeds; led += 1) {
                if (frame <= middle) {
                    if (led < frame) {
                        pushColorAndPreviousColor(sceneDataSet.rgbArray, left, previousLEDColors, led);
                    } else if (led > numLeds - frame) {
                        pushColorAndPreviousColor(sceneDataSet.rgbArray, right, previousLEDColors, led);
                    } else {
                        pushColorAndPreviousColor(sceneDataSet.rgbArray, previousColorAt(previousLEDColors, led), previousLEDColors, led);
                    }
                } else {
                    let reverseFrame = numLeds - frame;
                    if (led < reverseFrame - 1) {
                        pushColorAndPreviousColor(sceneDataSet.rgbArray, previousColorAt(previousLEDColors, led), previousLEDColors, led);
                    } else if (led <= middle - GRADIENT_STEPS) {
                        pushColorAndPreviousColor(sceneDataSet.rgbArray, right, previousLEDColors, led);
                    } else if (led < middle) {
                        pushColorAndPreviousColor(sceneDataSet.rgbArray, leftGradient[middle - led], previousLEDColors, led);
                    } else if (led <= frame) {
                        if (led < middle + GRADIENT_STEPS) {
                            pushColorAndPreviousColor(sceneDataSet.rgbArray, rightGradient[led - middle], previousLEDColors, led);
                        } else {
                            pushColorAndPreviousColor(sceneDataSet.rgbArray, left, previousLEDColors, led);
                        }
                    } else {
                        pushColorAndPreviousColor(sceneDataSet.rgbArray, previousColorAt(previousLEDColors, led), previousLEDColors, led);
                    }
                }
            }

            sceneData.sceneDatas.push(sceneDataSet);
        }
    }

    function addClearAnimationToDataSet(sceneData, speed, previousLEDColors, numLeds) {
        let middle = Math.round(parseFloat(numLeds) / 2.0);
        let frame = 0;

        for (frame = 0; frame < middle; frame += 1) {
            let sceneDataSet = ScenesCommon.createSceneDataSet(numLeds, speed);
            let led = 0;

            for (led = 0; led < numLeds; led += 1) {
                if ((led < middle - frame) || (led > middle + frame)) {
                    pushColorAndPreviousColor(sceneDataSet.rgbArray, previousColorAt(previousLEDColors, led), previousLEDColors, led);
                } else {
                    pushColorAndPreviousColor(sceneDataSet.rgbArray, ScenesCommon.BLACK_COLOR, previousLEDColors, led);
                }
            }

            sceneData.sceneDatas.push(sceneDataSet);
        }
    }

    function generateScene(sceneID, sceneName, numLeds, parameters) {
        const config = getParameters();
        const speed = ScenesCommon.valueOrDefaultFromParameters(parameters, config, 'speed');
        let sceneData = ScenesCommon.createSceneData(sceneID, numLeds, sceneName);
        const previousLEDColors = [];

        COLORS.forEach(function (color) {
            addStrikeColorsToDataSet(sceneData, speed, color.left, color.right, previousLEDColors, numLeds);
        });

        addClearAnimationToDataSet(sceneData, speed, previousLEDColors, numLeds);

        // ????: are 420 sets allowed?
        return sceneData;
    }

    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="M3.523,4.979c-0.265,-0.319 -0.22,-0.792 0.099,-1.056c0.318,-0.265 0.791,-0.22 1.056,0.098l2.9,3.5c0.23,0.278 0.23,0.68 0,0.958l-2.9,3.5c-0.265,0.318 -0.738,0.363 -1.056,0.098c-0.319,-0.264 -0.364,-0.737 -0.099,-1.056l2.504,-3.021l-2.504,-3.021Zm-1.909,1.59c-0.176,-0.212 -0.146,-0.528 0.066,-0.704c0.213,-0.176 0.528,-0.147 0.704,0.066l1.451,1.75c0.153,0.185 0.153,0.453 -0,0.638l-1.451,1.75c-0.176,0.213 -0.491,0.242 -0.704,0.066c-0.212,-0.176 -0.242,-0.492 -0.066,-0.704c0,-0 1.186,-1.431 1.186,-1.431l-1.186,-1.431Zm9.708,-2.548c0.265,-0.318 0.738,-0.363 1.056,-0.098c0.319,0.264 0.364,0.737 0.099,1.056l-2.504,3.021l2.504,3.021c0.265,0.319 0.22,0.792 -0.099,1.056c-0.318,0.265 -0.791,0.22 -1.056,-0.098l-2.9,-3.5c-0.23,-0.278 -0.23,-0.68 -0,-0.958l2.9,-3.5Zm2.294,1.91c0.176,-0.213 0.491,-0.242 0.704,-0.066c0.212,0.176 0.242,0.492 0.066,0.704c-0,0 -1.186,1.431 -1.186,1.431l1.186,1.431c0.176,0.212 0.146,0.528 -0.066,0.704c-0.213,0.176 -0.528,0.147 -0.704,-0.066l-1.451,-1.75c-0.153,-0.185 -0.153,-0.453 0,-0.638l1.451,-1.75Z"/>
</svg>`;
    }

    function getColors() {
        let colors = [];
        COLORS.forEach(function (color) {
            colors.push(color.left);
            colors.push(color.right);
        });
        return ScenesCommon.hexColors(colors);
    }

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


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

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

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

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

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

function getColors() {
    return FusionScene.colors();
}
