/*
 * 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, graphite: true, require: true, module: true */
"use strict";

var Backbone    = require('backbone'),
    _           = require("underscore"),
    Headlights  = require("./utils/Headlights"),
    Path        = require("path"),
    FilePathSanitizer = require("shared/FilePathSanitizer");



var GenableCollection = Backbone.Collection.extend({
    
    currentSelection: null,
    hasBackground: false,
    initialize: function (models, options) {
        this.listenTo(this, "change:isActive", this.updateSelectedStates);
        this.listenTo(this, "add", this.checkForBackgroundLayer);
        this.listenTo(this, "remove", this.selectNext);
        this.listenTo(this, "reset", this.resetBackgroundLayerFlag);
        this.headlightsAssetGroup = (options && options.headlightsGroup) || Headlights.EXPORT_ASSETS_GROUP;
    },
    listenForFileConflicts: function () {
        this.listenTo(this, "add remove reset change:file", this.renameFileConflicts);
    },
    stopListeningForFileConflicts: function () {
        this.stopListening(this, "add remove reset change:file", this.renameFileConflicts);
    },
    resetBackgroundLayerFlag: function () {
        this.hasBackground = false;
        this.trigger("background-layer-status-change");
    },
    checkForBackgroundLayer: function (model) {
        if (model.get("layerType") === "backgroundLayer") {
            this.hasBackground = true;
            this.trigger("background-layer-status-change");
        }
    },
    getActiveSelection: function () {
        var activeModel = this.findBy("isActive", true);
        return activeModel ? activeModel.getActiveSelection() : null;
    },
    selectNext: function (model, collection, options) {
        if (model.get("layerType") === "backgroundLayer") {
            this.hasBackground = false;
            this.trigger("background-layer-status-change");
        }
        if (model.previousAttributes().selected && this.size() > 0) {
            var currentIndex = this.map(function(item) { return item.cid; }).indexOf(model.cid),
                index = currentIndex === (this.size() - 1) ? --currentIndex  : ++currentIndex,
                newModel = this.at(index);

            if (newModel) {
                newModel.set({ "isActive": true, selected: true });
            }
        }
    },
    hasDisplayableItems: function () {
        return this.length > 0;
    },    
    getSettings: function (filterPredicate) {
        var getLayerSettings = function (layerModel) {
            var settings = layerModel.get("layerSettings");
            if (!settings) {
                return;
            }
            if (filterPredicate) {
                return settings.filter(filterPredicate);
            }
            return settings.toArray();
        };
        
        var arrayOfSettingsArrays = this.map(getLayerSettings),
            singleArrayOfSettings = _.flatten(arrayOfSettingsArrays),
            emptySettingsRemoved = _.compact(singleArrayOfSettings);
        
        return emptySettingsRemoved;
    },
    
    getConflictedFileSettings: function (allSettings) {
        var normalizedFile = function (setting) {
            var file = setting.get("file");
            return file && file.toLowerCase();
        };
        
        var allFiles = _.compact(_.map(allSettings, normalizedFile)),
            fileCount = _.countBy(allFiles, _.identity);
        
        var settingHasDupeFile = function (settingsModel) {
            return fileCount[normalizedFile(settingsModel)] > 1;
        };
        return this.getSettings(settingHasDupeFile);
    },
    
    updateFileConflicts: function () {
        var allSettings = this.getSettings(),
            conflicts = this.getConflictedFileSettings(allSettings),
            nonConflicted = _.difference(allSettings, conflicts);
        _.invoke(nonConflicted, "set", "namesConflict", false);
        _.invoke(conflicts, "set", "namesConflict", true);
    },
    
    renameFileConflicts: function () {
        var createKeyedSetting = function(setting, index) {
            return { id: index,
                     name: setting.getBaseName(),
                     extension: setting.getFileExtension(),
                     setting: setting };
        };
        
        var applySanitizedSettings = function (sanitizeMap, keyedSetting) {
            var newVal = sanitizeMap[keyedSetting.id];
            if (newVal !== keyedSetting.name) {
                keyedSetting.setting.setBaseName(newVal);
            }
        };
        
        var layerHasASetting = function(settings, layer) {
            var layerSettings = layer.get("layerSettings");
            return layerSettings && _.some(settings, layerSettings.contains, layerSettings);
        };
        
        var allSettings = this.getSettings(),
            conflictSettings = this.getConflictedFileSettings(allSettings),
            conflictLayers = this.filter(_.partial(layerHasASetting, conflictSettings)),
            settingToSanitize = _.map(allSettings, createKeyedSetting),
            sanitizedMap = FilePathSanitizer.createSanitizedUniqueLayerBasenamesMap(settingToSanitize);
        _.each(settingToSanitize, _.partial(applySanitizedSettings, sanitizedMap));
    },

    updateSelectedStates: function (model) {
        if (!model.get("isActive")) {
            return;
        }
        var layers = this.reject(function (layerModel) {
            return layerModel.cid === model.cid;
        });
        _.invoke(layers, "deselectAll");
        
        this.trigger("change:currentSelection", model);
    },
    hasBackgroundLayer: function () {
        return this.hasBackground;
    },
    findBy: function (fieldName, id) {
        var findObj = {};
        findObj[fieldName] = id;
        return this.findWhere(findObj);
    },

    logAssetSummary: function (itemType, exportCount, seconds) {
        Headlights.accumulateData(Headlights.EXPORTTYPE, Headlights.DIALOG);
        Headlights.accumulateData(Headlights.ITEMTYPE, itemType);
        Headlights.accumulateData(Headlights.ITEMCOUNT, exportCount);
        Headlights.accumulateData(Headlights.SECONDS, seconds);
        Headlights.logAccumulatedData(Headlights.EXPORT_SUMMARY_GROUP);
    },

    logDataForOneAsset: function (oneAssetModel, itemType) {
        var format = oneAssetModel.get("extension"),
            quality = oneAssetModel.get("quality"),
            interp = oneAssetModel.get("interpolationType"),
            scale = oneAssetModel.get("scale"),
            originalDim = oneAssetModel.get("originalDimensions"),
            imageWidth = Math.round(originalDim.width * scale),
            imageHeight = Math.round(originalDim.height * scale),
            canvasWidth = oneAssetModel.get("canvasWidth"),
            canvasHeight = oneAssetModel.get("canvasHeight"),
            assetWidth = canvasWidth ? canvasWidth : imageWidth,
            assetHeight = canvasHeight ? canvasHeight : imageHeight,
            canvasSpecified = !!(canvasWidth || canvasHeight);

        Headlights.accumulateData(Headlights.EXPORTTYPE, Headlights.DIALOG);
        Headlights.accumulateData(Headlights.ITEMTYPE, itemType);
        Headlights.accumulateData(Headlights.INTERP, interp);
        Headlights.accumulateData(Headlights.SCALE, scale);
        Headlights.accumulateData(Headlights.WIDTH, assetWidth);
        Headlights.accumulateData(Headlights.HEIGHT, assetHeight);
        Headlights.accumulateData(Headlights.CANVAS, canvasSpecified);

        if (format === "png" && quality !== "100") {
            format += quality;
        } else if (format.substr(0,4) === "png-") {
            format = format.replace("-", "");
        }

        Headlights.accumulateData(Headlights.FORMAT, format);

        if (format === "jpg") {
            quality = parseInt(quality);
            Headlights.accumulateData(Headlights.QUALITY, quality);
        }

        // log accumulated data for this asset
        Headlights.logAccumulatedData(this.headlightsAssetGroup);
    },
    
    logDataForOneLayer: function (layer, itemType) {
        var layerSettings = layer.get("layerSettings"),
            j;
        for (j = 0; j < layerSettings.length; j++) {
            this.logDataForOneAsset(layerSettings.at(j), itemType);
        }
    },

    logExportedAssetData : function (exportDoc, exportDocArtboards, seconds) {
        var i,
            docLayer,
            exportedLayers,
            itemType = Headlights.SELECTION;

        if (exportDoc) {
            docLayer = this.findBy("isDocument", true);
            itemType = Headlights.DOCUMENT;
            this.logAssetSummary(itemType, 1, seconds);
            this.logDataForOneLayer(docLayer, itemType);
        } else {
            if (exportDocArtboards) {
                itemType = Headlights.ARTBOARD;
                exportedLayers = this.where({isArtboard: true});
            } else {
                itemType = Headlights.SELECTION;
                exportedLayers = this.filter(function (layer) {
                    return layer.get("layerSettings").length > 0;
                });
            }
            this.logAssetSummary(itemType, exportedLayers.length, seconds);
            exportedLayers.forEach(function (layer) {
                this.logDataForOneLayer(layer, itemType);
            }.bind(this));
        }
    }
    
});

module.exports = GenableCollection;
