/*
 * ADOBE CONFIDENTIAL
 *
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, bitwise: true, node: true */
/*global define: true, require:true, _:true, $:true, module: true */

"use strict";

var Backbone = require('backbone'),
    JSXRunner   = require("./JSXRunner"),
    LayerModel = require("./layerModel.js"),
    ServerInterface = require("./serverInterface.js"),
    Strings = require("./LocStrings"),
    ActionRollup = require("./actionRollup.js"),
    LayerNameParser = require("./utils/LayerNameParser.js");

if (Strings.SETTINGS_PLACEHOLDER_WEB_DEFAULT === undefined) {
    Strings.SETTINGS_PLACEHOLDER_WEB_DEFAULT = "";
}

var DefaultSettingsModel = Backbone.Model.extend({
    
    defaultLayer: null,
    duplicateDefaultLayers: [],
    lastDocId: 0,
    lastDocWidth: 0,
    lastDocHeight: 0,
    
    sizeDefaultLookup: {
        "0.25": ["quarter"],
        "0.33": ["third"],
        "0.5": ["half"],
        "0.75": ["android_ldpi"],
        "1": ["web_default"],
        "1.5": ["android_hdpi"],
        "2": ["web_retina"],
        "3": ["android_xxhdpi"],
        "4": ["four_times"]
    },
    
    defaultSizeLookup: {
        "quarter": 0.25,
        "third": 0.33,
        "half": 0.5,
        "android_ldpi": 0.75,
        "web_default": 1,
        "web_retina": 2,
        "android_hdpi": 1.5,
        "android_xxhdpi": 3,
        "four_times": 4
    },

    defaults: {
        designedAt: 1.0,
        previewAt: 1.0,
        activePreviewDefault: "web_default",
        "web_default": true,
        "web_retina": false,
        "android_ldpi": false,
        "android_mdpi": false,
        "android_hdpi": false,
        "android_xhdpi": false,
        "android_xxhdpi": false,
        "half": false,
        "four_times": false,
        "text_web_default": "",
        "text_web_retina": "",
        "text_android_ldpi": "",
        "text_android_mdpi": "",
        "text_android_hdpi": "",
        "text_android_xhdpi": "",
        "text_android_xxhdpi": "",
        "text_half": "",
        "text_four_times": "",
        "text_third": false,
        "text_quarter": false,
        "third": false,
        "quarter": false
    },
    
    initialize: function (options) {
        this.listenTo(this, "change", this.updateModelBacking);
        this.listenTo(this, "change:designedAt", this.updateModelBackingForDesignedAt);
        this.listenTo(this, "change:activePreviewDefault", this.updateModelBackingForPreviewAt);
        this.listenTo(this, "change:autoSaveOnUpdate", this.updateModelBackingForAutoSaveChanges);
        this.listenTo(ServerInterface, "autosave-setting-update", this.udpateAutoSaveFromServer);
    },
    
    reset: function () {
        var defName;
        for (defName in this.defaults) {
            if (this.defaults.hasOwnProperty(defName)) {
                this.set(defName, this.defaults[defName]);
            }
        }
        this.trigger("reset");
    },
    
    isValidDefaultLayerName: function (defaultLayerName) {
        var settings;
        try {
            settings = LayerNameParser.parse(defaultLayerName);
        } catch (exLN) {
            console.warn("Failed to parse potential defualt layer " + defaultLayerName + " with " + exLN);
        }
        if (!settings) {
            return false;
        }
        var isDefault = function (parsedItem) {
            return parsedItem["default"];
        };
        return _.every(settings, isDefault);
    },
    
    applyDefaultLayerIfNecessary: function (defaultLayerName, options) {
        var bNecessary = false,
            skipActionRollup = options && options.skipActionRollup;
        
        if (this.defaultLayer && defaultLayerName === this.defaultLayer.get("name")) {
            return; // no change
        }
        
        //see if this default layer name qualifies
        if (defaultLayerName && defaultLayerName !== "" && defaultLayerName !== "default") {
            bNecessary = true;
        }
        
        if (bNecessary && !this.isValidDefaultLayerName(defaultLayerName)) {
            return;
        }
        
        if (!this.defaultLayer && bNecessary && !this.isAddingLayer) {
            if (!skipActionRollup) {
                ActionRollup.addDefaultLayer();
                ActionRollup.renameDefaultLayer(defaultLayerName);
            }
            this.defaultLayer = new LayerModel({
                layerId: "ADDED",
                layerIndex: 0,
                layerType: "layer",
                name: defaultLayerName,
                selected: false,
                isActive: false
            }, { generatorSettings: { } });
            //TBD: parse and add the layerSettings
            
            
        } else if (this.defaultLayer && !bNecessary) {
            if (!skipActionRollup) {
                ActionRollup.removeDefaultLayer();
            }
            this.defaultLayer = null;
            
        } else if (this.defaultLayer) {
            if (!skipActionRollup) {
                ActionRollup.renameDefaultLayer(defaultLayerName);
            }
            this.defaultLayer.set("name", defaultLayerName);
            
            //TBD: do we need to re-parse and apply the layer settings here?
        }
    },
    getDesignedAt: function () {
        return this.get("designedAt");
    },
    //does not trigger model changes (silent) - only call during initialization
    applyDocSettings: function (docSettings) {
        
        this.set({
            "extension": docSettings.extension,
            "quality": docSettings.quality,
            "scale": docSettings.scale,
            "interpolationType": docSettings.interpolationType
        }, {
            silent: true
        });
    },
    
    applyAssetToDefault: function (asset, options) {
        var scale = asset.get("scale") || 1,
            scaleRendered,
            assetName = asset.get("name"),
            i,
            iSpacePos = assetName.indexOf(" "),
            sizePart,
            localizedFolderSuffix,
            designedAt = parseFloat(this.get("designedAt"), 10) || 1;
        
        scaleRendered = Math.round(100 * scale) + "%";
        scale *= designedAt;
        
        if (assetName.indexOf(scaleRendered) === 0) {
            assetName = assetName.substr(scaleRendered.length).trim();
            asset.set({
                "name": assetName,
                "scale": scale
            }, {
                silent: true
            });
        } else {
            asset.set({
                "scale": scale
            }, {
                silent: true
            });
        }
        
        var aKeysAtScale = this.sizeDefaultLookup[String(scale)];
        if (aKeysAtScale) {
            
            for (i = aKeysAtScale.length - 1; i >= 0; i--) {
                localizedFolderSuffix = Strings["SETTINGS_PLACEHOLDER_" + aKeysAtScale[i].toUpperCase()];
                if (i === 0 || (i > 0 && assetName && localizedFolderSuffix && assetName.indexOf(localizedFolderSuffix) >= 0)) {
                    var oSet = {};
                    oSet[aKeysAtScale[i]] = true;
                    oSet["text_" + aKeysAtScale[i]] = assetName;
                    this.set(oSet, options);
                    return true;
                }
            }
        }
        return false;
    },
    
    _initializeDefaultLayerSetting: function (layerSettings) {
        
        layerSettings.forEach(function (defaultAsset) {
            if (!this.applyAssetToDefault(defaultAsset, {skipActionRollup: true})) {
                console.warn("Failed to apply this default.  We are sorry that you lost: " + defaultAsset.get("name"));
                
                //TBD: keep this asset in a list and re-apply it, so we don't loose data
                
            }
        }.bind(this));
        
        //make sure 1.0 is enabled
        if (!this.get("web_default")) {
            this.set("web_default", true);
        }
    },
    
    initializeWithLayer: function (defaultLayer) {
        
        var layerSettings,
            firstAsset;
        
        if (!this.defaultLayer) {
            this.defaultLayer = defaultLayer;
            
            ActionRollup.setDefaultLayer(defaultLayer.get("layerId"), defaultLayer.get("name"));
            
            //reset just takes it back to defaults, we want to erase and then rebuild the enablement
            Object.keys(this.defaultSizeLookup).forEach(function (def) {
                this.set(def, false, { silent: true });
            }.bind(this));
            
            layerSettings = defaultLayer.get("layerSettings");
            if (layerSettings && layerSettings.size() > 0) {
                this._initializeDefaultLayerSetting(layerSettings);
            }
            
            this.trigger("default-names-changed", this);
            
        } else {
            console.log("found a duplicate (ignored) default layer " + defaultLayer.get("name"));
            this.duplicateDefaultLayers.push(defaultLayer);
            ActionRollup.deleteLayer(defaultLayer.get("layerId"));
        }
    },
    
    removeDefaultLayer: function (defaultLayer) {
        if (defaultLayer === this.defaultLayer) {
            this.defaultLayer = null;
        } else {
            this.duplicateDefaultLayers.remove(defaultLayer);
        }
    },
    getExportString: function (data) {
        if (!data) {
            return "";
        }
        if (!data.suffix) {
            data.suffix = "";
        }
        if (!data.folder || !data.folder.trim() || data.folder.trim() === "/") {
            data.folder = "";
        }
        if (data.folder && !_.endsWith(data.folder, "/")) {
            data.folder = data.folder + "/";
        }
        return data.folder + data.suffix;
    },
    serializeToLayerName: function () {
        var outA = "default",
            outB = "",
            outVal = "",
            chain = [],
            val,
            nameVal,
            sizeVal,
            sepA = "",
            sepB = "",
            designedAt = parseFloat(this.get("designedAt"), 10) || 1.0,
            i,
            isDefaulted;
        
        Object.keys(this.defaultSizeLookup).forEach(function (def) {
            outVal = "";
            val = this.get(def);
            if (val === true) {
                //store these in a list and sort it before writing it to "out" so we can persist designed-at
                nameVal = this.get("text_" + def) || "";
                sizeVal = Math.round(100.0 * this.defaultSizeLookup[def] / designedAt) + "%";
                
                if (sizeVal !== "100%") {
                    if (nameVal !== "") {
                        outVal = sizeVal + " " + nameVal;
                    } else {
                        outVal = sizeVal;
                    }
                    isDefaulted = false;
                } else if (nameVal !== "") {
                    isDefaulted = false;
                    outVal = nameVal;
                } else {
                    isDefaulted = true;
                    outVal = "100%";
                }

                if (outVal !== "") {
                    chain.push({ isDefaulted: isDefaulted, out: outVal });
                }
            }
        }.bind(this));
        
        if ((chain.length > 0 && !isDefaulted) || (chain.length > 1)) {
            for (i = 0; i < chain.length; i++) {
                if (chain[i].isDefaulted) {
                    outA += sepA + " " + chain[i].out;
                    sepA = ",";
                } else {
                    outB += sepB + " " + chain[i].out;
                    sepB = ",";
                }
            }
        }
        
        return outA + sepA + outB;
    },
    getFolderSuffixObject: function (value) {
        value = value || "";
        var split = value.split("/"),
            folder = "";
        if (split[0]) {
            folder =  split[0] + "/";
        }
        return {
            folder: folder,
            suffix: split[1]
        };
    },
    createKVP: function () {
        var kvp = {};
        Object.keys(this.sizeDefaultLookup).forEach(function (key) {
            var objectKey = this.sizeDefaultLookup[key][0];
            if (this.get(objectKey)) {
                kvp[key] = this.getFolderSuffixObject(this.get("text_" + objectKey));
            }
        }, this);
        return kvp;
    },
    updateModelBacking: function (model, options) {
        var defaultName = this.serializeToLayerName();
        this.applyDefaultLayerIfNecessary(defaultName, options);
    },
    
    updateModelBackingForDesignedAt: function (model, value, options) {
        //make sure we have the designed at resolution checked...
        var settingsAtSize = this.sizeDefaultLookup[String(value)];
        if (settingsAtSize && settingsAtSize.length > 0 && !_.any(settingsAtSize, function (sizeSet) { return model.get(sizeSet); })) {
            model.set(settingsAtSize[0], true);
        }
        this.serializeDocGeneratorSettings();
    },
    
    updateModelBackingForPreviewAt: function (model, value, options) {
        var previewAtValue = this.defaultSizeLookup[value];
        this.set("previewAt", previewAtValue);
        this.serializeDocGeneratorSettings();
    },
    
    serializeDocGeneratorSettings: function () {
        ActionRollup.serializeDocGeneratorSettings({ docSettings: {
            previewAt: this.get("previewAt"),
            designedAt: this.get("designedAt")
        }});
    },
    
    updateModelBackingForAutoSaveChanges: function (model, value, options) {
        var ignore = options && options.ignore === this;
        if (this.lastDocId && !ignore) {
            var update = this.setAutosaveOnServer.bind(this, this.lastDocId);
            ActionRollup.setAutoSaveUpdater(update);
        }
    },
    
    setAutosaveOnServer: function (docId) {
        var enabled = this.get("autoSaveOnUpdate") ? true : false;
        return ServerInterface.sendCommand("setAutoGenerateImageSetting", {docId: docId, enabled: enabled});
    },
    
    updateForDocSize: function (width, height) {
        this.lastDocWidth = width;
        this.lastDocHeight = height;
    },
    
    updateForDocId: function (id) {
        var self = this;
        this.lastDocId  = id;
        ServerInterface.sendCommand("getAutoGenerateImageSetting", {docId: id})
            .then(function (docinfo) {
                var enabled = (docinfo && docinfo.enabled) ? true : false;
                self.set("autoSaveOnUpdate", enabled, {ignore: self});
            }, function (error) {
                console.log("error for ServerInterface.sendCommand(\"getAutoGenerateImageSetting\"");
            });
    },
    
    udpateAutoSaveFromServer: function () {
        if (this.lastDocId) {
            this.updateForDocId(this.lastDocId);
        }
    }
});


module.exports = DefaultSettingsModel;
