var DmxLightManager = function(lightCount) {
    this.sock = new Socket();
    this.lightCount = 0;
    this.headerSize = 10;
    this.sock.setType(SocketType.UDP);
    this.mockColor = void null;

    this.dataPacket = void null;
}

DmxLightManager.prototype.deinit = function() {
    this.sock.closeConnection();
    this.sock.delete();
}

DmxLightManager.prototype.isInitialized = function() {
    return this.lightCount > 0;
}

DmxLightManager.prototype.init = function(lightCount) {
    if (!this.sock.establishConnection()) {
        loggerWarning("could not connect to DMX lights!");
    }

    this.lightCount = lightCount;

    // Protocol: https://github.com/Instanssi/effectserver
    this.dataPacket = new Uint8Array(this.headerSize + 6 * this.lightCount);
    this.dataPacket[ 0] = 1; // spec version
    this.dataPacket[ 1] = 0; // nick tag start
    this.dataPacket[ 2] = 'J'.charCodeAt(0);
    this.dataPacket[ 3] = 'M'.charCodeAt(0);
    this.dataPacket[ 4] = 'L'.charCodeAt(0);
    this.dataPacket[ 5] = '2'.charCodeAt(0);
    this.dataPacket[ 6] = '0'.charCodeAt(0);
    this.dataPacket[ 7] = '2'.charCodeAt(0);
    this.dataPacket[ 8] = '4'.charCodeAt(0);
    this.dataPacket[ 9] = 0;  // nick tag end

    for (var i = 0; i < this.lightCount; i++) {
        var light = this.headerSize + 6 * i;
        this.dataPacket[light + 0] = 1; // type = light
        this.dataPacket[light + 1] = i; // light id
        this.dataPacket[light + 2] = 0; // light type (0 = RGB)
        this.dataPacket[light + 3] = 0x00; // Red
        this.dataPacket[light + 4] = 0x00; // Green
        this.dataPacket[light + 5] = 0x00; // Blue
    }

    // just ensure that there will be black in the begin
    for(var i = 0; i < 3; i++) {
        this.setColor(0x00, 0x00, 0x00, 0, this.lightCount);
        this.sendData();
    }
}

DmxLightManager.prototype.setColor = function(r,g,b,lightIdStart,lightIdEnd,clearColor) {
    if (lightIdStart === void null) {
        lightIdStart = 0;
    }
    if (lightIdEnd === void null) {
        lightIdEnd = this.lightCount;
    } else if (lightIdEnd > this.lightCount) {
        lightIdEnd = this.lightCount;
    }

    for (var i = 0; i < this.lightCount; i++) {
        var light = this.headerSize + 6 * i;
        if (i >= lightIdStart && i < lightIdEnd) {
            this.dataPacket[light + 3] = r; // Red
            this.dataPacket[light + 4] = g; // Green
            this.dataPacket[light + 5] = b; // Blue
        }
        
        if (clearColor) {
            this.dataPacket[light + 3] = clearColor[0]; // Red
            this.dataPacket[light + 4] = clearColor[1]; // Green
            this.dataPacket[light + 5] = clearColor[2]; // Blue
        }
    }
}

DmxLightManager.prototype.sendMockColorData = function() {
    this.mockColor = [];
    for (var i = 0; i < this.lightCount; i++) {
        var light = this.headerSize + 6 * i;
        var r = this.dataPacket[light + 3] / 255.0;
        var g = this.dataPacket[light + 4] / 255.0;
        var b = this.dataPacket[light + 5] / 255.0;
        this.mockColor.push([r, g, b]);
    }
}

DmxLightManager.prototype.sendData = function() {
    //loggerWarning("PRKL! " + JSON.stringify(this.dataPacket,null,2));
    // NOTE: Sending all light data every time (mitigating possible UDP issues, like missing packets)
    
    if (!this.sock.sendData(this.dataPacket)) {
        // small retry mechanism
        loggerWarning("Data send failed, retrying once");
        this.sock.closeConnection();
        if (this.sock.establishConnection()) {
            if (!this.sock.sendData(this.dataPacket)) {
                loggerError("Data send failed");
            }
        }
    }

    this.sendMockColorData();
}

// actual DMX host: valot.instanssi (used to be valot.party at some point)
var dmxLightManagerSettings = {
    //"host": "127.0.0.1",
    "host": "valot.instanssi",
    "port": "9909",
    "count": "24"
}
var dmxLightManager = void null;

var Menu = function() {
    this.input = new Input();

    this.dmxLights = {"v":true};
    this.dmxHost = {"v":dmxLightManagerSettings.host, "size":128};
    this.dmxPort = {"v":dmxLightManagerSettings.port, "size":5};
    this.dmxLightCount = {"v":dmxLightManagerSettings.count, "size":3};
7
    this.mute = {"v":Settings.audio.mute};
    this.fullscreen = {"v":Settings.window.fullscreen};
    this.displayModeSelect = void null;

    this.displayModes = getDisplayModes();

    this.displayModeList = "";
    for (var i = 0; i < this.displayModes.length; i++) {
        var dm = this.displayModes[i];
        if (!dm) {
            continue;
        }

        this.displayModeList += dm.width + "x" + dm.height + "\0";

        if (dm.width == Settings.demo.graphics.canvasWidth && dm.height == Settings.demo.graphics.canvasHeight) {
            this.displayModeSelect = {"v": i};
        }
    }
    this.displayModeList += "\0";

    if (this.displayModeSelect === void null) {
        this.displayModeSelect = {"v": 0};
    }

    this.audioDevices = getAudioDevices();

    this.audioDeviceList = "";
    for (var i = 0; i < this.audioDevices.length; i++) {
        var audioDevice = this.audioDevices[i];
        if (!audioDevice) {
            continue;
        }

        this.audioDeviceList += audioDevice + "\0";
    }
    this.audioDeviceList += "\0";
    this.audioDeviceSelect = {"v": 0};
}
Menu.prototype.setQuit = function(quit) {
    menuSetQuit(quit);
}
Menu.prototype.getWidth = function() {
    return menuGetWidth();
}
Menu.prototype.getHeight = function() {
    return menuGetHeight();
}
Menu.prototype.render = function() {
    ImGui.SetNextWindowPos({"x":0, "y":0}, ImGui.Cond.Always);
    ImGui.SetNextWindowSize({"x":this.getWidth(), "y":this.getHeight()}, ImGui.Cond.Always);

    ImGui.PushStyleVar(ImGui.StyleVar.WindowRounding, 0);
    ImGui.Begin("menu", {"v":true},
      ImGui.WindowFlags.NoSavedSettings
      | ImGui.WindowFlags.NoTitleBar
      | ImGui.WindowFlags.NoResize
      | ImGui.WindowFlags.NoMove
      | ImGui.WindowFlags.NoCollapse);
    var flags = ImGui.WindowFlags.NoResize;

    ImGui.SetWindowFontScale(3.0);

    ImGui.Combo("display mode", this.displayModeSelect, this.displayModeList);

    ImGui.Combo("audio device", this.audioDeviceSelect, this.audioDeviceList);

    ImGui.Checkbox("fullscreen", this.fullscreen);
    ImGui.SameLine();
    ImGui.Checkbox("mute", this.mute);

    ImGui.InputText("DMX host", this.dmxHost);
    ImGui.InputText("DMX port", this.dmxPort);
    ImGui.InputText("DMX lights", this.dmxLightCount);
    ImGui.Checkbox("DMX Lights", this.dmxLights);
    ImGui.SameLine();
    if (ImGui.Button("Test DMX")) {
        var dmxLightManagerTest = new DmxLightManager();
        dmxLightManagerTest.sock.setHost(this.dmxHost.v);
        dmxLightManagerTest.sock.setPort(parseInt(this.dmxPort.v));
        dmxLightManagerTest.init(parseInt(this.dmxLightCount.v));
        var iterStep = 5;
        for (var i = 0; i < dmxLightManagerTest.lightCount; i += iterStep) {
            var r = Math.floor(Math.random() * (0xFF + 1));
            var g = Math.floor(Math.random() * (0xFF + 1));
            var b = Math.floor(Math.random() * (0xFF + 1));
            dmxLightManagerTest.setColor(r,g,b, i, i + iterStep);
            dmxLightManagerTest.sendData();
        }
        dmxLightManagerTest.deinit();
    }

    if (ImGui.Button("Start") || ImGui.IsKeyPressed(ImGui.GetKeyIndex(ImGui.Key.Enter), true)) {
        dmxLightManager = new DmxLightManager();
        if (this.dmxLights.v) {
            dmxLightManager.sock.setHost(this.dmxHost.v);
            dmxLightManager.sock.setPort(parseInt(this.dmxPort.v));
            dmxLightManager.init(parseInt(this.dmxLightCount.v));
        }

        var displayMode = this.displayModes[this.displayModeSelect.v];

        Settings.audio.mute = this.mute.v;
        Settings.audio.device = this.audioDevices[this.audioDeviceSelect.v];
        Settings.window.fullscreen = this.fullscreen.v;

        var userOptions = {
            "displayMode": displayMode,
            "mute": Settings.audio.mute,
            "device": Settings.audio.device,
            "fullscreen": Settings.window.fullscreen
        };
        loggerInfo("User menu options: " + JSON.stringify(userOptions, null, 2));

        // Send Settings modified in JS to backend
        settingsLoadSettingsFromString(JSON.stringify(Settings, null, 2));
        settingsDemoLoadDemoSettingsFromString(JSON.stringify(Settings.demo, null, 2));

        settingsWindowSetWindowDimensions(displayMode.width, displayMode.height);

        this.setQuit(false); // i.e. let's continue and show the demo
        this.input.setUserExit(true);
    }
    ImGui.SameLine();
    if (ImGui.Button("Exit") || ImGui.IsKeyPressed(ImGui.GetKeyIndex(ImGui.Key.Escape), true)) {
        this.input.setUserExit(true);
    }

    ImGui.End();
    ImGui.PopStyleVar();

    ImGui.Render();
}
