/* <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,
    TextDocument =	require("js/document/text-document").TextDocument,
    NJUtils = 		require("js/lib/NJUtils").NJUtils,
	GLWorld =			require("js/lib/drawing/world").World,
    MaterialsModel = require("js/models/materials-model").MaterialsModel;
////////////////////////////////////////////////////////////////////////
//
exports.HTMLDocument = Montage.create(TextDocument, {
    
    _selectionExclude: { value: null, enumerable: false },
    _htmlTemplateUrl: { value: "js/document/templates/montage-html/index.html", enumerable: false},
    _iframe: { value: null, enumerable: false },
    _server: { value: null, enumerable: false },
    _templateDocument: { value: null, enumerable: false },
    _selectionModel: { value: [], enumerable: false },
    _undoModel: { value: { "queue" : [], "position" : 0 }, enumerable: false},

    _document: { value: null, enumerable: false },
    _documentRoot: { value: null, enumerable: false },
    _liveNodeList: { value: null, enumarable: false },
    _stageBG: { value: null, enumerable: false },
    _window: { value: null, enumerable: false },
    _styles: { value: null, enumerable: false },
    _stylesheets: { value: null, enumerable: false },
    _stageStyleSheetId : { value: 'nj-stage-stylesheet', enumerable: false },
    _userDocument: { value: null, enumerable: false },
    _htmlSource: {value: "<html></html>", enumerable: false},
    _glData: {value: null, enumerable: false },
    _userComponents: { value: {}, enumarable: false},

    _elementCounter: { value: 1, enumerable: false },
    _snapping : { value: true, enumerable: false },
    _layoutMode: { value: "all", enumerable: false },
    _draw3DGrid: { value: false, writable: true },
    _swfObject: { value: false, enumerable: false },

    _zoomFactor: { value: 100, enumerable: false },

    cssLoadInterval: { value: null, enumerable: false },

    _savedLeftScroll: {value:null},
    _savedTopScroll: {value:null},

    _codeViewDocument:{
        writable: true,
        enumerable: true,
        value:null
    },


    //drawUtils state
    _gridHorizontalSpacing: {value:0},
    _gridVerticalSpacing: {value:0},
    //end - drawUtils state

    _undoStack: { value: [] },
    undoStack: {
        get: function() {
            return this._undoStack;
        },
        set:function(value){
            this._undoStack = value;
        }
    },

    _redoStack: { value: [], enumerable: false },

    redoStack: {
        get: function() {
            return this._redoStack;
        },
        set:function(value){
            this._redoStack = value;
        }
    },


    // GETTERS / SETTERS

    codeViewDocument:{
        get: function() { return this._codeViewDocument; },
        set: function(value) { this._codeViewDocument = value}
    },

    savedLeftScroll:{
        get: function() { return this._savedLeftScroll; },
        set: function(value) { this._savedLeftScroll = value}
    },

    savedTopScroll:{
        get: function() { return this._savedTopScroll; },
        set: function(value) { this._savedTopScroll = value}
    },

    gridHorizontalSpacing:{
        get: function() { return this._gridHorizontalSpacing; },
        set: function(value) { this._gridHorizontalSpacing = value}
    },

    gridVerticalSpacing:{
        get: function() { return this._gridVerticalSpacing; },
        set: function(value) { this._gridVerticalSpacing = value}
    },

    selectionExclude: {
        get: function() { return this._selectionExclude; },
        set: function(value) { this._selectionExclude = value; }
    },

    iframe: {
        get: function() { return this._iframe; },
        set: function(value) { this._iframe = value; }
    },

    server: {
        get: function() { return this._server; },
        set: function(value) { this._server = value; }
    },

    selectionModel: {
        get: function() { return this._selectionModel; },
        set: function(value) { this._selectionModel = value; }
    },

    undoModel: {
        get: function() { return this._undoModel; },
        set: function(value) { this._undoModel.queue = value.queue; this._undoModel.position = value.position; }
    },

    documentRoot: {
        get: function() { return this._documentRoot; },
        set: function(value) { this._documentRoot = value; }
    },

    stageBG: {
        get: function() { return this._stageBG; },
        set: function(value) { this._stageBG = value; }
    },

    elementCounter: {
        set: function(value) { this._elementCounter = value; },
        get: function() { return this._elementCounter; }
    },

    snapping: {
        get: function() { return this._snapping; },
        set: function(value) {
            if(this._snapping !== value) {
                this._snapping = value;
            }
        }
    },

    // TODO SEND THE EVENT --> Redraw the desired layout
    layoutMode: {
        get: function() { return this._layoutMode; },
        set: function(mode) { this._layoutMode = mode; }
    },

    draw3DGrid: {
        get: function() { return this._draw3DGrid; },
        set: function(value) {
            if(this._draw3DGrid !== value) {
                this._draw3DGrid = value;
            }
        }
    },

    userComponents: {
        get: function() {
            return this._userComponents;
        }
    },
//    _drawUserComponentsOnOpen:{
//        value:function(){
//            for(var i in this._userComponentSet){
//                console.log(this._userComponentSet[i].control)
//                this._userComponentSet[i].control.needsDraw = true;
//            }
//        }
//    },
    
    glData: {
    	get: function() {
			//
			var elt = this.iframe.contentWindow.document.getElementById("UserContent");
			//
			if (elt) {
                var matLib = MaterialsModel.exportMaterials();
				this._glData = [matLib];
				this.collectGLData(elt, this._glData );
			} else {
				this._glData = null
			}
			//	
			return this._glData;
		},
        set: function(value) {
			var elt = this.documentRoot;
			if (elt)
			{
				var nWorlds= value.length;
				for (var i=0;  i<nWorlds;  i++)
				{
					/*
					// Use this code to test the runtime version of WebGL
					var cdm = new NinjaCvsRt.CanvasDataManager();
					cdm.loadGLData(elt,  value,  null );
					*/

					// /*
					// get the data for the next canvas
					var importStr = value[i];

					// determine if it is the new (JSON) or old style format
					var id = null;
					var jObj = null;
					var index = importStr.indexOf( ';' );
					if ((importStr[0] === 'v') && (index < 24))
					{
						// JSON format.  pull off the
						importStr = importStr.substr( index+1 );
						jObj = jObj = JSON.parse( importStr );
						id = jObj.id;
					}
					else
					{
                        // at this point the data could be either the materials library or
                        // an old style world.  We can determine which by converting the string
                        // to an object via JSON.parse.  That operation will fail if the string
                        // is an old style world.
                        var matLibStr = 'materialLibrary;';
                        index = importStr.indexOf( matLibStr );
                        if (index == 0)
                        {
                            importStr = importStr.substr( matLibStr.length );
                            var matLibObj = JSON.parse( importStr );
                            MaterialsModel.importMaterials( matLibObj );
                        }
                        else
                        {
						    var startIndex = importStr.indexOf( "id: " );
						    if (startIndex >= 0) {
							    var endIndex = importStr.indexOf( "\n", startIndex );
							    if (endIndex > 0)
								    id = importStr.substring( startIndex+4, endIndex );
						    }
                        }
					}

					if (id != null)
					{
						var canvas = this.findCanvasWithID( id, elt );
						if (canvas)
						{
							if (!canvas.elementModel)
							{
								NJUtils.makeElementModel(canvas, "Canvas", "shape", true);
							}
							if (canvas.elementModel)
							{
								if (canvas.elementModel.shapeModel.GLWorld)
									canvas.elementModel.shapeModel.GLWorld.clearTree();

								if (jObj)
								{
									var useWebGL = jObj.webGL;
									var world = new GLWorld( canvas, useWebGL );
									world.importJSON( jObj );
								}

								this.buildShapeModel( canvas.elementModel, world );
							}
						}
					}
					// */
				}
			}
		}
    },

	buildShapeModel:
	{
		value: function( elementModel, world )
		{
            var shapeModel = elementModel.shapeModel;
			shapeModel.shapeCount	= 1;	// for now...
			shapeModel.useWebGl		= world._useWebGL;
			shapeModel.GLWorld		= world;
			var root = world.getGeomRoot();
			if (root)
			{
				shapeModel.GLGeomObj			= root;
				shapeModel.strokeSize			= root._strokeWidth;
				shapeModel.strokeStyle			= "solid";
				//shapeModel.strokeStyleIndex
				switch (root.geomType())
				{
					case root.GEOM_TYPE_RECTANGLE:
                        elementModel.selection = "Rectangle";
                        elementModel.pi = "RectanglePi";
						shapeModel.tlRadius = root._tlRadius;
						shapeModel.trRadius = root._trRadius;
						shapeModel.blRadius = root._blRadius;
						shapeModel.brRadius = root._brRadius;
						break;

					case root.GEOM_TYPE_CIRCLE:
                        elementModel.selection = "Oval";
                        elementModel.pi = "OvalPi";
						shapeModel.innerRadius = root._innerRadius;
						break;

					case root.GEOM_TYPE_LINE:
                        elementModel.selection = "Line";
                        elementModel.pi = "LinePi";
						shapeModel.slope = root._slope;
						break;

                    case root.GEOM_TYPE_BRUSH_STROKE:
                        elementModel.selection = "BrushStroke";
                        elementModel.pi = "BrushStrokePi";
						break;

                    case root.GEOM_TYPE_CUBIC_BEZIER:
                        elementModel.selection = "Subpath";
                        elementModel.pi = "SubpathPi";
                        break;

					default:
						console.log( "geometry type not supported for file I/O, " + root.geomType());
						break;
				}
			}
		}
	},

    zoomFactor: {
        get: function() { return this._zoomFactor; },
        set: function(value) { this._zoomFactor = value; }
    },

    /**
     * Add a reference to a component instance to the userComponents hash using the
     * element UUID
     */
    setComponentInstance: {
        value: function(instance, el) {
            this.userComponents[el.uuid] = instance;
        }
    },

    /**
     * Returns the component instance obj from the element
     */
    getComponentFromElement: {
        value: function(el) {
            if(el) {
                if(el.uuid) return this.userComponents[el.uuid];
            } else {
                return null;
            }
        }
    },

    /**
     * search the DOM tree to find a canvas with the given id
     */
	findCanvasWithID:  {
		value: function( id,  elt )  {
			var cid = elt.getAttribute( "data-RDGE-id" );
			if (cid == id)  return elt;

			if (elt.children)
			{
				var nKids = elt.children.length;
				for (var i=0;  i<nKids;  i++)
				{
					var child = elt.children[i];
					var foundElt = this.findCanvasWithID( id, child );
					if (foundElt)  return foundElt;
				}
			}
		}
	},
    
    
    
    ////////////////////////////////////////////////////////////////////
	//
    initialize: {
		value: function(file, uuid, iframe, callback) {
			this.application.ninja.documentController._hackRootFlag = false;
			//
			this._userDocument = file;
			//
			this.init(file.name, file.uri, file.extension, iframe, uuid, callback);
			//
            this.iframe = iframe;
            this.selectionExclude = ["HTML", "BODY", "Viewport", "UserContent", "stageBG"];
            this.currentView = "design";
			//

            this.iframe.src = this._htmlTemplateUrl;
            this.iframe.addEventListener("load", this, true);
        }
    },
    ////////////////////////////////////////////////////////////////////


	collectGLData: {
		value: function( elt,  dataArray )
		{
			if (elt.elementModel && elt.elementModel.shapeModel && elt.elementModel.shapeModel.GLWorld)
			{
				var data = elt.elementModel.shapeModel.GLWorld.exportJSON();
				dataArray.push( data );
			}

			if (elt.children)
			{
				var nKids = elt.children.length;
				for (var i=0;  i<nKids;  i++)
				{
					var child = elt.children[i];
					this.collectGLData( child, dataArray );
				}
			}
		}
	},


    // OLD

    inExclusion: {
        value: function(element) {
            if(this._selectionExclude.indexOf(element.id) === -1) {
                if(this._selectionExclude.indexOf(element.nodeName) === -1) {
                    return -1;
                }
            } else if (this._selectionExclude.indexOf(element.id) === -1) {
                return -1;
            } else {
                return 1;
            }
        }
    },

    /**
     * Return the specified inline attribute from the element.
     */
    GetElementAttribute: {
        value: function(element, attribute) {

            var value;

            if(attribute === "src") {
                return element[attribute].replace(window.location.href, '');
            }

            value = element[attribute];

            if(value !== undefined) return value;
//            if(value || value === false) return [value, "inline"];

            // 3.
            //value = this._document.defaultView.getComputedStyle(element,null).getPropertyValue(attribute);
            //if(value) return value;

            return null;
        }
    },

    GetElementStyle: {
        value: function(element, style) {
//            return this._queryStylesheets(element, style);
        }
    },

    SetStyle: {
        value: function(type, selector, style, value) {
            try {
                for(var j=0; j<this._stylesheets.length;j++){
                    for(var i=0; i<this._stylesheets[j].cssRules.length;i++) {
                        if(this._stylesheets[j].cssRules[i].selectorText === type + selector) {
                            this._stylesheets[j].cssRules[i].style[style] = value;

                            return true;
                        }
                    }
                }
            } catch(err) {
                console.log("Cannot change the style of selector: " + selector + " " + err);
            }
        }
    },

    GetElementFromPoint: {
        value: function(x, y) {
            return this._window.getElement(x,y);
        }
    },
    
    
    
    
    
    
    
    
	/* 		
            DOM Mutation Events:
          		
            DOMActivate, DOMFocusIn, DOMFocusOut, DOMAttrModified,
           	DOMCharacterDataModified, DOMNodeInserted, DOMNodeInsertedIntoDocument,
       		DOMNodeRemoved, DOMNodeRemovedFromDocument, DOMSubtreeModified, DOMContentLoaded
            		
  	*/
  	
  	
  	
  	/*
//TODO: Remove and clean up event listener (DOMSubtreeModified)
  	_hackCount: {
  		value: 0
  	},
*/
	////////////////////////////////////////////////////////////////////
	//
    handleEvent: {
        value: function(event){
        	//TODO: Clean up, using for prototyping save
        	this._templateDocument = {};
        	this._templateDocument.html = this.iframe.contentWindow.document;
        	this._templateDocument.head = this.iframe.contentWindow.document.getElementById("userHead");
        	this._templateDocument.body = this.documentRoot = this.iframe.contentWindow.document.getElementById("UserContent");
        	//TODO: Remove, also for prototyping
        	this.application.ninja.documentController._hackRootFlag = true;
        	//
            this.stageBG = this.iframe.contentWindow.document.getElementById("stageBG");
            this.stageBG.onclick = null;
            this._document = this.iframe.contentWindow.document;
            this._window = this.iframe.contentWindow;
            //
            for (var k in this._document.styleSheets) {
            	if (this._document.styleSheets[k].ownerNode && this._document.styleSheets[k].ownerNode.setAttribute) {
            		this._document.styleSheets[k].ownerNode.setAttribute('data-ninja-template', 'true');
            	}
            }
            //
            if(!this.documentRoot.Ninja) this.documentRoot.Ninja = {};
            
            
            
            //TODO: Clean up, using for prototyping
            this._templateDocument.head.innerHTML = (this._userDocument.content.head.replace(/\b(href|src)\s*=\s*"([^"]*)"/g, this.application.ninja.ioMediator.getNinjaPropUrlRedirect.bind(this.application.ninja.ioMediator))).replace(/url\(([^"]*)(.+?)\1\)/g, this.application.ninja.ioMediator.getNinjaPropUrlRedirect.bind(this.application.ninja.ioMediator));
            this._templateDocument.body.innerHTML = (this._userDocument.content.body.replace(/\b(href|src)\s*=\s*"([^"]*)"/g, this.application.ninja.ioMediator.getNinjaPropUrlRedirect.bind(this.application.ninja.ioMediator))).replace(/url\(([^"]*)(.+?)\1\)/g, this.application.ninja.ioMediator.getNinjaPropUrlRedirect.bind(this.application.ninja.ioMediator));            
           	
            
            
            var scripttags = this._templateDocument.html.getElementsByTagName('script'), webgldata;  //TODO: Use querySelectorAll
            //
            for (var w in scripttags) {
            	if (scripttags[w].getAttribute) {
            		if (scripttags[w].getAttribute('data-ninja-webgl') !== null) {
            			//TODO: Add logic to handle more than one data tag
            			webgldata = JSON.parse((scripttags[w].innerHTML.replace("(", "")).replace(")", ""));
            		}
            	}
            }
            //
            if (webgldata) {
            	for (var n=0; webgldata.data[n]; n++) {
            		webgldata.data[n] = unescape(webgldata.data[n]);
            	}
            	this._templateDocument.webgl = webgldata.data;
            }
            
            
            
            //Temporarily checking for disabled special case
            var stags = this.iframe.contentWindow.document.getElementsByTagName('style'),
            	ltags = this.iframe.contentWindow.document.getElementsByTagName('link');
           	//
            for (var m = 0; m < ltags.length; m++) {
            	if (ltags[m].getAttribute('data-ninja-template') === null) {
            		if (ltags[m].getAttribute('disabled')) {
           				ltags[m].removeAttribute('disabled');
           				ltags[m].setAttribute('data-ninja-disabled', 'true');
           			}
           		}
           	}
            //
           	for (var n = 0; n < stags.length; n++) {
           		if (stags[n].getAttribute('data-ninja-template') === null) {
           			if (stags[n].getAttribute('disabled')) {
           				stags[n].removeAttribute('disabled');
           				stags[n].setAttribute('data-ninja-disabled', 'true');
            		}
            	}
            }
            
            
            
            //Adding a handler for the main user document reel to finish loading
            this._document.body.addEventListener("userTemplateDidLoad",  this.userTemplateDidLoad.bind(this), false);

            // Live node list of the current loaded document
            this._liveNodeList = this.documentRoot.getElementsByTagName('*');

            // TODO Move this to the appropriate location
            var len = this._liveNodeList.length;

            for(var i = 0; i < len; i++) {
                NJUtils.makeModelFromElement(this._liveNodeList[i]);
            }

            /* this.iframe.contentWindow.document.addEventListener('DOMSubtreeModified', function (e) { */ //TODO: Remove events upon loading once

            //TODO: When re-written, the best way to initialize the document is to listen for the DOM tree being modified
            setTimeout(function () {
            	
            	
            	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            	if(this._document.styleSheets.length > 1) {
					//Checking all styleSheets in document
					for (var i in this._document.styleSheets) {
						//If rules are null, assuming cross-origin issue
						if(this._document.styleSheets[i].rules === null) {
							//TODO: Revisit URLs and URI creation logic, very hack right now
							var fileUri, cssUrl, cssData, query, prefixUrl, fileCouldDirUrl, docRootUrl;
							//
            				docRootUrl = this.application.ninja.coreIoApi.rootUrl+escape((this.application.ninja.documentController.documentHackReference.root.split(this.application.ninja.coreIoApi.cloudData.root)[1]).replace(/\/\//gi, '/'));
							//TODO: Parse out relative URLs and map them to absolute
							if (this._document.styleSheets[i].href.indexOf(this.application.ninja.coreIoApi.rootUrl) !== -1) {
								//
								cssUrl = this._document.styleSheets[i].href.split(this.application.ninja.coreIoApi.rootUrl)[1];
								fileUri = this.application.ninja.coreIoApi.cloudData.root+cssUrl;
								//TODO: Add error handling for reading file
								cssData = this.application.ninja.coreIoApi.readFile({uri: fileUri});
								//
								var tag = this.iframe.contentWindow.document.createElement('style');
								tag.setAttribute('type', 'text/css');
								tag.setAttribute('data-ninja-uri', fileUri);
								tag.setAttribute('data-ninja-file-url', cssUrl);
								tag.setAttribute('data-ninja-file-read-only', JSON.parse(this.application.ninja.coreIoApi.isFileWritable({uri: fileUri}).content).readOnly);
								tag.setAttribute('data-ninja-file-name', cssUrl.split('/')[cssUrl.split('/').length-1]);
								//Copying attributes to maintain same properties as the <link>
								for (var n in this._document.styleSheets[i].ownerNode.attributes) {
									if (this._document.styleSheets[i].ownerNode.attributes[n].value && this._document.styleSheets[i].ownerNode.attributes[n].name !== 'disabled' && this._document.styleSheets[i].ownerNode.attributes[n].name !== 'disabled') {
										if (this._document.styleSheets[i].ownerNode.attributes[n].value.indexOf(docRootUrl) !== -1) {
											tag.setAttribute(this._document.styleSheets[i].ownerNode.attributes[n].name, this._document.styleSheets[i].ownerNode.attributes[n].value.split(docRootUrl)[1]);
										} else {
											tag.setAttribute(this._document.styleSheets[i].ownerNode.attributes[n].name, this._document.styleSheets[i].ownerNode.attributes[n].value);
										}
									}
								}
								//
								fileCouldDirUrl = this._document.styleSheets[i].href.split(this._document.styleSheets[i].href.split('/')[this._document.styleSheets[i].href.split('/').length-1])[0];
								
								//TODO: Make public version of this.application.ninja.ioMediator.getNinjaPropUrlRedirect with dynamic ROOT
								tag.innerHTML = cssData.content.replace(/url\(()(.+?)\1\)/g, detectUrl);
								
								function detectUrl (prop) {
									return prop.replace(/[^()\\""\\'']+/g, prefixUrl);;
								}
								
								function prefixUrl (url) {
									if (url !== 'url') {
										if (!url.match(/(\b(?:(?:https?|ftp|file|[A-Za-z]+):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$]))/gi)) {
											url = fileCouldDirUrl+url;
										}
									}
									return url;
								}
								
								//Looping through DOM to insert style tag at location of link element
								query = this._templateDocument.html.querySelectorAll(['link']);
								for (var j in query) {
									if (query[j].href === this._document.styleSheets[i].href) {
										//Disabling style sheet to reload via inserting in style tag
										query[j].setAttribute('disabled', 'true');
										//Inserting tag
										this._templateDocument.head.insertBefore(tag, query[j]);
									}
								}
							} else {
								console.log('ERROR: Cross-Domain-Stylesheet detected, unable to load in Ninja');
								//None local stylesheet, probably on a CDN (locked)
								var tag = this.iframe.contentWindow.document.createElement('style');
								tag.setAttribute('type', 'text/css');
								tag.setAttribute('data-ninja-external-url', this._document.styleSheets[i].href);
								tag.setAttribute('data-ninja-file-read-only', "true");
								tag.setAttribute('data-ninja-file-name', this._document.styleSheets[i].href.split('/')[this._document.styleSheets[i].href.split('/').length-1]);
								//Copying attributes to maintain same properties as the <link>
								for (var n in this._document.styleSheets[i].ownerNode.attributes) {
									if (this._document.styleSheets[i].ownerNode.attributes[n].value && this._document.styleSheets[i].ownerNode.attributes[n].name !== 'disabled' && this._document.styleSheets[i].ownerNode.attributes[n].name !== 'disabled') {
										if (this._document.styleSheets[i].ownerNode.attributes[n].value.indexOf(docRootUrl) !== -1) {
											tag.setAttribute(this._document.styleSheets[i].ownerNode.attributes[n].name, this._document.styleSheets[i].ownerNode.attributes[n].value.split(docRootUrl)[1]);
										} else {
											tag.setAttribute(this._document.styleSheets[i].ownerNode.attributes[n].name, this._document.styleSheets[i].ownerNode.attributes[n].value);
										}
									}
								}
								/*
								
								//TODO: Figure out cross-domain XHR issue, might need cloud to handle
								var xhr = new XMLHttpRequest();
                    			xhr.open("GET", this._document.styleSheets[i].href, true);
                    			xhr.send();
                    			//
                    			if (xhr.readyState === 4) {
                        			console.log(xhr);
                    			}
                    			//tag.innerHTML = xhr.responseText //xhr.response;
								*/
                    			//Temp rule so it's registered in the array
                    			tag.innerHTML = 'noRULEjustHACK{background: #000}';
								//Disabling external style sheets
								query = this._templateDocument.html.querySelectorAll(['link']);
								for (var k in query) {
									if (query[k].href === this._document.styleSheets[i].href) {
										
										//TODO: Removed the temp insertion of the stylesheet
										//because it wasn't the proper way to do it
										//need to be handled via XHR with proxy in Cloud Sim
										
										//Disabling style sheet to reload via inserting in style tag
										//var tempCSS = query[k].cloneNode(true);
										//tempCSS.setAttribute('data-ninja-template', 'true');
										query[k].setAttribute('disabled', 'true');
										//this.iframe.contentWindow.document.head.appendChild(tempCSS);
										//Inserting tag
										this._templateDocument.head.insertBefore(tag, query[k]);
									}
								}
							}
                    	}
					}
					////////////////////////////////////////////////////////////////////////////
					////////////////////////////////////////////////////////////////////////////
					
					//TODO: Check if this is needed
					this._stylesheets = this._document.styleSheets;
					
					////////////////////////////////////////////////////////////////////////////
					////////////////////////////////////////////////////////////////////////////
					
					//TODO Finish this implementation once we start caching Core Elements
					// Assign a model to the UserContent and add the ViewPort reference to it.
					NJUtils.makeElementModel(this.documentRoot, "Stage", "stage");
					//this.documentRoot.elementModel.viewPort = this.iframe.contentWindow.document.getElementById("Viewport");
					NJUtils.makeElementModel(this.stageBG, "Stage", "stage");
					NJUtils.makeElementModel(this.iframe.contentWindow.document.getElementById("Viewport"), "Stage", "stage");
					 
					for(i = 0; i < this._stylesheets.length; i++) {
						if(this._stylesheets[i].ownerNode.id === this._stageStyleSheetId) {
							this.documentRoot.elementModel.defaultRule = this._stylesheets[i];
							break;
						}
					}
					 
					//Temporary create properties for each rule we need to save the index of the rule
					var len = this.documentRoot.elementModel.defaultRule.cssRules.length;
					for(var j = 0; j < len; j++) {
						//console.log(this.documentRoot.elementModel.defaultRule.cssRules[j].selectorText);
						if(this.documentRoot.elementModel.defaultRule.cssRules[j].selectorText === "*") {
						
							this.documentRoot.elementModel.transitionStopRule = this.documentRoot.elementModel.defaultRule.cssRules[j];
						
						} else if(this.documentRoot.elementModel.defaultRule.cssRules[j].selectorText === "body") {
							
							this.documentRoot.elementModel.body = this.documentRoot.elementModel.defaultRule.cssRules[j];
						
						} else if(this.documentRoot.elementModel.defaultRule.cssRules[j].selectorText === "#Viewport") {
						
							this.documentRoot.elementModel.viewPort = this.documentRoot.elementModel.defaultRule.cssRules[j];
							
						} else if(this.documentRoot.elementModel.defaultRule.cssRules[j].selectorText === ".stageDimension") {
						
							this.documentRoot.elementModel.stageDimension = this.documentRoot.elementModel.defaultRule.cssRules[j];
							
						} else if(this.documentRoot.elementModel.defaultRule.cssRules[j].selectorText === ".stageView") {
							
							this.documentRoot.elementModel.stageView = this.documentRoot.elementModel.defaultRule.cssRules[j];
							
						} else if(this.documentRoot.elementModel.defaultRule.cssRules[j].selectorText === "#stageBG") {
							
							this.documentRoot.elementModel.stageBackground = this.documentRoot.elementModel.defaultRule.cssRules[j];
						}
					}
					
					this.callback(this);
					
					//Setting webGL data
					if (this._templateDocument.webgl) {
						this.glData = this._templateDocument.webgl;
					}
				}
				////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			
			
			
			
			
			}.bind(this), 1000);
			
			
            
            
     	}
    },

    ////////////////////////////////////////////////////////////////////

    // Handler for user content main reel. Gets called once the main reel of the template
    // gets deserialized.
    // Setting up the currentSelectedContainer to the document body.
    userTemplateDidLoad: {
        value: function(){
            //this.application.ninja.currentSelectedContainer = this.documentRoot;
        }
    },
    
    
    ////////////////////////////////////////////////////////////////////
    _setSWFObjectScript: {
        value: function() {
            if(!this._swfObject) {
                /*
                var swfObj = document.createElement("script");
                swfObj.type = "text/javascript";
                swfObj.src = "../../user-document-templates/external-libs/swf-object/swfobject.js";
                swfObj.id = "swfObject";
                var head= this._document.getElementsByTagName('head')[0];
                head.appendChild(swfObj);
                this._swfObject = true;
                */
            }
        }
    },
    
    
    
    
    
    ////////////////////////////////////////////////////////////////////
	//
    livePreview: {
    	enumerable: false,
    	value: function () {
    		//TODO: Add logic to handle save before preview
    		this.application.ninja.documentController.handleExecuteSaveAll(null);
    		//Temp check for webGL Hack
    		window.open(this.application.ninja.coreIoApi.rootUrl + this.application.ninja.documentController._activeDocument.uri.split(this.application.ninja.coreIoApi.cloudData.root)[1]);
    		//chrome.tabs.create({url: this.application.ninja.coreIoApi.rootUrl+this.application.ninja.documentController._activeDocument.uri.split(this.application.ninja.coreIoApi.cloudData.root)[1]});		
    	}
    },
	////////////////////////////////////////////////////////////////////
	//
	save: {
		enumerable: false,
    	value: function () {
    		//TODO: Add code view logic and also styles for HTML
    		if (this.currentView === 'design') {
    			var styles = [];
    			for (var k in this._document.styleSheets) {
    				if (this._document.styleSheets[k].ownerNode && this._document.styleSheets[k].ownerNode.getAttribute) {
            			if (this._document.styleSheets[k].ownerNode.getAttribute('ninjatemplate') === null) {
            				styles.push(this._document.styleSheets[k]);
            			}
            		}
            	}
    			//return {mode: 'html', document: this._userDocument, mjs: this._userComponents, webgl: this.glData, styles: styles, head: this._templateDocument.head.innerHTML, body: this._templateDocument.body.innerHTML};
    			return {mode: 'html', document: this._userDocument, webgl: this.glData, styles: styles, head: this._templateDocument.head.innerHTML, body: this._templateDocument.body.innerHTML};
    		} else if (this.currentView === "code"){
    			//TODO: Would this get call when we are in code of HTML?
    		} else {
    			//Error
    		}
    	}
	},
	////////////////////////////////////////////////////////////////////
	//
	saveAll: {
		enumerable: false,
    	value: function () {
    		//TODO: Add code view logic and also styles for HTML
    		if (this.currentView === 'design') {
    			var css = [];
    			for (var k in this._document.styleSheets) {
    				if (this._document.styleSheets[k].ownerNode && this._document.styleSheets[k].ownerNode.getAttribute) {
            			if (this._document.styleSheets[k].ownerNode.getAttribute('ninjatemplate') === null) {
            				css.push(this._document.styleSheets[k]);
            			}
            		}
            	}
    			//return {mode: 'html', document: this._userDocument, mjs: this._userComponents, webgl: this.glData, css: css, head: this._templateDocument.head.innerHTML, body: this._templateDocument.body.innerHTML};
    			return {mode: 'html', document: this._userDocument, webgl: this.glData, css: css, head: this._templateDocument.head.innerHTML, body: this._templateDocument.body.innerHTML};
    		} else if (this.currentView === "code"){
    			//TODO: Would this get call when we are in code of HTML?
    		} else {
    			//Error
    		}
    	}
	},
	////////////////////////////////////////////////////////////////////
    saveAppState:{
        enumerable: false,
        value: function () {

            this.savedLeftScroll = this.application.ninja.stage._iframeContainer.scrollLeft;
            this.savedTopScroll = this.application.ninja.stage._iframeContainer.scrollTop;

            this.gridHorizontalSpacing = this.application.ninja.stage.drawUtils.gridHorizontalSpacing;
            this.gridVerticalSpacing = this.application.ninja.stage.drawUtils.gridVerticalSpacing;

            if(typeof this.application.ninja.selectedElements !== 'undefined'){
                this.selectionModel = this.application.ninja.selectedElements.slice(0);
            }

            this.draw3DGrid = this.application.ninja.appModel.show3dGrid;

            //persist a clone of history per document
            this.undoStack = this.application.ninja.undocontroller.undoQueue.slice(0);
            this.redoStack = this.application.ninja.undocontroller.redoQueue.slice(0);
            this.application.ninja.undocontroller.clearHistory();//clear history to give the next document a fresh start

            //pause videos on switching or closing the document, so that the browser does not keep downloading the media data
            this.pauseVideos();
        }
    },

    ////////////////////////////////////////////////////////////////////
    restoreAppState:{
        enumerable: false,
        value: function () {
            this.application.ninja.stage.drawUtils.gridHorizontalSpacing = this.gridHorizontalSpacing;
            this.application.ninja.stage.drawUtils.gridVerticalSpacing = this.gridVerticalSpacing;
           
            if((this.savedLeftScroll !== null) && (this.savedTopScroll !== null)){
                this.application.ninja.stage._iframeContainer.scrollLeft = this.savedLeftScroll;
                this.application.ninja.stage._iframeContainer.scrollTop = this.savedTopScroll;
                this.application.ninja.stage.handleScroll();
            }

            this.application.ninja.currentSelectedContainer = this.documentRoot;
            if(this.selectionModel){
                this.application.ninja.selectedElements = this.selectionModel.slice(0);
            }

            this.application.ninja.appModel.show3dGrid = this.draw3DGrid;

            this.application.ninja.undocontroller.undoQueue = this.undoStack.slice(0);
            this.application.ninja.undocontroller.redoQueue = this.redoStack.slice(0);


        }
    },
	////////////////////////////////////////////////////////////////////
    /**
     *pause videos on switching or closing the document, so that the browser does not keep downloading the media data
    */
    pauseVideos:{
        value:function(){
            var videosArr = this.documentRoot.getElementsByTagName("video"), i=0;
            for(i=0;i<videosArr.length;i++){
                if(!videosArr[i].paused){
                    videosArr[i].pause();
                }
            }
        }
    },

    /**
     * remove the video src on closing the document, so that the browser does not keep downloading the media data, if the tag does not get garbage collected
     *removeSrc : boolean to remove the src if the video... set only in the close document flow
    */
    stopVideos:{
        value:function(){
            var videosArr = this.documentRoot.getElementsByTagName("video"), i=0;
            for(i=0;i<videosArr.length;i++){
                videosArr[i].src = "";
            }
        }
    },
    pauseAndStopVideos:{
        value:function(){
            var videosArr = this.documentRoot.getElementsByTagName("video"), i=0;
            for(i=0;i<videosArr.length;i++){
                if(!videosArr[i].paused){
                    videosArr[i].pause();
                }
                videosArr[i].src = "";
            }
        }
    }
    ////////////////////////////////////////////////////////////////////
});