/* <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, {
    arrayController: {
        value: null
    },

    styleComponent: {
        value: null
    },

    repetition: {
        value: null
    },

    cssText : { value: null },
    focusDelegate : { value: null },
    needsSort : { 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;
            }

            return 0;
            ///// 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 = this.filterShorthands(Array.prototype.slice.call(dec));
            stylesArray.forEach(function(prop, index) {
                this.styles.push({
                    name: prop,
                    value: dec.getPropertyValue(prop),
                    isEmpty: false
                });
            }, this);

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

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

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

            var stylesCopy = styles.map(function(style) {
                return style;
            });

            stylesCopy.forEach(function(property, index) {
                var shorthands = ShorthandProps.CSS_SHORTHAND_MAP[property];
                if(shorthands) {
                    subProps = ShorthandProps.CSS_SHORTHAND_TO_SUBPROP_MAP[shorthands[0]];

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

                    if(hasAll) {
                        for(var i = subProps.length-1; i>=0; i--) {
                            styles.splice(styles.indexOf(subProps[i]), 1);
                        }
                        shorthandsToAdd.push(shorthands[0]);
                    }

                    return true;
                }
            }, 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 styleObjectIndex = styleToIndexMap[prop];

                    ///// Style component exists for property
                    ///// Update its value
                    if(styleObjectIndex !== undefined) {
                        this.styles[styleObjectIndex].value = this.declaration.getPropertyValue(prop);
                        usedIndices.push(styleObjectIndex);
                    } 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);
                                    usedIndices.push(shorthandIndex);
                                    shorthandUpdated = true;
                                }
                            }, this);
                        }

                        if(!shorthandUpdated) {
                            //// push to usedIndices so we don't remove styles we just added
                            usedIndices.push(this.styles.length);
                            this.addStyle(prop, this.declaration.getPropertyValue(prop));
                        }
                    }
                }, this);

                for(var i = this.styles.length-1; i>=0; i--) {
                    if(usedIndices.indexOf(i) === -1) {
                        if(!this.styles[i].isEmpty) {
                            ///// index not used, remove style
                            this.removeStyle(this.styles[i]);
                        }
                    }
                }

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

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

    addNewStyle : {
        value: function(preventAnimation) {
            if(preventAnimation) {
                this.element.classList.add('css-animation-prevent');

                setTimeout(function() {
                    this.element.classList.remove('css-animation-prevent');
                }.bind(this), 1000);
            }

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

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

            //this.styles.push(styleDescriptor);
            this.arrayController.addObjects(styleDescriptor);

            this.needsSort = this.needsDraw = true;
        }
    },
    removeStyle : {
        value: function(styleDescriptor) {
            var styleDescriptorIndex = this.styles.indexOf(styleDescriptor);
            //this.styles.splice(styleDescriptorIndex, 1);
            this.arrayController.removeObjects(styleDescriptor);

            //this.needsDraw = true;
        }
    },

    /* 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);
        }
    },

    willDraw : {
        value: function() {
            if(this.needsSort) {
                //this.arrayController.organizeObjects();
                this.needsSort = 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;
        }
    }
});