/* <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;
var Component = require("montage/ui/component").Component;
var Collapser = require("js/panels/Timeline/Collapser").Collapser;
var Hintable = require("js/components/hintable.reel").Hintable;
var LayerStyle = require("js/panels/Timeline/Style.reel").LayerStyle;
var DynamicText = require("montage/ui/dynamic-text.reel").DynamicText;
var defaultEventManager = require("montage/core/event/event-manager").defaultEventManager;
var nj = require("js/lib/NJUtils").NJUtils;

var Layer = exports.Layer = Montage.create(Component, {

    hasTemplate:{
        value: true
    },
    
    /* Begin: Models */
   
	/* Main collapser model: the main collapser for the layer */
    _mainCollapser : {
    	value: false
    },
    mainCollapser: {
    	get: function() {
    		return this._mainCollapser;
    	},
    	set: function(newVal) {
    		this._mainCollapser = newVal;
    	}
    },
    
    /* Style models: the array of styles, and the repetition that uses them */
    _arrLayerStyles : {
	    value: []
    },
    arrLayerStyles : {
    	serializable: true,
    	get: function() {
    		return this._arrLayerStyles;
    	},
    	set: function(newVal) {
    		this._arrLayerStyles = newVal;
    	}
    },
    _styleRepetition : {
    	value: false
    },
    styleRepetition : {
    	get: function() {
    		return this._styleRepetition;
    	},
    	set: function(newVal) {
    		this._styleRepetition = newVal;
    	}
    },
    _styleCounter : {
    	value: 0
    },

	/* Layer models: the name, ID, and selected and animation booleans for the layer */
    _layerName:{
    	value: "Default Layer Name"
    },
    
    layerName:{
    	serializable: true,
        get:function(){
            return this._layerName;
        },
        set:function(newVal){

			this._layerEditable.value = newVal;
	    	this._layerName = newVal;
	    	this.layerData.layerName = newVal;
	    	if (typeof(this.dynamicLayerName) !== "undefined") {
	    		this.dynamicLayerName.value = newVal;
	    	}
        }
    },
    _layerID:{
    	value: "Default Layer ID"
    },

    layerID:{
    	serializable: true,
        get:function(){
            return this._layerID;
        },
        set:function(value){
            this._layerID = value;
            this.layerData.layerID = value;
        }
    },
    _layerTag:{
    	value: "tag"
    },
    
    layerTag:{
    	serializable: true,
        get:function(){
            return this._layerTag;
        },
        set:function(newVal){
	    	this._layerTag = newVal;
	    	this.layerData.layerTag = newVal;
        }
    },
    _docUUID : {
    	value: null
    },
    docUUID : {
    	serializable: true,
    	get: function() {
    		return this._docUUID;
    	},
    	set: function(newVal) {
    		this._docUUID = newVal;
    	}
    },
    
    
    _elementsList : {
    	value: []
    },
    elementsList : {
    	serializable: true,
    	get: function() {
    		return this._elementsList;
    	},
    	set: function(newVal) {
    		this._elementsList = newVal;
    	}
    },
    
    /* Position and Transform hottext values */
    _dtextPositionX : {
        value:null
    },

    dtextPositionX:{
    	serializable: true,
        get:function(){
            return this._dtextPositionX;
        },
        set:function(value){
        	if (this._dtextPositionX !== value) {
        		this._dtextPositionX = value;
        		this.layerData.dtextPositionX = value;
        	}
            
        }
    },
    
    _dtextPositionY : {
        value:null
    },

    dtextPositionY:{
    	serializable: true,
        get:function(){
            return this._dtextPositionY;
        },
        set:function(value){
        	if (this._dtextPositionY !== value) {
        		this._dtextPositionY = value;
        		this.layerData.dtextPositionY = value;
        	}
            
        }
    },
    
    _dtextScaleX : {
        value:null
    },

    dtextScaleX:{
    	serializable: true,
        get:function(){
            return this._dtextScaleX;
        },
        set:function(value){
        	if (this._dtextScaleX !== value) {
        		this._dtextScaleX = value;
        		this.layerData.dtextScaleX = value;
        	}
            
        }
    },
    
    _dtextScaleY : {
        value:null
    },

    dtextScaleY:{
    	serializable: true,
        get:function(){
            return this._dtextScaleY;
        },
        set:function(value){
        	if (this._dtextScaleY !== value) {
        		this._dtextScaleY = value;
        		this.layerData.dtextScaleY = value;
        	}
            
        }
    },
    
    _dtextSkewX : {
        value:null
    },

    dtextSkewX:{
    	serializable: true,
        get:function(){
            return this._dtextSkewX;
        },
        set:function(value){
        	if (this._dtextSkewX !== value) {
        		this._dtextSkewX = value;
        		this.layerData.dtextSkewX = value;
        	}
            
        }
    },
    
    _dtextSkewY : {
        value:null
    },

    dtextSkewY:{
    	serializable: true,
        get:function(){
            return this._dtextSkewY;
        },
        set:function(value){
        	if (this._dtextSkewY !== value) {
        		this._dtextSkewY = value;
        		this.layerData.dtextSkewY = value;
        	}
            
        }
    },
    
    _dtextRotate : {
        value:null
    },

    dtextRotate:{
    	serializable: true,
        get:function(){
            return this._dtextRotate;
        },
        set:function(value){
        	if (this._dtextRotate !== value) {
        		this._dtextRotate = value;
        		this.layerData.dtextRotate = value;
        	}
            
        }
    },
    
    /* isSelected: whether or not the layer is currently selected. */
    _isSelected:{
        value: false
    },

    isSelected:{
        get:function(){
            return this._isSelected;
        },
        set:function(value){
        	if (value !== this._isSelected) {
        		// Only concerned about different values
        		if (value === false) {
        			// If changing from true to false, we need to deselect any associated styles
        			this.selectStyle(false);
        		}
        		this._isSelected = value;
        		this.layerData.isSelected = value;
        		this.needsDraw = true;
        	}
            
        }
    },
    
    /* isActive:  Whether or not the user is actively clicking within the layer; used to communicate state with
     * TimelinePanel.
     */
    _isActive: {
    	value: false
    },
    isActive: {
    	get: function() {
    		return this._isActive;
    	},
    	set: function(newVal) {
    		this._isActive = newVal;
    		this.layerData.isActive = newVal;
    	}
    },
    
    
    _isAnimated:{
        value: false
    },

    isAnimated:{
        get:function(){
            return this._isAnimated;
        },
        set:function(value){
            this._isAnimated = value;
            this.layerData.isAnimated = value;
        }
    },
    _isVisible:{
        value: true
    },

    isVisible:{
        get:function(){
            return this._isVisible;
        },
        set:function(value){
        	if (this._isVisible !== value) {
        		this._isVisible = value;
        		if (value === true) {
        			this.element.classList.remove("layer-hidden");
        		} else {
        			this.element.classList.add("layer-hidden");
        		}
        	}
        	this.layerData.isVisible = value;
        }
    },
    
    _justAdded: {
    	value: false
    },
    _layerEditable : {
    	value: false
    },
    
    // Are the various collapsers collapsed or not
    _isMainCollapsed : {
    	value: true
    },
    isMainCollapsed : {
    	serializable: true,
    	get: function() {
    		return this._isMainCollapsed;
    	},
    	set: function(newVal) {
			this._isMainCollapsed = newVal;
			this.layerData.isMainCollapsed = newVal;

    	}
    },
    
    _isTransformCollapsed : {
    	value: true
    },
    isTransformCollapsed : {
    	serializable: true,
    	get: function() {
    		return this._isTransformCollapsed;
    	},
    	set: function(newVal) {
			this._isTransformCollapsed = newVal;
			this.layerData.isTransformCollapsed = newVal;
    	}
    },
    
    _isPositionCollapsed : {
    	value: true
    },
    isPositionCollapsed : {
    	serializable: true,
    	get: function() {
    		return this._isPositionCollapsed;
    	},
    	set: function(newVal) {
			this._isPositionCollapsed = newVal;
			this.layerData.isPositionCollapsed = newVal;
    	}
    },
    
    _isStyleCollapsed : {
    	value: true
    },
    isStyleCollapsed : {
    	serializable: true,
    	get: function() {
    		return this._isStyleCollapsed;
    	},
    	set: function(newVal) {
			this._isStyleCollapsed = newVal;
			this.layerData.isStyleCollapsed = newVal;
    	}
    },
    _bypassAnimation : {
    	value: false
    },
    bypassAnimation : {
    	serializable: true,
    	get: function() {
    		return this._bypassAnimation;
    	},
    	set: function(newVal) {
    		if (typeof(this.layerData) !== "undefined") {
	    		this._bypassAnimation = newVal;
	    		this.layerData.bypassAnimation = newVal;	
    		}
    	}
    },
    
    // Is this the first draw?
    _isFirstDraw : {
    	value: true
    },

    _layerData:{
        value:{}
    },

    layerData:{
        get:function(){
            return this._layerData;
        },
        set:function(val){
            this._layerData = val;
            if(this._layerData){
                this.setData(true);
            }
        }
    },

    setData:{
        value:function(boolNeedsDraw){
        	if (typeof(this._layerData) === "undefined")  {
        		return;
        	} 
        	
        	if (typeof(this._layerData.layerName) === "undefined") {
        		return;
        	}
        	
        	if (typeof(boolNeedsDraw) === "undefined") {
        		boolNeedsDraw = false;
        	}
        	
            this.layerName = this.layerData.layerName;
            this.layerID = this.layerData.layerID;
            this.arrLayerStyles = this.layerData.arrLayerStyles;
            this.isMainCollapsed = this.layerData.isMainCollapsed;
            this.isPositionCollapsed = this.layerData.isPositionCollapsed;
            this.isTransformCollapsed = this.layerData.isTransformCollapsed;
            this.isSelected = this.layerData.isSelected;
            this.isActive = this.layerData.isActive;
            this.isStyleCollapsed = this.layerData.isStyleCollapsed;
            this.bypassAnimation = this.layerData.bypassAnimation;
            this.dtextPositionX = this.layerData.dtextPositionX;
            this.dtextPositionY = this.layerData.dtextPositionY;
            this.dtextSkewX = this.layerData.dtextSkewX;
            this.dtextSkewY = this.layerData.dtextSkewY;
            this.dtextScaleX = this.layerData.dtextScaleX;
            this.dtextScaleY = this.layerData.dtextScaleY;
            this.dtextRotate = this.layerData.dtextRotate;
            this._isFirstDraw = this.layerData._isFirstDraw;
            this.layerTag = this.layerData.layerTag;
            this.isVisible = this.layerData.isVisible;
            this.isAnimated = this.layerData.isAnimated;
            this.docUUID = this.layerData.docUUID;
            this.needsDraw = boolNeedsDraw;
        }
    },
    
    /* Data binding point and outgoing binding trigger method */
    _bindingPoint : {
    	value : {}
    },
    bindingPoint: {
    	get: function() {
    		return this._bindingPoint;
    	},
    	set: function(newVal) {
    		if (newVal !== this._bindingPoint) {
	    		this._bindingPoint = newVal;
	    		this.setData(true);
    		}
    	}
    },
    
    triggerOutgoingBinding : {
    	value: function() {
    		if (this.layerData.triggerBinding === true) {
    			this.layerData.triggerBinding = false;
    		} else {
    			this.layerData.triggerBinding = true;
    		}
    	}
    },
	/* END: Models */

	/* Begin: Draw cycle */
    prepareForDraw: {
        value: function() {
        	
        	// Initialize myself
			this.init();
			
        	// Make it editable!
        	this._layerEditable = Hintable.create();
        	this._layerEditable.element = this.titleSelector;
        	this.titleSelector.identifier = "selectorEditable";
        	this.titleSelector.addEventListener("click", this, false);
        	this._layerEditable.addEventListener("blur", this.handleSelectorEditableBlur.bind(this), false);
        	this._layerEditable.addEventListener("change", this.handleLayerNameChange.bind(this), false);
        	this._layerEditable.editingClass = "editable2";
        	this._layerEditable.value = this.layerName;
        	
        	// Collapser event handlers.
            this.mainCollapser.clicker.addEventListener("click", this.handleMainCollapserClick.bind(this), false);
            this.positionCollapser.clicker.addEventListener("click", this.handlePositionCollapserClick.bind(this), false);
            this.transformCollapser.clicker.addEventListener("click", this.handleTransformCollapserClick.bind(this), false);
            this.styleCollapser.clicker.addEventListener("click", this.handleStyleCollapserClick.bind(this), false);

            // Add event listeners to add and delete style buttons
            this.buttonAddStyle.addEventListener("click", this.handleAddStyleClick.bind(this), false);
            this.buttonDeleteStyle.addEventListener("click", this.handleDeleteStyleClick.bind(this), false);
            
            // Add mousedown listener to set isActive
            this.element.addEventListener("mousedown", this, false);
            this.element.addEventListener("click", this, false);
            
			// Drag and drop event handlers
			this.myLabel.addEventListener("mouseover", this.handleMouseover.bind(this), false);
			this.myLabel.addEventListener("mouseout", this.handleMouseout.bind(this), false);
			this.element.addEventListener("dragover", this.handleDragover.bind(this), false);
			this.element.addEventListener("dragleave", this.handleDragleave.bind(this), false);
			this.element.addEventListener("dragstart", this.handleDragstart.bind(this), false);
			this.element.addEventListener("drop", this.handleDrop.bind(this), false);
        }
    },
    draw: {
    	value: function() {
            if (this.isSelected) {
            	this.element.classList.add("selected");
            } else {
            	this.element.classList.remove("selected");
            }
    	}
    },
    didDraw: {
    	value: function() {
    		// console.log("Layer.didDraw: Layer "+ this.layerID );
    		if (this._isFirstDraw === true) {
    			if (this.isSelected === true) {
    				if (this.application.ninja.currentDocument._uuid === this._docUUID) {
		    			// Once we're done drawing the first time we need to tell the TimelinePanel if
		    			// this layer is supposed to be selected.
		    			//console.log('layerName ' +  this.layerName);
		    			this.parentComponent.parentComponent.selectedLayerID = this.layerID;
					}
    			}
    			this._isFirstDraw = false;
    			this.layerData._isFirstDraw = false;
    		}
    	}
    },
	/* End: Draw cycle */
	
	/* Begin: Controllers */
	
	// Initialize a just-created layer
	init: {
		value: function() {
			// Get some selectors.
        	this.label = this.element.querySelector(".label-layer");
        	this.titleSelector = this.label.querySelector(".collapsible-label");
        	this.buttonAddStyle = this.element.querySelector(".button-add");
        	this.buttonDeleteStyle = this.element.querySelector(".button-delete");
		}
	},
	addStyle : {
		value: function() {
			// Add a new style rule.  It should be added above the currently selected rule, 
			// Or at the end, if no rule is selected.

			var newLength = 0, 
				mySelection = 0,
				// newStyle = LayerStyle.create(),
				newStyle = {},
				newEvent = document.createEvent("CustomEvent");
			
			this.isStyleCollapsed = false;
			this.layerData.isStyleCollapsed = false;
			this.triggerOutgoingBinding();
			
			newEvent.initCustomEvent("layerEvent", false, true);
			newEvent.layerEventLocale = "styles";
			newEvent.layerEventType = "newStyle";
			newEvent.layerID = this.layerID;
			newEvent.styleID = this.layerID + "@" + this._styleCounter;
			
			newStyle.styleID = newEvent.styleID;
			newStyle.whichView = "hintable";
			newStyle.editorProperty = "";
			newStyle.editorValue = "";
			newStyle.ruleTweener = false;
			newStyle.isSelected = false;

			if (!!this.styleRepetition.selectedIndexes) {
				mySelection = this.styleRepetition.selectedIndexes[0];
				this.arrLayerStyles.splice(mySelection, 0, newStyle);
				//this.styleRepetition.selectedIndexes = [mySelection];
				this.selectStyle(mySelection);
			} else {
				newLength = this.arrLayerStyles.length;
				this.arrLayerStyles.push(newStyle);
				mySelection = this.arrLayerStyles.length;
				// this.styleRepetition.selectedIndexes = [mySelection-1];
				this.selectStyle(mySelection-1);
			}
			
			// Set up the event info and dispatch the event

			newEvent.styleSelection = mySelection;
			defaultEventManager.dispatchEvent(newEvent);


		}
	},
	deleteStyle : {
		value: function() {
			var newEvent = document.createEvent("CustomEvent"),
				selectedIndex = 0;
			if (this.arrLayerStyles.length > 0) {
				if (!!this.styleRepetition.selectedIndexes) {
					
					selectedIndex = this.styleRepetition.selectedIndexes[0];

					// Set up the event info and dispatch the event
					newEvent.initCustomEvent("layerEvent", false, true);
					newEvent.layerEventLocale = "styles";
					newEvent.layerEventType = "deleteStyle";
					newEvent.layerID = this.layerID;
					newEvent.styleID = this.arrLayerStyles[selectedIndex].styleID;
					newEvent.styleSelection = selectedIndex;
					defaultEventManager.dispatchEvent(newEvent);
					
					// Delete the style from the view
					this.arrLayerStyles.splice(selectedIndex, 1);
					
					// Was that the last style?
					if (this.arrLayerStyles.length === 0) {
						this.buttonDeleteStyle.classList.add("disabled");
					}
					
				}
			}
		}
	},
	selectStyle : {
		value: function(styleIndex) {

    		// Select a style based on its index.
    		// use layerIndex = false to deselect all styles.
    		var i = 0,
    			arrLayerStylesLength = this.arrLayerStyles.length;

    		// First, update this.arrStyles[].isSelected
    		for (i = 0; i < arrLayerStylesLength; i++) {
    			if (i === styleIndex) {
    				this.arrLayerStyles[i].isSelected = true;
    			} else {
    				this.arrLayerStyles[i].isSelected = false;
    			}
    		}
    		
    		// Next, update this.styleRepetition.selectedIndexes.
    		if (styleIndex !== false) {
    			this.styleRepetition.selectedIndexes = [styleIndex];
    			this.buttonDeleteStyle.classList.remove("disabled");
    		} else {
    			this.styleRepetition.selectedIndexes = null;
    			if (typeof(this.buttonDeleteStyle) !== "undefined") {
    				this.buttonDeleteStyle.classList.add("disabled");
    			}
    		}
			
		}
	},
    getActiveStyleIndex : {
    	value: function() {
    		// Searches through the styles and looks for one that has
    		// set its isActive flag to true.
    		var i = 0, 
    			returnVal = false,
    			arrLayerStylesLength = this.arrLayerStyles.length;
    		
    		for (i = 0; i < arrLayerStylesLength; i++) {
    			if (this.arrLayerStyles[i].isActive === true) {
    				returnVal = i;
    				this.arrLayerStyles[i].isActive = false;
    			}
    		}
    		return returnVal;
    	}
    },
	/* End: Controllers */
    
	/* Begin: Event handlers */
	handleLayerNameChange: {
		value: function(event) {		
			this.dynamicLayerName.value = this._layerEditable.value;
			this.application.ninja.timeline.currentLayerSelected.layerData.elementsList[0].dataset.storedLayerName = this.dynamicLayerName.value;
			this.needsDraw = true;
			this.application.ninja.documentController.activeDocument.needsSave = true;
		}
	},
	handleAddStyleClick: {
		value: function(event) {
			this.addStyle();
		}
	},
	handleDeleteStyleClick: {
		value: function(event) {
			this.deleteStyle();
		}
	},
	handleSelectorEditableBlur : {
		value: function(event) {
        	this.titleSelector.scrollLeft = 0;
        	this.handleSelectorEditableChange(event);
		}
	},
	handleSelectorEditableChange: {
		value: function(event) {
			var newVal = this._layerEditable.enteredValue;
			if (this._layerEditable.enteredValue.length === 0) {
				newVal = this._layerEditable._preEditValue;
			}
			this.dynamicLayerName.value = newVal;
			this.layerName = newVal;
			this.application.ninja.timeline.currentLayerSelected.layerData.elementsList[0].dataset.storedLayerName = newVal;
			this.application.ninja.documentController.activeDocument.needsSave = true;
			this.needsDraw = true;
		}
	},
	handleMousedown: {
		value: function(event) {
			this.layerData.isActive = true;
			var ptrParent = nj.queryParentSelector(event.target, ".content-style");
			if (ptrParent !== false) {
				this.selectStyle(this.getActiveStyleIndex());
			}
		}
	},
	handleLayerClick : {
		value: function(event) {
			var ptrParent = nj.queryParentSelector(event.target, ".content-style");
			if (ptrParent !== false) {
				var myIndex = this.getActiveStyleIndex();
				this.selectStyle(myIndex);
			}
		}
	},
	handleMainCollapserClick : {
		value: function(event) {
			this.mainCollapser.bypassAnimation = false;
			this.bypassAnimation = false;
			this.layerData.bypassAnimation = false;
			if (this.isMainCollapsed) {
				this.isMainCollapsed = false;
			} else {
				this.isMainCollapsed = true;
			}
			this.triggerOutgoingBinding();
		}
	},
	handlePositionCollapserClick : {
		value: function(event) {
			this.positionCollapser.bypassAnimation = false;
			this.bypassAnimation = false;
			this.layerData.bypassAnimation = false;
			if (this.isPositionCollapsed) {
				this.isPositionCollapsed = false;
			} else {
				this.isPositionCollapsed = true;
			}
			this.triggerOutgoingBinding();
		}
	},
	handleTransformCollapserClick : {
		value: function(event) {
			this.transformCollapser.bypassAnimation = false;
			this.bypassAnimation = false;
			this.layerData.bypassAnimation = false;
			if (this.isTransformCollapsed) {
				this.isTransformCollapsed = false;
			} else {
				this.isTransformCollapsed = true;
			}
			this.triggerOutgoingBinding();
		}
	},
	handleStyleCollapserClick : {
		value: function(event) {
			this.styleCollapser.bypassAnimation = false;
			this.bypassAnimation = false;
			this.layerData.bypassAnimation = false;
			if (this.isStyleCollapsed) {
				this.isStyleCollapsed = false;
			} else {
				this.isStyleCollapsed = true;
			}
			this.triggerOutgoingBinding();
		}
	},
	handleMouseover: {
		value: function(event) {
			this.element.draggable = true;
		}
	},
	handleMouseout: {
		value: function(event) {
			this.element.draggable = false;
		}
	},
	handleDragenter: {
		value: function(event) {
		}
	},
	handleDragleave: {
		value: function(event) {
			this.element.classList.remove("dragOver");
		}
	},
	handleDragstart: {
		value: function(event) {
			this.parentComponent.parentComponent.dragLayerID = this.layerID;
            event.dataTransfer.setData('Text', 'Layer');
		}
	},
	handleDragover: {
		value: function(event) {
			event.preventDefault();
			this.element.classList.add("dragOver");
			event.dataTransfer.dropEffect = "move";
			return false;
		}
	},
	
	handleDrop : {
		value: function(event) {
			event.stopPropagation();
			this.element.classList.remove("dragOver");
			if (this.parentComponent.parentComponent.dragLayerID !== this.layerID) {
				this.parentComponent.parentComponent.dropLayerID = this.layerID;
			}
			return false;
		}
	},
	/* End: Event handlers */
	
	/* Begin: Logging routines */
    _boolDebug: {
    	enumerable: false,
    	value: false // set to true to enable debugging to console; false for turning off all debugging.
    },
    boolDebug: {
    	get: function() {
    		return this._boolDebug;
    	},
    	set: function(boolDebugSwitch) {
    		this._boolDebug = boolDebugSwitch;
    	}
    },
    log: {
    	value: function(strMessage) {
    		if (this.boolDebug) {
    			console.log(this.getLineNumber() + ": " + strMessage);
    		}
    	}
    },
    getLineNumber: {
    	value: function() {
			try {
			   throw new Error('bazinga')
			}catch(e){
				return e.stack.split("at")[3].split(":")[2];
			}
    	}
    }
	/* End: Logging routines */

});