/*
 * ADOBE CONFIDENTIAL
 *
 * Copyright (c) 2013-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 */
/*global define: true, graphite: true, setTimeout: true, window: true*/

define([
    "jquery",
    "underscore",
    "backbone",
    "ccweb.files.extract/Constants",
    "ccweb.files.extract/views/popup/BasePreviewPopupView",
    'plugin-dependencies',
    'ccweb.files.extract/controllers/ClipboardController',
    'ccweb.files.extract/controllers/ZoomController',
    'ccweb.files.extract/controllers/SelectionController',
    'ccweb.files.extract/models/LayerModelMap',
    'ccweb.files.extract/models/UserSettingsModel',
    'ccweb.files.extract/utils/TemplateUtil',
    'ccweb.files.extract/utils/MeasurementUtil',
    'ccweb.files.extract/utils/UTF8',
    'dreamweaver/models/CopyCssPopupModel',
    'dreamweaver/views/CopyCssPopupView',
    'DWPSDExtractManager',
    'text!ccweb.files.extract/views/templates/measurementPopupTemplate.html',
    'DWPopUpManager',
    'parfait/MeasurementPopupView'
], function ($, _, Backbone, Constants, BasePreviewPopupView, deps,
        ClipboardController, ZoomController, SelectionController, LayerModelMap, UserSettingsModel,
        TemplateUtil, MeasurementUtil, UTF8, CopyCssPopupModel, CopyCssPopupView, DWPSDExtractManager, MeasurementPopupTemplate, DWPopUpManager, MeasurementPopupView) {

    "use strict";

    var DwMeasurementPopupView = MeasurementPopupView.extend({
        
        className: "measurementPopup popup measurementTooltip",
        elementCss: '',
        events: {
            "click #copyCSSLink": "handleCopyCSS",
            "click #copy-css-groups-container": "handleCssItemClick",
            "mousedown #copyCSSLink": "handleMouseDown",
            "click #copyTextLink": "handleCopyText",
            "click .copyable": "handleCopyableClick",
            "mousedown #copyTextLink": "handleMouseDown"
        },

        initialize: function () {
            this.addPreinitializeHandlers();
            BasePreviewPopupView.prototype.initialize.apply(this, arguments);
        },
        
        remove: function () {
            var copyables = this.$el.find(".copyable"),
                extractIcon = this.$el.find(".measurementElementAssetExtract");
            
            if (extractIcon.length) {
                extractIcon.off('click');
            }
            if (copyables.length) {
                copyables.off("mouseenter mouseleave");
            }
            
            // COMPLETELY UNBIND THE VIEW
            if (this.copyCssPopupModel) {
                this.copyCssPopupModel.destroy();
				this.copyCssPopupModel = null;
            }
            
            if (this.cssGroupView) {
                this.cssGroupView.remove();
                this.cssGroupView = null;
            }

            window.graphite.events.off(null, null, this);

            // Remove view from DOM
            return BasePreviewPopupView.prototype.remove.apply(this, arguments);
        },
        
        addPreinitializeHandlers: function () {
            var mouseEnter = function () {
                    $(this).data('title', $(this).attr('title'));
                    $(this).removeAttr('title');
                },
                mouseLeave = function () {
                    $(this).attr('title', $(this).data('title'));
                };
            window.graphite.events.on("disable-css-copy", function () {
                if (this.copyCssPopupModel && this.copyCssPopupModel.get("isDisabled")) {
                    var copyButton = this.$el.find("#copyCSSLink");
                    copyButton.addClass("disabled");
                    copyButton.hover(mouseEnter, mouseLeave);
                }
            }, this);
            window.graphite.events.on("enable-css-copy", function () {
                if (this.copyCssPopupModel && !this.copyCssPopupModel.get("isDisabled")) {
                    var copyButton = this.$el.find("#copyCSSLink");
                    copyButton.unbind('mouseenter', mouseEnter).unbind('mouseleave', mouseLeave);
                    copyButton.removeClass("disabled");
                }
            }, this);
        },
        
        addHandlers: function () {
            window.graphite.events.on("netstatus-change", function (notification) {
                var extractIcon = this.$el.find(".measurementElementAssetExtract");
                if (notification === "reconnected" && DWPSDExtractManager.canEnableDownloadAssets()) {
                    extractIcon.removeClass('disabled');
                } else {
                    extractIcon.addClass('disabled');
                }
            }, this);
        },

        render: function () {
            BasePreviewPopupView.prototype.render.apply(this, arguments);

            this.$el.find(".popup-contents").html(
                TemplateUtil.createTemplate(MeasurementPopupTemplate)
            );

            var copyCssLink = this.$el.find('#copyCSSLink'),
                copyTextLink = this.$el.find('#copyTextLink'),
                extractIcon = this.$el.find(".measurementElementAssetExtract"),
                copyables = this.$el.find(".copyable");

            copyCssLink.html(deps.translate("COPY_CSS"));
            copyTextLink.html(deps.translate("COPY_TEXT"));

            copyables.attr("title", deps.translate("CLICK_TO_COPY"));
            copyables.hover(this.highlightLabel, this.unhighlightLabel);

            extractIcon.click(function (event) {
                // add click handler for the measurement popup extract button
                graphite.events.trigger("show-extract-asset-popup", { sourceElement: extractIcon, origin: "measurementPopup"});
                event.stopPropagation();
            });
            
            this.renderCssGroups();
            return this;
        },
        
        renderCssGroups: function () {
            var selectionList = SelectionController.getSelectedLayers();
            
            // Do not show group list on multiple selection
            if (selectionList.length === 1) {
                if (!this.copyCssPopupModel) {
                    this.copyCssPopupModel = new CopyCssPopupModel();
                }
                
                var gradientUsage = selectionList[0].getUsageModels().gradients;
                var vendorPrefixedGrads = [];
                if (gradientUsage && gradientUsage.length > 0) {
                    var gradientModel = gradientUsage[0].get('style');
                    vendorPrefixedGrads = gradientModel.getCSS(true);
                    this.copyCssPopupModel.set('vendorSpecificGradients', vendorPrefixedGrads);
                }
                
                this.copyCssPopupModel.set('cssArray', selectionList[0].getCSSArray());
                this.copyCssPopupModel.createCssStructures();
                if (this.cssGroupView) {
                    this.cssGroupView.remove();
                }
                this.cssGroupView = new CopyCssPopupView({model: this.copyCssPopupModel});
                this.$el.find('#copy-css-groups-container').append(this.cssGroupView.el);
                DWPopUpManager.setCSSPopupView(this);
            }
        },

        initCopyToClipboard: function () {
            var self = this,
                clipboard = ClipboardController.getClipboard(),
                copyables = this.$el.find(".copyable");

            //copy text link
            var copyTextBtn = this.$el.find("#copyTextLink");

            //copy css button
            var copyCSSBtn = this.$el.find("#copyCSSLink");

            _.each(copyables, function (elem) {
                clipboard.clip(elem);
            });

            graphite.events.on("clipboard-data-requested", function (elem) {
                if (elem === copyTextBtn[0]) {
                    if (self.layerModel && self.layerModel.get("type") === Constants.Type.LAYER_TEXT) {
                        clipboard.setText(UTF8.decodeCharacters($.trim(self.layerModel.get("properties").get("rawText"))));
                        //copy text event
                        graphite.events.trigger('copy-text');
                        self.showSuccessTooltip(deps.translate("TEXT_COPIED_TO_CLIPBOARD"));
                    }
                } else if (elem === copyCSSBtn[0]) {
                    if (self.layerModel) {
                        var cssStr = self.layerModel.getCSSAsString(true, UserSettingsModel.get('preprocessor'));
                        clipboard.setText(cssStr);
                        //copy css event
                        graphite.events.trigger('copy-css');
                        self.showSuccessTooltip(deps.translate("CSS_COPIED_TO_CLIPBOARD"));
                    }
                } else if ($(elem).hasClass("copyable")) {
                    this.handleCopyableElement($(elem));
                }
            }, this);

            graphite.events.on("clipboard-complete", function (elem) {
                //$(parent).append("<div style='background-color:#0000FF;'><span>TESTTEST</span></div>");
            });
        },

        // Handles special case copyable values that are specific to MeasurementPopupView, otherwise
        // just adds the element's value as 'px' value to clipboard.
        handleCopyableElement: function ($elem) {
            var clipboard = ClipboardController.getClipboard(),
                copyMsg = deps.translate("VALUE_COPIED_TO_CLIPBOARD"),
                bounds = this.lastMeasuredBounds,
                clipValue;

            if ($elem.hasClass("width") || $elem.hasClass("height")) {
                clipValue = "width: " + (bounds.right - bounds.left) + "px;\nheight: " + (bounds.bottom - bounds.top) + "px;";
                copyMsg = deps.translate("SIZE_COPIED_TO_CLIPBOARD");
            } else if ($elem.hasClass("x") || $elem.hasClass("y")) {
                clipValue = "top: " + bounds.top + "px;\nleft: " + bounds.left + "px;";
                copyMsg = deps.translate("POSITION_COPIED_TO_CLIPBOARD");
            } else {
                clipValue = $elem.text() + "px";
            }

            clipboard.setText(clipValue);
            this.showSuccessTooltip(copyMsg);
        },

        showSuccessTooltip: function (message) {
            var parent = this.$el.parent().get(0);
            $(parent).append("<div id='notificationTooltip' style='display:none'><span>" + message + "</span></div>");
            var tooltip = $("#notificationTooltip");
            var tipWidth = tooltip.width();
            var tipHeight = tooltip.height();
            var elementBounds = this.layerModel ? this.layerModel.attributes.bounds : this.layerGroupBounds;
            var tipPosLeft = ((elementBounds.left + (elementBounds.right - elementBounds.left) / 2) * ZoomController.getZoomLevel()) - tipWidth / 2;
            var tipPosTop = ((elementBounds.top + (elementBounds.bottom - elementBounds.top) / 2) * ZoomController.getZoomLevel()) - tipHeight / 2;
            tooltip.css({top: tipPosTop, left: tipPosLeft, opacity: 0.8});
            tooltip.fadeIn(250);
            setTimeout(function () {
                tooltip.remove();
            }, Constants.toolTipTimeout);
        },
        
        getFilteredElementCss: function () {
            var cssString = '',
                propertyName = '',
                propertyValue = '';
            Array.prototype.slice.call(this.$el.find('.css-property-item'), 0).forEach(function (cssItemNode) {
                if ($(cssItemNode).find('.copy-css-check').is(':checked')) {
                    propertyName = $(cssItemNode).find('.property-name').text();
                    propertyValue = $(cssItemNode).find('.property-value').text();
                    cssString += propertyName + ': ' + propertyValue + ';\n';
                }
            });
            return cssString;
        },
        
        getGradientVendorPrefixesStr: function (addWebkitPrefix, addMozPrefix, addOPrefix, shouldFormatCode) {
            var cssString = '',
                propertyName = '',
                propertyValue = '',
                loopCounter = 0,
                formatCode = shouldFormatCode;
            
            Array.prototype.slice.call(this.$el.find('.css-property-item'), 0).forEach(function (cssItemNode) {
                if ($(cssItemNode).find('.copy-css-check').is(':checked')) {
                    propertyName = $(cssItemNode).find('.property-name').text();
                    propertyValue = $(cssItemNode).find('.property-value').text();
                    
                    if (propertyValue.indexOf('gradient') >= 0) {
                        var gradientVendorPrefixes = this.copyCssPopupModel.get('vendorSpecificGradients');
                        // append the vendorPrefixes to the string.
                        var idx;
                        for (idx = 0; idx < gradientVendorPrefixes.length; idx++) {
                            var grad = gradientVendorPrefixes[idx];
                            if (grad.property) {
                                
                                if ((grad.value.indexOf('-webkit') === 0 && addWebkitPrefix) ||
                                        (grad.value.indexOf('-moz') === 0 && addMozPrefix) ||
                                        (grad.value.indexOf('-o') === 0 && addOPrefix) ||
                                        (grad.value.indexOf('linear-gradient') === 0) ||
                                        (grad.value.indexOf('radial-gradient') === 0)) {
                                    
                                    if (loopCounter !== 0 || idx > 0) {
                                        if (formatCode) {
                                            cssString = cssString + '\n\t';
                                        } else {
                                            cssString = cssString + '\n';
                                        }
                                    }
                                    
                                    cssString += 'background-image: ' + grad.value + ';';
                                    
                                }
                            }
                        }
                    } else {
                        
                        if (loopCounter !== 0) {
                            if (formatCode) {
                                cssString = cssString + '\n\t';
                            } else {
                                cssString = cssString + '\n';
                            }
                        }
                        cssString += propertyName + ': ' + propertyValue + ';';
                    }
                    
                    loopCounter++;
                    
                }
            }, this);
            return cssString;
        },

        //------------------------------------------------
        // Handlers
        //------------------------------------------------
        handleCopyCSS: function (event) {
            if (!$(event.target).hasClass("disabled") && this.layerModel) {
                var cssStr = this.getFilteredElementCss();
                var gradientVendorPrefixStr = this.getGradientVendorPrefixesStr(true, true, true, false);
                if (cssStr) {
                    DWPSDExtractManager.copyCSS(cssStr, gradientVendorPrefixStr);
                    graphite.events.trigger('copy-css');
                    this.showSuccessTooltip(deps.translate("CSS_COPIED_TO_CLIPBOARD"));
                }
            }
            event.stopPropagation();
        },

        handleCopyText: function (event) {
            if (this.layerModel && this.layerModel.get("type") === Constants.Type.LAYER_TEXT) {
                var text = UTF8.decodeCharacters(this.layerModel.get("properties").get("rawText"));
                DWPSDExtractManager.copyText(text);
                graphite.events.trigger('copy-text');
                this.showSuccessTooltip(deps.translate("TEXT_COPIED_TO_CLIPBOARD"));
            }
            event.stopPropagation();
        },
        
        handleCssItemClick: function (event) {
            event.stopPropagation();
        },

        highlightLabel: function () {
            $(this).addClass("zeroclipboard-is-hover");
        },

        unhighlightLabel: function () {
            $(this).removeClass("zeroclipboard-is-hover");
        },

        handleShowMeasurementInfo: function (params) {
            var notchElement = this.$el.find(".notch"),
                dimensionDiv = this.$el.find('.measurementElementInfoDim'),
                positionDiv = this.$el.find('.measurementElementInfoPos'),
                copyCSSLink = this.$el.find("#copyCSSLink"),
                copyTextLink = this.$el.find("#copyTextLink"),
                extractIcon = this.$el.find(".measurementElementAssetExtract"),
                $popupOverlay = $('#popupOverlay'),
                hScrollPos =  $("div.psd-preview-view").scrollLeft(),
                vScrollPos =  $("div.psd-preview-view").scrollTop(),
                previewAreaHeight = $('div.psd-preview-view').height(),
                previewAreaWidth = $('div.psd-preview-view').width() - 10,
                maxX = Math.min(previewAreaWidth, this.$el.parent().width()),
                maxY = Math.min(previewAreaHeight, this.$el.parent().height()),
                verticalPadding = Math.min(Math.floor(maxY / 10), 90), //Use less vertical padding when we have less vertical space
                bounds,
                $bannerElements,
                $bannerElement1,
                $bannerElement2;

            this.layerModel = null;
            this.layerGroupBounds = null;

            if (params.layerList instanceof Array) {
                bounds = MeasurementUtil.calcLayerGroupBounds(params.layerList, SelectionController.getPSDModel());
                this.lastMeasuredBounds = _.clone(bounds);
                this.layerGroupBounds = params.layerList[0].attributes.bounds;

                //User has selected multiple elements, modify the popup accordingly

                dimensionDiv.find(".width").text(bounds.right - bounds.left);
                dimensionDiv.find(".height").text(bounds.bottom - bounds.top);

                notchElement.hide();
                positionDiv.hide();
                copyCSSLink.addClass('disabled');
                copyTextLink.addClass('disabled');
                if (!DWPSDExtractManager.canEnableDownloadAssets()) {
                    extractIcon.addClass('disabled');
                }
                //Figure the bounds for our popup. Start by assuming we're going to place it in the middle, centered horizontally
                var popupBounds = {left: (maxX - this.$el.outerWidth()) / 2 + hScrollPos,
                                   top: (maxY - this.$el.outerHeight()) / 2 + vScrollPos,
                                   right: (maxX + this.$el.outerWidth()) / 2 + hScrollPos,
                                   bottom: (maxY + this.$el.outerHeight()) / 2 + vScrollPos};

                if (params.layerList.length === 2) {
                    $bannerElements = $popupOverlay.find("div.measurementOffsetsBanner");
                    $bannerElement1 = $bannerElements.first();
                    $bannerElement2 = $bannerElements.slice(1).first();
                    //We need to figure out what the banner's actual bounds will be, but that's difficult because
                    //it's currently animating and is contained in a parent that's also animating. So we figure
                    //where the banner will end up after the animations by inferring from the current CSS values.
                    var bannerLeft = parseInt($bannerElement1.css("left"), 10),
                        bannerParentLeft = parseInt($bannerElement1.parent().css("left"), 10),
                        bannerParentParentOffsetLeft = $bannerElement1.parent().parent().offset().left,
                        bannerTop = parseInt($bannerElement1.css("top"), 10),
                        bannerParentTop = parseInt($bannerElement1.parent().css("top"), 10),
                        bannerParentParentOffsetTop = $bannerElement1.parent().parent().offset().top,
                        pendingBannerX = bannerLeft + bannerParentLeft + bannerParentParentOffsetLeft - $popupOverlay.offset().left,
                        pendingBannerY = bannerTop + bannerParentTop + bannerParentParentOffsetTop - $popupOverlay.offset().top;

                    //Now that we've computed the position of the first banner, figure out it's bounds
                    var banner1Bounds = {left: pendingBannerX, top: pendingBannerY, right: pendingBannerX + $bannerElement1.outerWidth(), bottom: pendingBannerY + $bannerElement1.outerHeight()};
                    var banner2Bounds = {left: 0, top: 0, right: 0, bottom: 0};

                    //Now determine if there is a second banner and it's bounds
                    if ($bannerElement2.length === 1) {
                        bannerLeft = parseInt($bannerElement2.css("left"), 10);
                        bannerParentLeft = parseInt($bannerElement2.parent().css("left"), 10);
                        bannerParentParentOffsetLeft = $bannerElement2.parent().parent().offset().left;
                        bannerTop = parseInt($bannerElement2.css("top"), 10);
                        bannerParentTop = parseInt($bannerElement2.parent().css("top"), 10);
                        bannerParentParentOffsetTop = $bannerElement2.parent().parent().offset().top;
                        pendingBannerX = bannerLeft + bannerParentLeft + bannerParentParentOffsetLeft - $popupOverlay.offset().left;
                        pendingBannerY = bannerTop + bannerParentTop + bannerParentParentOffsetTop - $popupOverlay.offset().top;
                        banner2Bounds = {left: pendingBannerX, top: pendingBannerY, right: pendingBannerX + $bannerElement2.outerWidth(), bottom: pendingBannerY + $bannerElement2.outerHeight()};
                    }

                    //And then figure out if the popup intersects with either banner so we know if we need to move it to the top
                    if (MeasurementUtil.boundsIntersect(banner1Bounds, popupBounds) || MeasurementUtil.boundsIntersect(banner2Bounds, popupBounds)) {
                        //The bounds intersect, so place the popup near the top
                        popupBounds.top = verticalPadding + $("div.psd-preview-view").scrollTop();
                        popupBounds.bottom = popupBounds.top + this.$el.outerHeight();

                        //Can we put it at the top?
                        if (MeasurementUtil.boundsIntersect(banner1Bounds, popupBounds) || MeasurementUtil.boundsIntersect(banner2Bounds, popupBounds)) {
                            //The bounds intersect, so place the popup near the bottom
                            popupBounds.top = maxY - this.$el.outerHeight() - verticalPadding + $("div.psd-preview-view").scrollTop();
                            popupBounds.bottom = popupBounds.top + this.$el.outerHeight();
                        }

                        //TODO - If the bounds intersect at the bottom as well we will need to search for an open space to put the popup
                    }
                }
                this.$el.show();
                this.$el.css({left: popupBounds.left, top: popupBounds.top});
            } else {
                notchElement.show();
                positionDiv.show();
                this.layerModel = params.layerModel;
                if (!this.layerModel || (this.layerModel.get("type") !== Constants.Type.LAYER_TEXT)) {
                    copyTextLink.addClass('disabled');
                    copyTextLink.attr("title", "");
                } else {
                    copyTextLink.removeClass('disabled');
                }
                if (!DWPSDExtractManager.canEnableDownloadAssets()) {
                    extractIcon.addClass('disabled');
                } else {
                    extractIcon.removeClass('disabled');
                }
                if (params.layerModel) {
                    var newSourceElement = LayerModelMap.getLayerInfoForId(params.layerModel.attributes.layerId).item;
                    if (this.sourceElement !== newSourceElement) {
                        this.sourceElement = newSourceElement;
                        bounds = MeasurementUtil.getVisibleBounds(params.layerModel, SelectionController.getPSDModel());
                        this.lastMeasuredBounds = _.clone(bounds);
                        this.layerBounds = ZoomController.zoomRect(bounds);

                        dimensionDiv.find(".width").text(bounds.right - bounds.left);
                        dimensionDiv.find(".height").text(bounds.bottom - bounds.top);
                        positionDiv.find(".x").text(bounds.left);
                        positionDiv.find(".y").text(bounds.top);

                        this.handleShow({sourceElement: $(this.sourceElement)});
                    }
                } else {
                    this.closePopup();
                    this.sourceElement = null;
                }

            }
        },
        
        handleShow: function (params) {
            BasePreviewPopupView.prototype.handleShow.apply(this, arguments);
            var extractIcon = this.$el.find(".measurementElementAssetExtract");
            if (DWPSDExtractManager.canEnableDownloadAssets()) {
                extractIcon.removeClass('disabled');
            } else {
                extractIcon.addClass('disabled');
            }
        },
        
        destroy: function () {
            this.remove();
            DWPopUpManager.setCSSPopupView(null);
        }
    });
    
    return DwMeasurementPopupView;
});