/* <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 defaultEventManager = require("montage/core/event/event-manager").defaultEventManager;

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

    hasTemplate:{
        value:true
    },

    _trackID:{
        value:null
    },

    trackID:{
        serializable:true,
        get:function () {
            return this._trackID;
        },
        set:function (value) {
        	if (value !== this._trackID) {
        		this._trackID = value;
                this.trackData.layerID = value;
        	}
        }
    },
    _isVisible:{
        value: true
    },

    isVisible:{
        get:function(){
            return this._isVisible;
        },
        set:function(value){
        	if (this._isVisible !== value) {
        		this._isVisible = value;
        		if (this.element !== null) {
	        		if (value === true) {
	        			this.element.classList.remove("layer-hidden");
	        		} else {
	        			this.element.classList.add("layer-hidden");
	        		}
        		}
        	}
        	this.trackData.isVisible = value;
        }
    },

    // Are the various collapsers collapsed or not
    _isMainCollapsed:{
        value: true
    },
    isMainCollapsed:{
        get:function () {
            return this._isMainCollapsed;
        },
        set:function (newVal) {
            this._isMainCollapsed = newVal;
            this.trackData.isMainCollapsed = newVal;
        }
    },
    _isTransformCollapsed:{
        value:true
    },
    isTransformCollapsed:{
        get:function () {
            return this._isTransformCollapsed;
        },
        set:function (newVal) {
            this._isTransformCollapsed = newVal;
            this.trackData.isTransformCollapsed = newVal;
        }
    },
    _isPositionCollapsed:{
        value:true
    },
    isPositionCollapsed:{
        get:function () {
            return this._isPositionCollapsed;
        },
        set:function (newVal) {
            this._isPositionCollapsed = newVal;
            this.trackData.isPositionCollapsed = newVal;
        }
    },
    _isStyleCollapsed:{
        value:true
    },
    isStyleCollapsed:{
        get:function () {
            return this._isStyleCollapsed;
        },
        set:function (newVal) {
            this._isStyleCollapsed = newVal;
            this.trackData.isStyleCollapsed = newVal;
        }
    },
    _bypassAnimation : {
    	value: false
    },
    bypassAnimation : {
    	serializable: true,
    	get: function() {
    		return this._bypassAnimation;
    	},
    	set: function(newVal) {
    		if (typeof(this.trackData) !== "undefined") {
    			this._bypassAnimation = newVal;
                this.trackData.bypassAnimation = newVal;
    		}
    	}
    },
    
    _arrStyleTracks : {
    	value: []
    },
    arrStyleTracks: {
        serializable:true,
    	get: function() {
    		return this._arrStyleTracks;
    	},
    	set: function(newVal) {
    		this._arrStyleTracks = newVal;
            this.trackData.arrStyleTracks = newVal;
    	}
    },
    _styleTracksRepetition: {
    	value: null
    },
    styleTracksRepetition : {
    	get: function() {
    		return this._styleTracksRepetition;
    	},
    	set: function(newVal) {
    		this._styleTracksRepetition = newVal;
    	}
    },
    
    /* Position Property Tracks */
    _arrPositionTracks : {
    	value: []
    },
    arrPositionTracks: {
        serializable:true,
    	get: function() {
    		return this._arrPositionTracks;
    	},
    	set: function(newVal) {
    		this._arrPositionTracks = newVal;
            this.trackData.arrPositionTracks = newVal;
    	}
    },
    _positionTracksRepetition: {
    	value: null
    },
    positionTracksRepetition : {
    	get: function() {
    		return this._positionTracksRepetition;
    	},
    	set: function(newVal) {
    		this._positionTracksRepetition = newVal;
    	}
    },
    
    
    /* Transform Property Tracks */
    _arrTransformTracks : {
    	value: []
    },
    arrTransformTracks: {
        serializable:true,
    	get: function() {
    		return this._arrTransformTracks;
    	},
    	set: function(newVal) {
    		this._arrTransformTracks = newVal;
            this.trackData.arrTransformTracks = newVal;
    	}
    },
    _transformTracksRepetition: {
    	value: null
    },
    transformTracksRepetition : {
    	get: function() {
    		return this._transformTracksRepetition;
    	},
    	set: function(newVal) {
    		this._transformTracksRepetition = newVal;
    	}
    },

    _tweens:{
        value:[]
    },

    tweens:{
    	serializable: true,
        get:function () {
            return this._tweens;
        },
        set:function (newVal) {
            this._tweens = newVal;
            this.trackData.tweens = newVal;
        }
    },

    _tweenRepetition:{
        value:null
    },

    tweenRepetition:{
        get:function () {
            return this._spanRepetition;
        },
        set:function (newVal) {
            this._spanRepetition = newVal;
        }
    },

    _trackDuration:{
        value:0
    },

    trackDuration:{
        serializable:true,
        get:function () {
            return this._trackDuration;
        },
        set:function (val) {
            this._trackDuration = val;
            if(this._trackDuration > this.application.ninja.timeline.masterDuration){
                this.application.ninja.timeline.masterDuration = this._trackDuration;
            }
            this.trackData.trackDuration = val;
        }
    },

    _trackPosition:{
        value:0
    },

    trackPosition:{
        serializable:true,
        get:function () {
            return this._trackPosition;
        },
        set:function (val) {
            this._trackPosition = val;
            this.trackData.trackPosition = val;
        }
    },

    _currentKeyframeRule:{
        value:null
    },

    currentKeyframeRule:{
        serializable: true,
        get:function(){
            return this._currentKeyframeRule;
        },
        set:function(val){
            this._currentKeyframeRule = val;
            this.trackData.currentKeyframeRule = val;
        }
    },

    nextKeyframe:{
        value:1
    },

    currentMillisecClicked:{
        value:0
    },

    _isTrackAnimated:{
        value:null
    },

    isTrackAnimated:{
        serializable: true,
        get:function(){
            return this._isTrackAnimated;
        },
        set:function(val){
            this._isTrackAnimated = val;
            this.trackData.isTrackAnimated = val;
        }
    },

    // should be unneeded with one element per layer restriction
    _animatedElement:{
        value:null
    },
    animatedElement:{
        serializable:true,
        get:function () {
            return this._animatedElement;
        },
        set:function (val) {
            this._animatedElement = val;
            this.trackData.animatedElement = val;
        }
    },

    _animationName:{
        value:null
    },

    animationName:{
        serializable:true,
        get:function () {
            return this._animationName;
        },
        set:function (val) {
            this._animationName = val;
            this.trackData.animationName = val;
        }
    },

    ninjaStylesContoller:{
        value:null
    },

    _positionCollapser:{
        value:null
    },
    _mainCollapser:{
        value:null
    },
    _transformCollapser:{
        value:null
    },
    _styleCollapser:{
        value:null
    },

    _trackData:{
		value: false
    },

    trackData:{
        get:function(){
            return this._trackData;
        },
        set:function(val){
            this._trackData = val;
            if(this._trackData){
                 this.setData();
            }
        }
    },
    
    _setDataTimestamp : {
    	value: false
    },

    setData:{
        value:function(){
        	if (typeof(this.trackData) === "undefined") {
        		return;
        	}
            this.bypassAnimation = this.trackData.bypassAnimation;
            this.trackID = this.trackData.layerID;
            this.tweens = this.trackData.tweens;
            this.animatedElement = this.trackData.animatedElement; // unneeded with one element per layer restriction
            this.arrStyleTracks = this.trackData.arrStyleTracks;
            this.isTrackAnimated = this.trackData.isTrackAnimated;
            this.trackDuration = this.trackData.trackDuration;
            this.animationName = this.trackData.animationName;
            this.currentKeyframeRule = this.trackData.currentKeyframeRule;
            this.isMainCollapsed = this.trackData.isMainCollapsed;
            this.isPositionCollapsed = this.trackData.isPositionCollapsed;
            this.isTransformCollapsed = this.trackData.isTransformCollapsed;
            this.isStyleCollapsed = this.trackData.isStyleCollapsed;
            this.trackPosition = this.trackData.trackPosition;
            this.isVisible = this.trackData.isVisible;
            this.needsDraw = true;
        }
    },
    
    // Data binding observation point and trigger method
	_bindingPoint : {
    	value : {}
    },
    bindingPoint: {
    	get: function() {
    		return this._bindingPoint;
    	},
    	set: function(newVal) {
    		if (newVal !== this._bindingPoint) {
	    		this._bindingPoint = newVal;
	    		this.setData();
    		}
    	}
    },
    
    triggerOutgoingBinding : {
    	value: function() {
    		if (this.trackData.triggerBinding === true) {
    			this.trackData.triggerBinding = false;
    		} else {
    			this.trackData.triggerBinding = true;
    		}
    	}
    },

    prepareForDraw:{
        value:function () {
            this.init();
            this.ninjaStylesContoller = this.application.ninja.stylesController;
            this.element.addEventListener("click", this, false);
            this.eventManager.addEventListener("tlZoomSlider", this, false);
        }
    },

    draw:{
        value:function () {
            this.ninjaStylesContoller = this.application.ninja.stylesController;
            var selectedIndex = this.application.ninja.timeline.getLayerIndexByID(this.trackID);
            if (selectedIndex !== false) {
	            if(this.application.ninja.timeline.arrLayers[selectedIndex].layerData.elementsList[0]){
	                this.animatedElement = this.application.ninja.timeline.arrLayers[selectedIndex].layerData.elementsList[0];
	            }
            }

        }
    },

    didDraw:{
        value:function () {
            if ((!this.application.ninja.documentController.creatingNewFile)||(!this.application.ninja.currentDocument.setLevel)) {
                if (this.application.ninja.currentDocument.documentRoot.children[0]) {
                    var selectedIndex = this.application.ninja.timeline.getLayerIndexByID(this.trackID);
                    if (selectedIndex !== false) {
	                    if (!this.application.ninja.timeline.arrLayers[selectedIndex].layerData.created) {
	                        this.retrieveStoredTweens();

	                    }
                    }
                }
            }
        }
    },

	handleTlZoomSlider: {
		value: function(event) {
			
	        var currentMilliSecPerPixel , currentMilliSec , clickPos,thingToPush;
	        var i = 0,
	        	tweensLength = this.tweens.length;

	        for (i = 0; i < tweensLength; i++) {
	        	
	        	if (i === 0) {
					// Exception: 0th item does not depend on anything
					// TODO: If 0th tween is draggable, this will need to be fixed.
			        this.tweens[i].tweenData.spanWidth=0;
		            this.tweens[i].tweenData.spanPosition=0;
		            this.tweens[i].tweenData.keyFramePosition=0;
		            this.tweens[i].tweenData.keyFrameMillisec=0;
	
	        	} else {
					var prevKeyFramePosition = this.tweens[i - 1].tweenData.keyFramePosition,
						myObj = {},
						thing = {};

			        currentMilliSecPerPixel = Math.floor(this.application.ninja.timeline.millisecondsOffset / 80);
		            currentMilliSec = this.tweens[i].tweenData.keyFrameMillisec;
		            clickPos = currentMilliSec / currentMilliSecPerPixel;

		            for (thing in this.tweens[i].tweenData) {
		            	myObj[thing] = this.tweens[i].tweenData[thing];
		            }
					myObj.spanWidth = clickPos - prevKeyFramePosition;
		            myObj.keyFramePosition = clickPos;
		            myObj.spanPosition = clickPos - (clickPos - prevKeyFramePosition);

		            this.tweens[i].tweenData = myObj;
	        	}
	        	

	        }
		}
	},
    handleClick:{
        value:function (ev) {
            // TEMP - if the SHIFT key is down, add a new keyframe or split an existing span
            // This needs to move to a keyboard shortcut that is TBD
            var selectedIndex = this.application.ninja.timeline.getLayerIndexByID(this.trackID);
            if (ev.shiftKey) {
                if (this.application.ninja.timeline.arrLayers[selectedIndex].layerData.elementsList.length == 1) {
                    if (this.tweens.length < 1) {
                        this.insertTween(0);
                        this.addAnimationRuleToElement(ev);
                        this.updateKeyframeRule();
                    } else {
                        this.handleNewTween(ev);
                        this.updateKeyframeRule();
                    }
                } else {
                    console.log("There must be exactly one element in an animated layer.");
                }
            }
        }
    },

    handleNewTween:{
        value:function (ev) {
            if (ev.offsetX > this.tweens[this.tweens.length - 1].tweenData.keyFramePosition) {
                var selectedIndex = this.application.ninja.timeline.getLayerIndexByID(this.trackID);
                this.application.ninja.timeline.selectLayer(selectedIndex, false);
                this.insertTween(ev.offsetX);
            } else {
                this.splitTween(ev);
            }
        }
    },

    insertTween:{
        value:function (clickPos) {
            var selectedIndex = this.application.ninja.timeline.getLayerIndexByID(this.trackID);
                        this.application.ninja.timeline.selectLayer(selectedIndex, true);

            var currentMillisecPerPixel = Math.floor(this.application.ninja.timeline.millisecondsOffset / 80);
            var currentMillisec = currentMillisecPerPixel * clickPos;
            this.trackDuration = currentMillisec;
            var newTween = {};
            newTween.tweenData = {};

            if (clickPos == 0) {
                this.animatedElement = this.application.ninja.timeline.currentLayerSelected.layerData.elementsList[0];
                newTween.tweenData.spanWidth = 0;
                newTween.tweenData.keyFramePosition = 0;
                newTween.tweenData.keyFrameMillisec = 0;
                newTween.tweenData.tweenID = 0;
                newTween.tweenData.spanPosition = 0;
                newTween.tweenData.tweenedProperties = [];
                newTween.tweenData.tweenedProperties["top"] = this.animatedElement.offsetTop;
                newTween.tweenData.tweenedProperties["left"] = this.animatedElement.offsetLeft;
                newTween.tweenData.tweenedProperties["width"] = this.animatedElement.offsetWidth;
                newTween.tweenData.tweenedProperties["height"] = this.animatedElement.offsetHeight;
                this.tweens.push(newTween);
            } else {
                newTween.tweenData.spanWidth = clickPos - this.tweens[this.tweens.length - 1].tweenData.keyFramePosition;
                newTween.tweenData.keyFramePosition = clickPos;
                newTween.tweenData.keyFrameMillisec = currentMillisec;
                newTween.tweenData.tweenID = this.nextKeyframe;
                newTween.tweenData.spanPosition = clickPos - newTween.tweenData.spanWidth;
                newTween.tweenData.tweenedProperties = [];
                newTween.tweenData.tweenedProperties["top"] = this.animatedElement.offsetTop;
                newTween.tweenData.tweenedProperties["left"] = this.animatedElement.offsetLeft;
                newTween.tweenData.tweenedProperties["width"] = this.animatedElement.offsetWidth;
                newTween.tweenData.tweenedProperties["height"] = this.animatedElement.offsetHeight;
                this.tweens.push(newTween);

                // update the animation duration
                var animationDuration = (this.trackDuration / 1000) + "s";
                this.ninjaStylesContoller.setElementStyle(this.animatedElement, "-webkit-animation-duration", animationDuration);
                this.nextKeyframe += 1;
            }

            this.application.ninja.documentController.activeDocument.model.needsSave = true;
        }
    },

    splitTween:{
        value:function (ev) {
            console.log("Splitting an existing span with a new keyframe is not yet supported.");
        }
    },

    retrieveStoredTweens:{
        value:function () {
            var percentValue, fraction, splitValue,offsetAttribute,topOffSetAttribute,leftOffsetAttribute;
            var currentMilliSec,currentMilliSecPerPixel,clickPosition,tempTiming,tempTimingFloat,trackTiming,i = 0;

            var selectedIndex = this.application.ninja.timeline.getLayerIndexByID(this.trackID);
            this.application.ninja.timeline.arrLayers[selectedIndex].layerData.created=true;
            this.animatedElement = this.application.ninja.timeline.arrLayers[selectedIndex].layerData.elementsList[0];
            if(this.animatedElement!==undefined){
                this.animationName = this.application.ninja.stylesController.getElementStyle(this.animatedElement, "-webkit-animation-name");
                if(this.animationName){
                    trackTiming = this.application.ninja.stylesController.getElementStyle(this.animatedElement, "-webkit-animation-duration");
                    this.nextKeyframe = 0;

                    this.currentKeyframeRule = this.application.ninja.stylesController.getAnimationRuleWithName(this.animationName, this.application.ninja.currentDocument._document);

                    for (i =0; this.currentKeyframeRule[i] ;i++) {
                        var newTween = {};
                        newTween.tweenData = {};

                        offsetAttribute = this.currentKeyframeRule[i].cssText.split(" ");
                        topOffSetAttribute = offsetAttribute[3].split("px");
                        leftOffsetAttribute = offsetAttribute[5].split("px");

                        var tempTopOffset = parseInt(topOffSetAttribute[0]);
                        var tempLeftOffset =parseInt(leftOffsetAttribute[0]);

                        if (this.currentKeyframeRule[i].keyText === "0%") {
                            newTween.tweenData.spanWidth = 0;
                            newTween.tweenData.keyFramePosition = 0;
                            newTween.tweenData.keyFrameMillisec = 0;
                            newTween.tweenData.tweenID = 0;
                            newTween.tweenData.spanPosition = 0;
                            newTween.tweenData.tweenedProperties = [];
                            newTween.tweenData.tweenedProperties["top"] = tempTopOffset;
                            newTween.tweenData.tweenedProperties["left"] = tempLeftOffset;
                            this.tweens.push(newTween);
                        }
                        else {
                            tempTiming = trackTiming.split("s");
                            tempTimingFloat = parseFloat(tempTiming[0]);
                            this.trackDuration = tempTimingFloat *1000;
                            percentValue = this.currentKeyframeRule[i].keyText;
                            splitValue = percentValue.split("%");
                            fraction = splitValue[0] / 100;
                            currentMilliSec = fraction * this.trackDuration;
                            currentMilliSecPerPixel = Math.floor(this.application.ninja.timeline.millisecondsOffset / 80);
                            clickPosition = currentMilliSec / currentMilliSecPerPixel;
                            newTween.tweenData.spanWidth = clickPosition - this.tweens[this.tweens.length - 1].tweenData.keyFramePosition;
                            newTween.tweenData.keyFramePosition = clickPosition;
                            newTween.tweenData.keyFrameMillisec = currentMilliSec;
                            newTween.tweenData.tweenID = this.nextKeyframe;
                            newTween.tweenData.spanPosition =clickPosition - newTween.tweenData.spanWidth;
                            newTween.tweenData.tweenedProperties=[];
                            newTween.tweenData.tweenedProperties["top"] = tempTopOffset;
                            newTween.tweenData.tweenedProperties["left"] = tempLeftOffset;
                            this.tweens.push(newTween);
                        }
                        this.nextKeyframe += 1;
                    }
                    this.isTrackAnimated = true;
                }
            }
        }
    },

    addAnimationRuleToElement:{
        value:function (tweenEvent) {
            this.tweens[0].tweenData.tweenedProperties["top"] = this.animatedElement.offsetTop;
            this.tweens[0].tweenData.tweenedProperties["left"] = this.animatedElement.offsetLeft;
            var animationDuration = Math.round(this.trackDuration / 1000) + "s";
            this.animationName = "animation_" + this.animatedElement.classList[0];
            this.ninjaStylesContoller.setElementStyle(this.animatedElement, "-webkit-animation-name", this.animationName);
            this.ninjaStylesContoller.setElementStyle(this.animatedElement, "-webkit-animation-duration", animationDuration);
            this.ninjaStylesContoller.setElementStyle(this.animatedElement, "-webkit-animation-iteration-count", 1);
            this.ninjaStylesContoller.setElementStyle(this.animatedElement, "-webkit-animation-fill-mode", "both");
            this.ninjaStylesContoller.setElementStyle(this.animatedElement, "-webkit-transition-timing-function", "linear");
            var initRule = "@-webkit-keyframes " + this.animationName + " { 0% {top: " + this.animatedElement.offsetTop + "px; left: " + this.animatedElement.offsetLeft + "px;} 100% {top: " + this.animatedElement.offsetTop + "px; left: " + this.animatedElement.offsetLeft + "px;} }";

            this.currentKeyframeRule = this.ninjaStylesContoller.addRule(initRule);

            this.insertTween(tweenEvent.offsetX);
            this.isTrackAnimated = true;
        }
    },

    updateKeyframeRule:{
        value:function () {
            // delete the current rule
            this.ninjaStylesContoller.deleteRule(this.currentKeyframeRule);

            // build the new keyframe string
            var keyframeString = "@-webkit-keyframes " + this.animationName + " {";

            for (var i = 0; i < this.tweens.length; i++) {
                var keyMill = parseInt(this.tweens[i].tweenData.keyFrameMillisec);
                // TODO - trackDur should be parseFloat rounded to significant digits
                var trackDur = parseInt(this.trackDuration);
                var keyframePercent = Math.round((keyMill / trackDur) * 100) + "%";
                var keyframePropertyString = " " + keyframePercent + " {";
                for(var prop in this.tweens[i].tweenData.tweenedProperties){
                    keyframePropertyString += prop + ": " + this.tweens[i].tweenData.tweenedProperties[prop] + "px;";
                }
                keyframePropertyString += "}";
                keyframeString += keyframePropertyString;
            }
            keyframeString += " }";
            // set the keyframe string as the new rule
            this.currentKeyframeRule = this.ninjaStylesContoller.addRule(keyframeString);
            this.application.ninja.documentController.activeDocument.model.needsSave = true;
        }
    },

    // Init and event handler for layer expand/collapse
    init:{
        value:function () {
            
            this.arrPositionTracks = [0, 1];
            this.arrTransformTracks = [0, 1, 2, 3, 4];

            // Register event handler for layer events.
            defaultEventManager.addEventListener("layerEvent", this, false);

        }
    },

    handleLayerEvent:{
        value:function (layerEvent) {
            if (layerEvent.layerID !== this.trackID) {
                return;
            }
            if (layerEvent.layerEventType === "newStyle") {
            	// TODO: Add a real track of tweens.  Probably need a method for that.
            	this.arrStyleTracks.push("1");
            } else if (layerEvent.layerEventType === "deleteStyle") {
            	// TODO: Delete the right track.  Index can be passed in event object, use that for splice().
            	this.arrStyleTracks.pop();
            }
        }
    },
    getTweenIndexById: {
    	value: function(intID) {
    		var i = 0,
    			arrTweensLength = this.tweens.length;
			for (i = 0; i < arrTweensLength; i++) {
			    if (this.tweens[i].tweenData.tweenID === intID) {
			        returnVal = i;
			    }
			}
			return returnVal;
    	}
    },
	/* 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 */
});