/* <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,
    ShorthandProps = require("js/panels/CSSPanel/css-shorthand-map");

exports.StyleDeclaration = Montage.create(Component, {
    cssText : { value: null },
    focusDelegate : { value: null },

    includeEmptyStyle : {
        value: true,
        distinct: true
    },
    styles : {
        value: [],
        distinct: true
    },

    _styleSortFunction : {
        value: function(styleA, styleB) {
            ///// If the style is an empty style (with Add button)
            ///// push to end of declaration
            if(styleA.isEmpty) {
                return 1;
            } else if (styleB.isEmpty) {
                return -1;
            }

            ///// Alphabetic sort based on property name
            if (styleA.name < styleB.name) {
                return -1;
            } else if (styleA.name > styleB.name) {
                return 1;
            } else {
                return 0;
            }
        }
    },
    _styleFilterFunction: {
        value: function(style, styleArray) {
            var shorthands = ShorthandProps.CSS_SHORTHAND_MAP[style.name];

            ///// No shorthands, return true to include style
            if(!shorthands) { return true; }

            var subProps = ShorthandProps.CSS_SHORTHAND_TO_SUBPROP_MAP[shorthands[0]],
                stylesArray = styleArray,
                hasAll;

            debugger;
            hasAll = subProps.every(function(subProp) {
                debugger;
                return this.declaration[subProp];
            }, this);

            if(hasAll) {
                return false;
            }
        }
    },

    _declaration: {
        value: null
    },
    declaration: {
        get: function() {
            return this._declaration;
        },
        set: function(dec) {
            var stylesArray;

            if(this._declaration) {
                this.styles = null;
                this.styles = [];
            }

            ///// Take snapshot of declaration
            this.cssText = dec.cssText;

            stylesArray = Array.prototype.slice.call(dec);

            if(this.includeEmptyStyle) {
                this.styles.push({
                    name    : "property",
                    value   : "value",
                    isEmpty : true
                });
            }

            stylesArray.forEach(function(prop, index) {
                this.styles.push({
                    name: prop,
                    value: dec.getPropertyValue(prop)
                });
            }, this);

            this._declaration = dec;
            this.needsDraw = true;
        }
    },

    styleShorthander : {
        value: function(styles) {
            var shorthandsToAdd = [],
                subProps, hasAll;

            styles.forEach(function(property, index, styleArray) {
                var shorthands = ShorthandProps.CSS_SHORTHAND_MAP[property];

                if(!shorthands) { return false; }

                var subProps = ShorthandProps.CSS_SHORTHAND_TO_SUBPROP_MAP[shorthands[0]],
                    stylesArray = styleArray;

                hasAll = subProps.every(function(subProp) {
                    return stylesArray.indexOf(subProp) !== -1;
                });

                if(hasAll) {
                    subProps.forEach(function(subProp) {
                        stylesArray.splice(stylesArray.indexOf(subProp), 1);
                    }, this);
                    shorthandsToAdd.push(shorthands[0]);
                }
            }, this);

            return styles.concat(shorthandsToAdd);
        }
    },

    _getStyleToIndexMap : {
        value: function() {
            var map = {};

            for(var i = 0; i<this.styles.length; i++) {
                map[this.styles[i].name] = i;
            }

            return map;
        }
    },

    update : {
        value: function() {
            if(this.declaration.cssText !== this.cssText) {
                var usedIndices = [],
                    styleToIndexMap = this._getStyleToIndexMap();

                Array.prototype.slice.call(this.declaration).forEach(function(prop, index) {
                    var i = styleToIndexMap[prop];

                    ///// Style component exists for property
                    ///// Update its value
                    if(i) {
                        this.styles[i].value = this.declaration.getPropertyValue(prop);
                        usedIndices.push(i);
                    } else {
                        //// styles doesn't exist, does shorthand?
                        var shorthands = ShorthandProps.CSS_SHORTHAND_MAP[prop],
                            shorthandUpdated = false;

                        if(shorthands) {
                            shorthands.forEach(function(shorthand) {
                                var shorthandIndex = styleToIndexMap[shorthand];
                                if(shorthandIndex) {
                                    //// if shorthand exists in list of rendered styles
                                    //// update it
                                    this.styles[shorthandIndex].value = this.declaration.getPropertyValue(shorthand);
                                    shorthandUpdated = true;
                                }
                            }, this);
                        }

                        if(!shorthandUpdated) {
                            this.addStyle(prop, this.declaration.getPropertyValue(prop));
                        }
                    }
                }, this);

                ///// Keep copy of cssText to know when we need to
                ///// update the view
                this.cssText = this.declaration.cssText;
                this.needsDraw = true;
            }
        }
    },

    styleTree : {
        value: {
            "properties" : []
        },
        distinct: true
    },

    addNewStyle : {
        value: function() {
            this.addStyle('property', 'value', {
                isEmpty : true
            });
        }
    },
    addStyle : {
        value: function(property, value, data) {
            var styleDescriptor = {
                property : property,
                value : value
            }, prop;

            for(prop in data) {
                if(data.hasOwnProperty(prop)) {
                    styleDescriptor[prop] = data[prop];
                }
            }

            this.arrayController.addObjects(styleDescriptor);
        }
    },

    /* drag/drop events */
    handleDrop : {
        value: function(e) {
            console.log('dropped');
        }
    },
    handleDragenter : {
        value: function(e) {
            console.log("dec - drag enter");
            this.element.classList.add("drag-over");
        }
    },
    handleDragleave : {
        value: function(e) {
            if(this.element === e._event.toElement || this._containsElement(e._event.toElement)) {
                //// Dragged-over element is inside of component element
                //// I.e. it's not really a "drag leave"
                e.stopPropagation();
                e.preventDefault();
                return false;
            }

            console.log("DECLARATION - ELEMENT NOT IN DEC", e._event.toElement);

            //console.log("dec - drag leave");
            this.element.classList.remove("drag-over");
        }
    },

    templateDidLoad : {
        value: function() {
            if(this.focusDelegate) {
                this.styleComponent.delegate = this.focusDelegate;
            }
            this.arrayController.sortFunction = this._styleSortFunction;
        }
    },

    prepareForDraw : {
        value: function(e) {
            this._element.addEventListener('drop', this, false);
            this.element.addEventListener('dragenter', this, false);
            this.element.addEventListener('dragleave', this, false);
        }
    },

    _containsElement : {
        value: function(innerElement) {
            var isInComponent = false,
                parent = innerElement.parentNode;

            while (parent !== document) {
                if(parent === this.element) {
                    isInComponent = true;
                    break;
                }
                parent = parent.parentNode;
            }

            return isInComponent;
        }
    }
});