//This file should be treated like a js file
//It contains a js array of all the ui template chunks for use in the ui and will be cached by the browser

;(function( $ ){

	//N.B. For data handling of various data types ONLY, Server and Template engine are aware of the specific data structure, and must
	// thus have methods, pass pointers that cache and data store can use for keying, saving and loading in a common/uniform manner.
	$.localData = {

		localCacheEnabled : false,
		loadedFromLocalCache : false,
		initializeData : function(dataSourceUrl, dataSourceParams, localDataNode)
		{
			//localDataNode directly points to the node to be worked on
			if( this.localCacheEnabled )
			{

				//TODO: load required pages if needed
				if( !this.loadedFromLocalCache )
				{

					this.loadDataFromLocalCache(dataSourceParams, localDataNode)

				}

			}
			return this.getLocalData(dataSourceUrl, dataSourceParams, localDataNode)
		},
		checkProviderStoreReady : function( dataSourceParams ) {

			//takes metadata from dataSourceParams and makes sure the data sotre for that profider node is initialized
			var pid = dataSourceParams.pid || alert('templateEngine.js #41: pid missing while checking if dataStore ready')
			var serviceType = dataSourceParams.serviceType || alert('templateEngine.js #42: serviceType missing while checking if dataStore ready')
			var serviceName = dataSourceParams.serviceName || alert('templateEngine.js #44: serviceName missing while checking if dataStore ready')
			var serviceDescription = dataSourceParams.serviceDescription || ''
			var folder = dataSourceParams.folder || undefined
			var myId = dataSourceParams.myId || undefined
			var myDisplayName = dataSourceParams.myDisplayName || myId
			var dataSourceURL = dataSourceParams.dataSourceURL || undefined

			if( $.localData.dataStore["pid" + pid] == undefined )
			{

				//possibly new service just added with a new pid so add ampty folder node
				$.localData.dataStore["pid" + pid] = $.extend({}, $.localData.genericFolderedDataNode)
				$.localData.dataStore["pid" + pid].pid = pid
				$.localData.dataStore["pid" + pid].serviceType = serviceType
				$.localData.dataStore["pid" + pid].serviceName = serviceName
				$.localData.dataStore["pid" + pid].serviceDescription = serviceDescription
				$.localData.dataStore["pid" + pid].myId = myId
				$.localData.dataStore["pid" + pid].myDisplayName = myDisplayName
				$.localData.dataStore["pid" + pid].dataSourceURL = dataSourceURL

			}

			//clone missing folders from template if not existing

			if( $.templateEngine.templates[serviceType][serviceName] != undefined && $.templateEngine.templates[serviceType][serviceName].defaultFolders != undefined ) //$.templateEngine.templates[serviceType][serviceName] might be undefined if datatype only uses subtemplates, not a main template
			{

				$.each( $.templateEngine.templates[serviceType][serviceName].defaultFolders, function(key, node)
				{

					if( $.localData.dataStore["pid" + pid].folders[key] == undefined )
						$.localData.dataStore["pid" + pid].folders[key] = $.extend({}, node)

				})

			}
			//lastly if requesting a new/custom folder that not in template defaultFolders doesnt yet have a slot in the dataStore
			if( $.localData.dataStore["pid" + pid].folders[folder] == undefined )
			{
				$.localData.dataStore["pid" + pid].folders[folder] = $.extend({}, $.localData.genericFolderNode)
				$.localData.dataStore["pid" + pid].folders[folder].folderName = folder
			}
			if( folder != undefined )
				return $.localData.dataStore["pid" + pid].folders[folder]
			else
				return $.localData.dataStore["pid" + pid]

		},
		loadDataFromLocalCache : function(dataSourceParams, localDataNode) { //loads local data from local cache (SQLite)

			//TODO: load chunk (for performance) from local cache (SQLite)
			//compile a unique static key for keying the data to be stored
		},
		saveDataToLocalCache : function(dataSourceParams, localDataNode)
		{

			//TODO: save chunk (for performance) from local cache (SQLite)
			//compile a unique static key for keying the data to be loaded into the localDataNode
		},
		getLocalData : function(dataSourceUrl, dataSourceParams, localDataNode) //returns data formatted with extra useful fields that can be passed around as one object
		{
			return {
				success : true, //Did the action complete without failure (server fails, network down etc.)
				result : true, //Did the executing the action result in a success or fail for the commend (e.g. delete, or add)
				noteEnglish : "Fetched local data successfuly", //used for english display and translation
				noteCode : 200, //used for programatic success and result handling
				serviceType : dataSourceParams.serviceType || undefined, //used to direct template engine to different template if needed (e.g. rendering unknown message type, mail, twitter, sms, vm, fb)
				serviceName : dataSourceParams.serviceName || undefined, //used to direct template engine to different template if needed
				pid : dataSourceParams.pid,
				folder : dataSourceParams.folder || undefined, //used to direct template engine to different template if needed (i.e. different header icons)
				localDataNode :  localDataNode,  //caller must rely on this data source in case needed to change (e.g. folder deleted, or redirected to new data Node)
				dataSourceParams : dataSourceParams
			}

		},
		callNewData : function(dataSourceUrl, dataSourceParams, localDataNode, $callbackContext, $callback, specificTemplate)  //loads data into dataStore from server and updates local Cache (SQLite)
		{

			//TODO: currently this is a replace, but should in future do an inteligent merge
			//CONSIDER setting a timeout watchdog for timeout if this Js Thread never comes back, calling same callback but with fail object
			//show loading widget
			//CONSIDER: this loading widget should be a global UI location
			$('.jsMainHeadding', $callbackContext).addClass('loading')

			$XMLHttpRequestObject = $.get(dataSourceUrl, dataSourceParams, function(response, textStatus) {

				if( response.result == "false")
				{
					$('.jsMainHeadding', $callbackContext).removeClass('loading')
					return
				}
				else if( response.serviceData == undefined )
				{
					$('.jsMainHeadding', $callbackContext).removeClass('loading')
					return
				}
				if( dataSourceParams.sort != undefined && response.sorted != true )
				{

					localDataNode.sort = dataSourceParams.sort
					localDataNode.order = dataSourceParams.order
					// sort data and update sort and order flags if required
					//TODO: sort here
					//if requested in different sort order then re-sort and set flags

				}
				$.localData.mergeData( response, localDataNode )

				dataPacket = {
					success : true, //successfully compleeted json request if we get this far (whether the requested business action failed will be in result.)
					result : response.result || true, //Did the executing the action result in a success or fail for the business commend (e.g. delete, or add)
					noteEnglish : "Fetched remote data successfuly", //used for english display and translation
					noteCode : 200, //used for programatic success and result handling
					serviceType : response.serviceType || dataSourceParams.serviceType || undefined, //reset serviceType if server specifies a different one (e.g. request for data on an unknown service type (get stream))
					serviceName : response.serviceName || dataSourceParams.serviceName || undefined, //reset serviceName if server specifies a different one (e.g. request for data on an unknown service type (get stream))
					pid : response.pid || dataSourceParams.pid || undefined,
					folder : response.folder || dataSourceParams.folder || undefined,
					"localDataNode" :  localDataNode,  //caller must rely on this data source in case needed to change (e.g. re-paging)
					dataSourceParams : dataSourceParams
				}

				if( $callback === null && specificTemplate != undefined)
					specificTemplate.update.call(specificTemplate, $callbackContext, dataPacket)
				else if( $callback == undefined  )
					$.templateEngine.templates[dataPacket.serviceType][dataPacket.serviceName].update.call($.templateEngine.templates[dataPacket.serviceType][dataPacket.serviceName], $callbackContext, dataPacket)
				else
					$callback($callbackContext, dataPacket)
				$('.jsMainHeadding', $callbackContext).removeClass('loading')

				//TODO thread in page info, complete set info etc.
				//TODO inteligently redirect storing of the data to a different node if the response data was different for whatever reason (e.g. stream asked for list not knpwn what type it is, server responds with data type)

			},"json")


			//N.B. sourceData can specify requesting list data, or thread data, or complete individual Message data (with or without attachment data or URLs) and
			// response must be handled accordingly to integrate results into the data store and sort accordingly, updating the sort and order flags

			//TODO: handling removing the data node if no longer exists on server when updating (e.g. folder deleted, message deleted, comment deleted)

			//TODO: only storing into social data schema for now, need to upgrade to store according to data type (e.g. contacts have a different store structure)

			//TODO: return must contain new pointer to data node in case server response required change to data pointer (e.g. folder deleted, message removed)

			//TODO: impliment handling of pages data that may be historical but not necessarily result in the dataset window being viewed being up to date with newest
			// e.g. localDataNode.pagesFetched = $.merge(localDataNode.pagesFetched, result.pagesFetched)

		},
		updateWithCallback : function(dataSourceUrl, dataSourceParams, localDataNode, $callbackContext, $callback)
		{



		},
		findById : function( folderData, id )
		{

			var threadNode = null
			$( folderData ).each( function(index, value)
			{

				if( typeof(value.id_str) != 'undefined' && value.id_str == id)
				{
					threadNode = value
					return false //break
				}
				if( value.id == id )
				{
					threadNode = value
					return false //break
				}

			})
			return threadNode

		},
		deleteByIds : function( folderData, ids )
		{

			$(ids).each( function(i,id)
			{
				$( folderData ).each( function(index, value)
				{

					if( value.id == id )
					{

						folderData.splice(index,1) //delete 1 entry starting from index (remove entry)
						return false //break

					}
					if( typeof(value.id_str) != 'undefined' && value.id_str == id)
					{

						folderData.splice(index,1) //delete 1 entry starting from index (remove entry)
						return false //break

					}

				})
			})
			return true

		},
		mergeData : function( response, localDataNode) {

			localDataNode.serviceData = response.serviceData//.reverse() //TODO: upgrade overwrite - needs to intelligently merge or complete if completeDataset = true
			localDataNode.lastUpdated = response.lastUpdated || 0
			localDataNode.completeDataset = response.completeDataset || localDataNode.completeDataset || false

		},
		addEventListener : function( eventName, eventFunction ) {

			//TODO: manage array of events handling so that external objects can register even listners that get triggered when data changes (e.g. notifying ui to remove an appointment object when that appointment is deleted in dataStore)
		},
		removeEventListener : function( eventName, eventFunction ) {
			//TODO
		},
		dataStore : { //N.B. folders are not stored hierarchically, they are stored flat
			pidStream : null, //N.B. there is no stream data because the stream template builds up its dataset from all the other datasources that it is aware of and has the ability to render
			pidEmail : {
				source1 : {
					serviceType : "Email",
					serviceName : "Email",
					nodeName : "source1",
					serviceDescription : "My Business Email",
					folders : {
						folder1 : {
							lastUpdated : 0,
							cacheTTL : 60,
							sort : undefined,
							order : undefined,
							serviceName : "email",
							parentFolderName : undefined,
							completeDataset : false, // set to true if reached the end of paging of if sent complete dataset in one hit
							serviceData : [ /* message array in pages as specified by object config (changes page config must repage data or discard and fetch new) */
								{ // First message
									mid : '123421',
									from:"",
									to:"",
									received:"",
									subject:"",
									summary:"",
									message : { /* complex prepared message object */}
								},
								{ /* Second Message... */ }


							]
						},
						folder2 : { lastUpdated : 0, cacheTTL : 60, sort : undefined, order : undefined, serviceName : "email", parentFolderName : "folder1", serviceData : [ /* message array */ ] }
					}
				},
				source2 : {
					serviceType : "Email",
					serviceName : "Email",
					nodeName : "source2",
					serviceDescription : "My Business Email",
					folders : {
						folder1 : {
							lastUpdated : 0,
							cacheTTL : 60,
							sort : undefined,
							order : undefined,
							serviceName : "Email",
							parentFolderName : undefined,
							completeDataset : false, // set to true if reached the end of paging of if sent complete dataset in one hit
							serviceData : [ /* message array in pages as specified by object config (changes page config must repage data or discard and fetch new) */
								{ // First message
									mid : '123421',
									from:"",
									to:"",
									received:"",
									subject:"",
									summary:"",
									message : { /* complex prepared message object */}
								},
								{ /* Second Message... */ }


							]
						},
						folder2 : { lastUpdated : 0, cacheTTL : 60, sort : undefined, order : undefined, serviceName : "email", parentFolderName : "folder1", serviceData : [ /* message array */ ] }
					}
				}
			},
			pidContacts : {
				source1 : {
					serviceType : "Contacts",
					serviceName : "LDAP",
					serviceDescription : "Company contact list",
					lastUpdated : 0,
					cacheTTL : 60,
					sort : undefined,
					order : undefined,
					serviceData : [ /* contacts array */ ] //N.B. each contact should contain its group, source, global etc.
				}
			},
			pidCalendar : {
				source1 : {
					serviceType : "Calendar",
					serviceName : "Calendar",
					serviceDescription : "My Business Calendar",
					lastUpdated : 0,
					cacheTTL : 60,
					sort : undefined,
					order : undefined,
					serviceData : [ /* appointment array */ ] //N.B. each appointment should have its group, calendarSource etc.
				}
			},
			pidX : {
				pid : "X",
				serviceType : "SocialNetwork",
				serviceName : "Facebook",
				serviceDescription : "Company Delta Campaign Facebook",
				folders : {
					wall : {
						lastUpdated : 0,
						cacheTTL : 60,
						sort : undefined,
						order : undefined,
						folder : "wall",
						folderName : "Wall",
						completeDataset : false, // set to true if reached the end of paging of if sent complete dataset in one hit
						serviceData : [
							{ mid : "1234563", meta : {from:"", to:"", received:"", summary:"", type : "status"}, message : {}, comments : {}, likes : {} },
							{ mid : "1234563", meta : {from:"", to:"", received:"", summary:"", type : "wall"}, message : {}, comments : {}, likes : {} },
						]
					},
					newsfeed : { lastUpdated : 0, cacheTTL : 60, sort : undefined, order : undefined, folder : "newsfeed", serviceFolder : "News Feed", serviceData : [ /* newsFeed array */ ] }
				}
			},
			pidY : {
				pid : "Y",
				serviceType : "SocialNetwork",
				serviceName : "Twitter",
				serviceDescription : "Company Delta Campaign Facebook",
				folders : {
					wall : {
						lastUpdated : 0,
						cacheTTL : 60,
						sort : undefined,
						order : undefined,
						folder : "wall",
						folderName : "Wall",
						completeDataset : false, // set to true if reached the end of paging of if sent complete dataset in one hit
						serviceData : [
							{ mid : "1234563", meta : {from:"", to:"", received:"", summary:"", type : "status"}, message : {}, comments : {}, likes : {} },
							{ mid : "1234563", meta : {from:"", to:"", received:"", summary:"", type : "wall"}, message : {}, comments : {}, likes : {} },
						]
					},
					newsfeed : { lastUpdated : 0, cacheTTL : 60, sort : undefined, order : undefined, folder : "newsfeed", serviceFolder : "News Feed", serviceData : [ /* newsFeed array */ ] }
				}
			},
			pidA : {
				pid : "A",
				serviceType : "SMS",
				serviceName : "SMSC",
				folders : {
					sent : {
						lastUpdated : 0, cacheTTL : 60, sort : undefined, order : undefined, folderName : "Missed calls", completeDataset : false,
						serviceData : [
							{ mid : "1234563", from:"", to:"", sent:"", message : {}, threadId : "" }, //threadID used to reassemble multi-party chats
							{ mid : "1234563", from:"", to:"", sent:"", message : {}, threadId : "" }, //threadID used to reassemble multi-party chats
						]
					},
					received : {
						lastUpdated : 0, cacheTTL : 60, sort : undefined, order : undefined, folderName : "Missed calls", completeDataset : false,
						serviceData : [
							{ mid : "1234563", from:"", to:"", sent:"", message : {}, threadId : "" }, //threadID used to reassemble multi-party chats
							{ mid : "1234563", from:"", to:"", sent:"", message : {}, threadId : "" }, //threadID used to reassemble multi-party chats
						]
					}
				}
			},
			pidB : {
				pid : "B",
				serviceType : "MMS",
				serviceName : "MMSC",
				lastUpdated : 0,
				cacheTTL : 60,
				sort : undefined,
				order : undefined,
				serviceData : [ /* twitter array */ ]
			},
			pidC : {
				pid : "C",
				serviceType : "Voicemail",
				serviceName : "BroadworksVoicemail",
				lastUpdated : 0,
				cacheTTL : 60,
				sort : undefined,
				order : undefined,
				serviceData : [ /* twitter array */ ]
			},
			pidD : {
				pid : "D",
				serviceType : "SIP",
				serviceName : "YTL",
				lastUpdated : 0,
				cacheTTL : 60,
				sort : undefined,
				order : undefined,
				folders : {
					CDR : {
						lastUpdated : 0,
						cacheTTL : 60,
						sort : undefined,
						order : undefined,
						folderName : "Calls",
						completeDataset : false, // set to true if reached the end of paging of if sent complete dataset in one hit
						serviceData : [
							{ mid : "1234563", meta : {from:"", to:"", received:"", summary:"", type : "status"}, message : {}, comments : {}, likes : {} },
							{ mid : "1234563", meta : {from:"", to:"", received:"", summary:"", type : "wall"}, message : {}, comments : {}, likes : {} },
						]
					},
					SMS : {
						lastUpdated : 0,
						cacheTTL : 60,
						sort : undefined,
						order : undefined,
						folderName : "SMS",
						completeDataset : false, // set to true if reached the end of paging of if sent complete dataset in one hit
						serviceData : [
							{ mid : "1234563", meta : {from:"", to:"", received:"", summary:"", type : "status"}, message : {}, comments : {}, likes : {} },
							{ mid : "1234563", meta : {from:"", to:"", received:"", summary:"", type : "wall"}, message : {}, comments : {}, likes : {} },
						]
					},
					Voicemail : {
						lastUpdated : 0,
						cacheTTL : 60,
						sort : undefined,
						order : undefined,
						folderName : "Voicemail",
						completeDataset : false, // set to true if reached the end of paging of if sent complete dataset in one hit
						serviceData : [
							{ mid : "1234563", meta : {from:"", to:"", received:"", summary:"", type : "status"}, message : {}, comments : {}, likes : {} },
							{ mid : "1234563", meta : {from:"", to:"", received:"", summary:"", type : "wall"}, message : {}, comments : {}, likes : {} },
						]
					}
				}
			}
		},
		genericFolderedDataNode : {
			pid : "",
			serviceType : "",
			serviceName : "",
			serviceDescription : "",
			folders : {}
		},
		genericDataNode : {
			pid : "Y",
			serviceType : "",
			serviceName : "",
			serviceDescription : "",
			lastUpdated : 0,
			cacheTTL : 60,
			sort : undefined,
			order : undefined,
			serviceData : []
		},
		genericFolderNode : {
			folderName : undefined,
			lastUpdated : 0,
			cacheTTL : 60,
			sort : undefined,
			order : undefined,
			serviceData : []
		}

	}

	//Null developer sample data so as not to poison real application data
	$.localData.dataStore = {}

	//TODO: upgrade templates to be able to render initially with cached data if available and then hit server for updates (if cache stale, or force refresh)

	//N.B. node data is populated seperately to list data, and the list data call can also return the first relevant node (if flagged in request) in its data response because rendering the list normally entails rendering the first node.

	//$.template engine is directly (performance) aware and depends on $.localData (just updated in case server needed to direct to different template)

	$.templateEngine = {

		templates : { Stream : {}, Email : {}, Contacts : {}, Calendar : {}, SocialNetwork : {}, SMS : {}, MMS : {}, Voicemail : {}, SIP : {} } //Append neatly externally

	}

	$.templateEngine.templates.SocialNetwork = { Generic : {}, Facebook : {}, Twitter : {} }

	$.templateEngine.showPanel = function($context, dataSourceUrl, dataSourceParams, localDataNode, specificTemplate, updateDataFromServer)
	{

		if( specificTemplate == undefined )																									//provide ability to provide specific template to use, else will calculate from data supplied
			specificTemplate = null

		if( updateDataFromServer == undefined )
			updateDataFromServer = true
		var dataPacket = $.localData.initializeData(dataSourceUrl, dataSourceParams, localDataNode)
		//get template directives from the response (i.e. if a request to get new data does not know what type the response will be then it must rely on the response data type to decide what template renderer to choose)
		//hand over to the template to produce the DOM modifications
		if( specificTemplate != null)
			specificTemplate.render.call(specificTemplate,$context, dataPacket)
		else
		{

			var templateType = dataPacket.serviceType || dataSourceParams.serviceType;
			var templateName = dataPacket.serviceName || dataSourceParams.serviceName;
			$.templateEngine.templates[templateType][templateName].render.call($.templateEngine.templates[templateType][templateName], $context, dataPacket)

		}

		if( updateDataFromServer )
		{
			if( specificTemplate != null )
				$.localData.callNewData(dataSourceUrl, dataSourceParams, localDataNode, $context, null, specificTemplate )
			else
				$.localData.callNewData(dataSourceUrl, dataSourceParams, localDataNode, $context )
		}
		//TODO: attempt to get parent template to handle requested method if method missing in requested template
		//TODO: gracefull handling if requested method can't be resolved to requeusted template or parents.
		//TODO: register any dataPoints that should be notified of dataChangeEvents

	}

	$.fn.showPanel = function( dataSourceUrl, dataSourceParams, localDataNode, specificTemplate, updateDataFromServer) {
		$.templateEngine.showPanel( $(this), dataSourceUrl, dataSourceParams, localDataNode, specificTemplate, updateDataFromServer )
		return $(this)
	}

})( jQuery );

function getLocalServiceData(folder, pid)
{
	return $.localData.dataStore["pid"+pid].folders[folder].serviceData;
}

function getUnreadCount(serviceData)
{
	count = 0
	$.each(serviceData, function(k, v){
		if( isUnread(v) ) ++count
	})

	return count
}

function isUnread(row)
{
	i = parseInt(row.readUnixGMT)
	return i == 0 || isNaN(i)
}

function updateLocalServiceData(folder, pid, row)
{
	serviceData = getLocalServiceData(folder, pid)

	for(key in serviceData) {
		node = serviceData[key]

		if(node.id == row.id) {
			for(key in row) {
				node.key = row.key
			}
			break;
		}
	}
}

function messagesAreInTheSameThread(message1, message2)
{
	//for a message to be in the same thread, currently requires total recipients list to be the same (order irrelevant)
	var dst1Processed = getPerson(message1.dst)
	var src1Processed = getPerson(message1.src)
	var src2Processed = getPerson(message2.src)
	var dst2Processed = getPerson(message2.dst)

	return dst1Processed == dst2Processed && src1Processed == src2Processed ||
		 dst1Processed == src2Processed && src1Processed == dst2Processed;
}