/* <copyright>
 This file contains proprietary software owned by Motorola Mobility, Inc.<br/>
 No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/>
 (c) Copyright 2011 Motorola Mobility, Inc.  All Rights Reserved.
 </copyright> */

var Montage = require("montage/core/core").Montage,
    Component = require("montage/ui/component").Component,
    Keyboard = require("js/mediators/keyboard-mediator").Keyboard;

exports.StylesViewDelegate = Montage.create(Component, {
    newClassPrefix      : { value: "new-class" },
    elementOutlineClass : { value: "nj-element-highlight" },

    stylesController : {
        get: function() {
            return this.application.ninja.stylesController;
        },
        set: function(){
            return;
        }
    },

    ///// Selector Actions
    //// -------------------------------------

    ///// Show the targeted elements in the document by applying a class
    ///// temporarily
    handleSelectorHover : {
        value: function(selector, direction) {
            if(!selector) { return false; }

            var elements = this.stylesController.currentDocument.model.views.design.document.querySelectorAll(selector),
                method = (direction === "out") ? "remove" : "add";

            Array.prototype.slice.call(elements).forEach(function(el) {
                el.classList[method](this.elementOutlineClass);
            }, this);
        }
    },

    ///// Apply new selector to the rule
    //// Verify that it applies to the selected elements
    //// Remove rule if the selector is deleted
    handleSelectorChange : {
        value: function(rule, newSelector, ruleComponent) {
            if(newSelector === "") {
                ruleComponent.parentComponent.removeRule(ruleComponent);
                this.stylesController.deleteRule(rule);
                ///// Remove the hover style
                this.handleSelectorHover(rule.selectorText, 'out');
                this._dispatchChange();
                return false;
            }

            if(ruleComponent.addClassNameOnChange) {
                var lastClass = this._getClassNameFromSelector(newSelector);

                if(lastClass) {
                    ///// Add the generated class to each element in selection
                    ///// and check whether it applies to the element
                    this.ruleListContainer.displayedList.selection.forEach(function(el) {
                        this.stylesController.addClass(el, lastClass);
                    },this);
                }
                ruleComponent.addClassNameOnChange = false;
            }

            rule.selectorText = newSelector;

            ruleComponent.applied = this.ruleListContainer.displayedList.selection.every(function(el) {
                return this._doesSelectorTargetElement(newSelector, el);
            }, this);

            this._dispatchChange();
        }
    },

    handleSelectorStop : {
        value: function(rule, newSelector, ruleComponent) {
            ruleComponent.declarationComponent.repetition.childComponents[0].propertyField.start()
        }
    },

    _getClassNameFromSelector : {
        value: function(selectorText) {
            var results = /.*\.([A-Za-z0-9_-]+)\:?[A-Za-z0-9_"=-]*$/.exec(selectorText);
            return (results) ? results[1] : null;
        }
    },

    ///// Returns true if the passed-in selector targets the passed-in element
    _doesSelectorTargetElement : {
        value: function doesSelectorTargetElement(selector, element) {
            var doc = element.ownerDocument,
                matchingEls = Array.prototype.slice.call(doc.querySelectorAll(selector));
            return matchingEls.indexOf(element) !== -1;
        }
    },

    ///// Style event handlers
    //// -------------------------------------

    ///// Enable/Disable Style when checkbox is clicked
    handleStyleToggle : {
        value: function(rule, enable, style) {
            if(enable) {
                this.stylesController.setStyle(rule, style.propertyText, style.browserValue, style.priority);
            } else {
                this.stylesController.deleteStyle(rule, style.propertyText);
            }

            this._dispatchChange();
        }
    },

    handlePropertyStop: {
        value: function(e, style) {
            var key, nextFocus;

            if(e._event.detail.type === 'keydown' && !style.deleting) {
                key = e._event.detail.keyCode;

                if(key === Keyboard.ENTER || key === Keyboard.TAB) {
                    e._event.detail.preventDefault();

                    if(e._event.detail.shiftKey) {
                        nextFocus = style.getSiblingStyle('prev') || style.getSiblingStyle('last');
                        nextFocus.valueField.start();
                    } else {
                        style.valueField.start();
                    }
                }
            }
        }
    },
    handleValueStop: {
        value: function(e, style) {
            var key, nextFocus;

            if(e._event.detail.type === 'keydown' && !style.deleting) {
                key = e._event.detail.keyCode;

                if(key === Keyboard.ENTER || key === Keyboard.TAB) {
                    e._event.detail.preventDefault();

                    if(e._event.detail.shiftKey) {
                        style.propertyField.start();
                    } else {

                        nextFocus = style.getSiblingStyle('next');
                        if(nextFocus) {
                            nextFocus.propertyField.start();
                        } else if(style.dirty) {
                            style.parentComponent.parentComponent.addNewStyle(true);
                            style.editingNewStyle = false;
                            setTimeout(function() {
                                style.getSiblingStyle('next').propertyField.start();
                            }, 50);
                        }
                    }
                }
            }
        }
    },
    handlePropertyChange : {
        value: function(rule, property, value, oldProperty, style) {
            var browserValue;

            if(style.editingNewStyle) {
                if(property === '') {
                    style.propertyField.value = 'property';
                    style.propertyField.isDirty = false;
                    style.editingNewStyle = false;
                }
                return false;
            }

            ///// Remove old property
            this.stylesController.deleteStyle(rule, oldProperty);

            if(property === '') {
                style.deleting = true;
                style.parentComponent.parentComponent.removeStyle(style.source);
                this._dispatchChange(oldProperty, browserValue);
                return false;
            }

            // now add new property
            browserValue = this.stylesController.setStyle(rule, property, value);

            ///// Mark style as invalid if the browser doesn't accept it
            style.invalid = (browserValue === null);

            this._dispatchChange(property, browserValue);
        }
    },
    handleValueChange : {
        value: function(rule, property, value, style) {
            var browserValue, units;

            if(value === '') {
                ///// Remove old property
                style.deleting = true;
                this.stylesController.deleteStyle(rule, property);
                style.parentComponent.parentComponent.removeStyle(style.source);
                this._dispatchChange(property, browserValue);
                return false;
            }

            ///// update value
            browserValue = this.stylesController.setStyle(rule, property, value);
            style.browserValue = browserValue;

            ///// Mark style as invalid if the browser doesn't accept it
            style.invalid = (browserValue === null);

            this._dispatchChange(property, browserValue);
        }
    },

    handlePaste : {
        value: function(e) {
//            var text = document.execCommand('insertHTML', null, e._event.clipboardData.getData("Text")).trim();
//
//            if(text.matches(/([a-zA-Z-]+:[a-zA-Z-]+){,1}/)) {
//
//            }
        }
    },

    /// Toolbar Button Actions
    /// -----------------------

    ///// Add rule button action
    handleAddAction : {
        value: function(e) {
            var selector,
                newRule,
                applies = true;

            ///// Get selection prefix
            if(this.ruleListContainer.displayedList.selection.length > 1) {
                selector = this.stylesController.generateClassName(null, true);
            } else {
                selector = this.stylesController.generateClassName(this.newClassPrefix);
            }

            ///// Create the rule with generated selector
            newRule = this.application.ninja.stylesController.addRule('.'+selector, ' { }');

            ///// Add rule directly to the rule list
            this.ruleListContainer.displayedList.component.addRule(newRule, null, applies, function(ruleComponent) {
                var rC = ruleComponent;

                // TODO: use stop event to apply class to element
                rC.addClassNameOnChange = true;

                setTimeout(function() {
                    rC.selectorField.start();
                    rC.selectorField._preEditValue = "";
                },50);

            });

        }
    },

    ///// Show/hide computed style sub panel
    handleComputedAction : {
        value: function(e) {
            var container = this.ownerComponent,
                panelToShow = (container.contentPanel === "computed") ? "rules" : "computed";

            ///// Handle showing and hiding of the add button
            if(panelToShow === "computed") {
                container.toolbar.hideButton('add');
            } else {
                container.toolbar.showButton('add');
            }

            container.contentPanel = panelToShow;
            container.handleSelectionChange();
        }
    },

    ///// Utilities
    //// -------------------------------------

    _dispatchChange : {
        value: function(property, value) {
            this.application.ninja.stage.updatedStage = true;
            NJevent('elementChange', {
                type : 'cssChange',
                data: {
                    "prop": property,
                    "value": value
                },
                redraw: null
            });
        }
    }
});