// True numeric value binding
ko.bindingHandlers.numericValue = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var underlyingObservable = valueAccessor();
        var interceptor = ko.dependentObservable({
            read: underlyingObservable,
            write: function (value) {
                if (!isNaN(value)) {
                    underlyingObservable(parseFloat(value));
                }
            }
        });
        ko.bindingHandlers.value.init(element, function () {
            return interceptor
        }, allBindingsAccessor, viewModel, bindingContext);
    },
    update: ko.bindingHandlers.value.update
};

var editor = ace.edit("config-editor");
editor.setTheme("ace/theme/monokai");
editor.session.setMode("ace/mode/json");

var parser;

$.get('js/atlas.pegjs', function (data) {
    parser = PEG.buildParser(data);
});

var viewmodel = ko.mapping.fromJS({
    // Server Argument Section
    "BaseServerArgs": "",
    "AdditionalCmdLineParams": "",

    // World Options
    "WorldFriendlyName": "New Server",
    "WorldAtlasId": "",
    "WorldAtlasPassword": "",
    "ModIDs": "",

    // Grid Options
    "gridSize": 1000,
    "totalGridsX": 1,
    "totalGridsY": 1,
    "coordsScaling": 0.000000000001,
    "globalTransitionMinZ": 0.0,

    // Image Paths
    "backgroundImgPath": "image.png",
    "discoZonesImagePath": "image.png",

    // URL Options
    "MetaWorldURL": "",
    "AuthListURL": "",
    "MapImageURL": "",

    // Time Options
    "Day0": "2019-01-09 20:28:56",
    "bUseUTCTime": false,
    "columnUTCOffset": 0.0,
    "lastImageOverride": "0001-01-01T00:00:00",

    // Info Options
    "showServerInfo": false,
    "showDiscoZoneInfo": false,
    "showShipPathsInfo": false,
    "showIslandNames": false,
    "showLines": false,
    "showBackground": false,

    // S3 Options
    "LocalS3URL": "",
    "LocalS3AccessKeyId": "",
    "LocalS3SecretKey": "",
    "LocalS3BucketName": "",
    "LocalS3Region": "",

    // Unsorted...
    "globalGameplaySetup": "",
    "shipPathsIdGenerator": 1,
    "idGenerator": 127,
    "regionsIdGenerator": 0,

    // Tribe Log Tab
    "TribeLogConfig": {
        // Main Options
        "MaxRedisEntries": 1000,
        "BackupMode": "off",
        "MaxFileHistory": 10,
        "HttpBackupURL": "",
        "HttpAPIKey": "",

        //S3 Options
        "S3URL": "",
        "S3AccessKeyId": "",
        "S3SecretKey": "",
        "S3BucketName": "",
        "S3KeyPrefix": ""
    },

    // Travel Data Tab
    "TravelDataConfig": {
        // Main Options
        "BackupMode": "off",
        "MaxFileHistory": 10,
        "HttpBackupURL": "",
        "HttpAPIKey": "",

        //S3 Options
        "S3URL": "",
        "S3AccessKeyId": "",
        "S3SecretKey": "",
        "S3BucketName": "",
        "S3KeyPrefix": ""
    },

    // Shared Log Tab
    "SharedLogConfig": {
        // Main Options
        "FetchRateSec": 60,
        "SnapshotCleanupSec": 900,
        "SnapshotRateSec": 1800,
        "SnapshotExpirationHours": 48,
        "BackupMode": "off",
        "MaxFileHistory": 10,
        "HttpBackupURL": "",
        "HttpAPIKey": "",

        //S3 Options
        "S3URL": "",
        "S3AccessKeyId": "",
        "S3SecretKey": "",
        "S3BucketName": "",
        "S3KeyPrefix": ""
    },

    // Databases Tab
    "DatabaseConnections": [
        {
            "Name": "Default",
            "URL": "127.0.0.1",
            "Port": 6390,
            "Password": ""
        },
        {
            "Name": "TribeDB",
            "URL": "127.0.0.1",
            "Port": 6390,
            "Password": ""
        },
        {
            "Name": "TravelDataDB",
            "URL": "127.0.0.1",
            "Port": 6390,
            "Password": ""
        },
        {
            "Name": "TerritoryDB",
            "URL": "127.0.0.1",
            "Port": 6390,
            "Password": ""
        },
        {
            "Name": "LogDB",
            "URL": "127.0.0.1",
            "Port": 6390,
            "Password": ""
        }
    ],

    // Servers Tab
    "servers": [],
    "spawnerOverrideTemplates": [],
    "shipPaths": [],
    "serverTemplates": [],

    // ?!?!
    "OverrideShooterGameModeDefaultGameIni": {}
});
ko.applyBindings(viewmodel);

configToEditor();

function editorToConfig() {
    ko.mapping.fromJSON(editor.getValue(), viewmodel);
}

function configToEditor() {
    var interim = ko.mapping.toJS(viewmodel);
    // coordsScaling may need special care?
    //interim.coordsScaling = Number(interim.coordsScaling).toFixed(12);
    editor.setValue(ko.toJSON(interim, null, 2));
}

function addDatabase() {
    var newDB = {
        "Name": ko.observable("NewDB"),
        "URL": ko.observable("127.0.0.1"),
        "Port": ko.observable(6390),
        "Password": ko.observable("")
    };
    viewmodel.DatabaseConnections.push(newDB);
}

function removeDatabase(obj) {
    viewmodel.DatabaseConnections.remove(obj);
}

function addServer() {
    var newServer = {
        // Basic Data
        "name": ko.observable("Server Name"),
        "serverTemplateName": ko.observable("Template Name"),
        "ip": ko.observable("127.0.0.1"),
        "port": ko.observable(29145),
        "gamePort": ko.observable(3045),
        "seamlessDataPort": ko.observable(31029),
        "gridX": ko.observable(0),
        "gridY": ko.observable(0),
        "MachineIdTag": ko.observable(""),
        "isHomeServer": ko.observable(false),
        "AdditionalCmdLineParams": ko.observable(""),

        // Biome Options
        "GlobalBiomeSeamlessServerGridPreOffsetValues": ko.observable(""),
        "GlobalBiomeSeamlessServerGridPreOffsetValuesOceanWater": ko.observable(""),

        // Override Options
        "OceanDinoDepthEntriesOverride": ko.observable(""),
        "OceanEpicSpawnEntriesOverrideValues": ko.observable(""),
        "oceanFloatsamCratesOverride": ko.observable(""),
        "treasureMapLootTablesOverride": ko.observable(""),
        "oceanEpicSpawnEntriesOverrideTemplateName": ko.observable(""),
        "NPCShipSpawnEntriesOverrideTemplateName": ko.observable(""),
        "regionOverrides": ko.observable(""),

        // Style Options
        "waterColorR": ko.observable(0.0),
        "waterColorG": ko.observable(0.0),
        "waterColorB": ko.observable(0.0),
        "skyStyleIndex": ko.observable(0),

        // Misc Options
        "floorZDist": ko.observable(0),
        "utcOffset": ko.observable(0),
        "transitionMinZ": ko.observable(0),
        "serverIslandPointsMultiplier": ko.observable(1.0),

        // Date Options
        "lastModified": ko.observable("2019-04-14T21:32:04.7310108Z"),
        "lastImageOverride": ko.observable("0001-01-01T00:00:00"),

        // Boolean Options
        "islandLocked": ko.observable(true),
        "discoLocked": ko.observable(true),
        "pathsLocked": ko.observable(false),

        // Tabled Options
        "sublevels": ko.observableArray([]),
        "extraSublevels": ko.observableArray([]),
        "totalExtraSublevels": ko.observableArray([]),
        "islandInstances": ko.observableArray([]),
        "discoZones": ko.observableArray([]),
        "spawnRegions": ko.observableArray([]),

        // ???
        "OverrideShooterGameModeDefaultGameIni": ko.observable({})
    };
    viewmodel.servers.push(newServer);
}

function removeServer(obj) {
    viewmodel.servers.remove(obj);
}

var deparseEditor = ace.edit("deparse-editor");
deparseEditor.setTheme("ace/theme/monokai");
deparseEditor.session.setMode("ace/mode/json");

var activeDeparseEdit;

function deparseEdit(data) {
    activeDeparseEdit = data.value;
    $('#deparse-modal').on('hide.bs.modal', function () {
        cancelDeparseEdit();
    });
    $('#deparse-modal').modal('show');
    var parsed = parser.parse(activeDeparseEdit());
    deparseEditor.setValue(ko.toJSON(parsed, null, 2));
}

function cancelDeparseEdit() {
    activeDeparseEdit = undefined;
    $('#deparse-modal').off('hide.bs.modal');
    $('#deparse-modal').modal('hide');
}

function saveDeparseEdit() {
    $('#deparse-modal').off('hide.bs.modal');
    $('#deparse-modal').modal('hide');
    var parsed = JSON.parse(deparseEditor.getValue());
    activeDeparseEdit(deparseJson(parsed));
    activeDeparseEdit = undefined;
}

var rawEditor = ace.edit("raw-editor");
rawEditor.setTheme("ace/theme/monokai");
rawEditor.session.setMode("ace/mode/json");

var activeRawEdit;

function rawEdit(data) {
    activeRawEdit = data;
    $('#raw-modal').on('hide.bs.modal', function () {
        cancelRawEdit();
    });
    $('#raw-modal').modal('show');
    rawEditor.setValue(ko.toJSON(ko.mapping.toJS(activeRawEdit), null, 2));
}

function cancelRawEdit() {
    activeDeparseEdit = undefined;
    $('#raw-modal').off('hide.bs.modal');
    $('#raw-modal').modal('hide');
}

function saveRawEdit() {
    $('#raw-modal').off('hide.bs.modal');
    $('#raw-modal').modal('hide');
    ko.mapping.fromJSON(rawEditor.getValue(), {}, activeRawEdit);
    activeRawEdit = undefined;
}

function addServerSubLevel(obj) {
    var newSubLevel = {
        "id": ko.observable(0),
        "name": ko.observable("Map_Name"),
        "additionalTranslationX": ko.observable(0),
        "additionalTranslationY": ko.observable(0),
        "additionalTranslationZ": ko.observable(0),
        "additionalRotationPitch": ko.observable(0),
        "additionalRotationYaw": ko.observable(0),
        "additionalRotationRoll": ko.observable(0),
        "landscapeMaterialOverride": ko.observable(-1)
    };
    obj.sublevels.push(newSubLevel);
}

function removeServerSubLevel(obj, e) {
    ko.contextFor(e.target).$parent.sublevels.remove(obj);
}

function addServerIslandInstance(obj) {
    var newIslandInstance = {
        "id": ko.observable(0),
        "name": ko.observable("Island_Name"),
        "spawnerOverrides": ko.observable({}),
        "minTreasureQuality": ko.observable(-1.0),
        "maxTreasureQuality": ko.observable(-1.0),
        "useNpcVolumesForTreasures": ko.observable(false),
        "useLevelBoundsForTreasures": ko.observable(true),
        "prioritizeVolumesForTreasures": ko.observable(false),
        "islandPoints": ko.observable(-1),
        "islandTreasureBottleSupplyCrateOverrides": ko.observable(""),
        "islandWidth": ko.observable(0),
        "islandHeight": ko.observable(0),
        "worldX": ko.observable(0),
        "worldY": ko.observable(0),
        "rotation": ko.observable(0)
    };
    obj.islandInstances.push(newIslandInstance);
}

function removeServerIslandInstance(obj, e) {
    ko.contextFor(e.target).$parent.islandInstances.remove(obj);
}

function addServerDiscoveryZone(obj) {
    var newDiscoveryZone = {
        "id": ko.observable(0),
        "name": ko.observable("New Discovery Zone"),
        "sizeX": ko.observable(0),
        "sizeY": ko.observable(0),
        "sizeZ": ko.observable(0),
        "xp": ko.observable(0),
        "bIsManuallyPlaced": ko.observable(false),
        "explorerNoteIndex": ko.observable(0),
        "allowSea": ko.observable(false),
        "worldX": ko.observable(0),
        "worldY": ko.observable(0),
        "rotation": ko.observable(0)
    };
    obj.discoZones.push(newDiscoveryZone);
}

function removeServerDiscoveryZone(obj, e) {
    ko.contextFor(e.target).$parent.discoZones.remove(obj);
}

function addServerSpawnRegion(obj) {
    var newServerSpawnRegion = {
        "name": ko.observable("")
    };
    obj.spawnRegions.push(newServerSpawnRegion);
}

function removeServerSpawnRegion(obj, e) {
    ko.contextFor(e.target).$parent.spawnRegions.remove(obj);
}

function addExtraSubLevels(obj) {
    var newSubLevel = '';
    obj.extraSublevels.push(newSubLevel);
}

function removeExtraSubLevels(obj, e) { ko.contextFor(e.target).$parent.extraSublevels.remove(obj) }

function addTotalExtraSubLevels(obj) {
    var newSubLevel = '';
    obj.totalExtraSublevels.push(newSubLevel);
}

function removeTotalExtraSubLevels(obj, e) { ko.contextFor(e.target).$parent.totalExtraSublevels.remove(obj) }

function addSpawner() {
    var newSpawner = {
        "Name": ko.observable("New Spawner"),
        "NPCSpawnEntries": ko.observable(""),
        "NPCSpawnLimits": ko.observable(""),
        "MaxDesiredNumEnemiesMultiplier": ko.observable(1)
    };
    viewmodel.spawnerOverrideTemplates.push(newSpawner);
}

function removeSpawner(obj) {
    viewmodel.spawnerOverrideTemplates.remove(obj);
}

function addShip() {
    var newShip = {
        "PathName": ko.observable("New Ship"),
        "PathId": ko.observable(1),
        "AutoSpawnShipClass": ko.observable(""),
        "AutoSpawnEveryUTCInterval": ko.observable(21600),
        "autoSpawn": ko.observable(true),
        "Nodes": ko.observableArray([])
    };
    viewmodel.shipPaths.push(newShip);
}

function removeShip(obj) {
    viewmodel.shipPaths.remove(obj);
}

function addShipNode(obj) {
    var newNode = {
        "controlPointsDistance": ko.observable(0),
        "worldX": ko.observable(0),
        "worldY": ko.observable(0),
        "rotation": ko.observable(0)
    };
    obj.Nodes.push(newNode);
}

function removeShipNode(obj, e) { ko.contextFor(e.target).$parent.Nodes.remove(obj) }

function addTemplate() {
    var newTemplate = {
        // Basic Data
        "name": ko.observable("New Template"),
        "ip": ko.observable("127.0.0.1"),
        "port": ko.observable(50000),
        "gamePort": ko.observable(6666),
        "seamlessDataPort": ko.observable(27000),
        "gridX": ko.observable(0),
        "gridY": ko.observable(0),
        "MachineIdTag": ko.observable(""),
        "isHomeServer": ko.observable(false),
        "AdditionalCmdLineParams": ko.observable(""),

        // Biome Options
        "GlobalBiomeSeamlessServerGridPreOffsetValues": ko.observable(""),
        "GlobalBiomeSeamlessServerGridPreOffsetValuesOceanWater": ko.observable(""),

        // Override Options
        "OceanDinoDepthEntriesOverride": ko.observable(""),
        "OceanEpicSpawnEntriesOverrideValues": ko.observable(""),
        "oceanFloatsamCratesOverride": ko.observable(""),
        "treasureMapLootTablesOverride": ko.observable(""),
        "oceanEpicSpawnEntriesOverrideTemplateName": ko.observable(""),
        "NPCShipSpawnEntriesOverrideTemplateName": ko.observable(""),
        "regionOverrides": ko.observable(""),

        // Style Options
        "templateColorR": ko.observable(0.0),
        "templateColorG": ko.observable(0.0),
        "templateColorB": ko.observable(0.0),
        "waterColorR": ko.observable(0.5),
        "waterColorG": ko.observable(0.1),
        "waterColorB": ko.observable(0.1),
        "skyStyleIndex": ko.observable(2),

        // Misc Options
        "floorZDist": ko.observable(0),
        "utcOffset": ko.observable(0),
        "transitionMinZ": ko.observable(0),
        "serverIslandPointsMultiplier": ko.observable(1.0),

        // Date Options
        "lastModified": ko.observable("0001-01-01T00:00:00"),
        "lastImageOverride": ko.observable("0001-01-01T00:00:00"),

        // Boolean Options
        "islandLocked": ko.observable(false),
        "discoLocked": ko.observable(false),
        "pathsLocked": ko.observable(false),

        // Long Tables
        "sublevels": ko.observableArray([]),
        "islandInstances": ko.observableArray([]),
        "discoZones": ko.observableArray([]),

        // Mini Tables
        "spawnRegions": ko.observableArray([]),
        "extraSublevels": ko.observableArray([]),
        "totalExtraSublevels": ko.observableArray([]),

        // ???? Will just have to have a custom JSON editor...
        "OverrideShooterGameModeDefaultGameIni": ko.observable({})
    };
    viewmodel.serverTemplates.push(newTemplate);
}

function removeTemplate(obj) {
    viewmodel.serverTemplates.remove(obj);
}