/**
 * $Id$
 * 
 * Project Name: 	Discovery 'Now showing in your region' Widget
 * Version:			1.2
 * Author:			alucas
 * Created:			19/09/2008
 * Last Modified:	19/09/2008
 * 					Complete rewrite of version 0.5
 * 
 * Description:		Provides a basic javascript type (AbstractWidgetInstance) to allow the creation
 * 					of ajax widgets which use a 'Discovery TV Listings version 2' service.
 * 
 * 					Provides implementations of time and series widgets
 * 					based on the abstract widget type.
 * 
 * 					You can request instances by using the associated factory methods:
 * 						<code>AbstractWidgetFactory</code>,
 * 						<code>SeriesWidgetFactory</code>,
 * 						and <code>TimeWidgetFactory</code>.
 * 
 * Objects in Global Scope:
 * 					<code>ListingsWidget</code>
 * 
 * Requirements:	Akamai ESI scripting is required for the geocode value
 */

if (!ListingsWidget) {
	
	var ListingsWidget = {
		util: {
		
			xhrObjectFactory: function () {
				if (window.ActiveXObject) {
					this.xhrObjectFactory = function () {
						return new ActiveXObject("Microsoft.XMLHTTP")
					}
					return new ActiveXObject("Microsoft.XMLHTTP")
				} else {
					this.xhrObjectFactory = function () {
						return new XMLHttpRequest();
					}
					return new XMLHttpRequest();
				}
			},
		
			httpGet: function (url, handler) {
				var xhr = this.xhrObjectFactory();
				xhr.open('GET', url, true);
				xhr.onreadystatechange = function (ev) {
					if (xhr.readyState == 4) {
						if (xhr.status == 200) {
							handler(xhr);
						}
					}
				}
				xhr.send(null);
			},
		
			buildUrl: function (url, params) {
				//create query string
				var tmp_str = "";
				for (var i in params) {
					if (params[i] !== false) {
						var q = params[i] ? "=" + escape(params[i]) : "";
						tmp_str += "&" + escape(i) + q;
					}
				}
				
				//arrange the new url
				var value = url + "?" + tmp_str.slice(1);
				
				//return the completed url
				return value;
			},
			
			getFormattedDate: function (date) {
				var day = "0" + date.getDate().toString();
				day = day.slice(-2);
				var year = date.getFullYear().toString();
				var month = "0" + (date.getMonth() + 1);
				month = month.slice(-2);
				var date = day + month + year;
				return date;
			},
			
			getFormattedDatetime: function (date) {
				return this.getFormattedDate(date) +
					("0" + date.getHours()).slice(-2) +
					("0" + date.getMinutes()).slice(-2);
			},
			
			removeChildren: function (elem) {
				while(elem.hasChildNodes()) {
					elem.removeChild(elem.firstChild);
				}
			}
		}
	}
	
	
	ListingsWidget.AbstractWidgetFactory = function (listings_address, freeze_date) {
		
		function WidgetInstance (listings_address, freeze_date) {
			
			//property to hold page element which contains this widget
			this.container = {};
			
			//initialise instance properties
			this.settings = {
				style: "",
				service_name: "",
				app_address: "/dni-tvlistings/",
				listings_address: listings_address,
				geocode: ListingsWidget.geoCode(), 
				
				//freeze the date to when the object was created
				freeze_date: freeze_date ? true : false
			}
			
			//store current date object and create getter 
			var this_date = new Date();
			
			this.creationDate = function () {
				return this_date;
			}
			
			//initialise basic request parameters
			this.properties = {
				date: false, datetime: false,
				country_code: false, channel_code: false,
				geocode: ListingsWidget.geoCode()			
			}
			
		}
		
		WidgetInstance.prototype.type = "generic";
		
		//returns the date based on current settings
		WidgetInstance.prototype.getDate = function () {
			if (this.settings.freeze_date) { return this.creationDate() }
			else { return new Date() }
		}
		
		//basic generic request parameters
		WidgetInstance.prototype.setProperties = function (props) {
			for (var i in props) {
				this.properties[i] = props[i];
			}
		}
		
		
		
		//setters for basic request parameters
		
		WidgetInstance.prototype.setDate = function (value) {
			if (!value) var value = this.getDate();
			this.properties.date = value;
		}
		
		WidgetInstance.prototype.setDatetime = function (value) {
			if (!value) var value = this.getDate();
			this.properties.datetime = value;
		}
		
		WidgetInstance.prototype.setCountryCode = function (value) {
			this.properties.country_code = value;
		}
		
		WidgetInstance.prototype.setChannelCode = function (value) {
			this.properties.channel_code = value;
		}

		

		//Request related methods
		
		WidgetInstance.prototype.request = {
			make: function (callback) {
				
				var self = this;
				var url = self.settings.app_address + self.settings.service_name;
			
				//gather GET request data
				var data = self.properties;
				if ((!data.geocode)&&(self.settings.geocode)) {
					data.geocode = self.settings.geocode;
				}
				data.style = self.settings.style;
				
				//format date and datetime
				if (data.date) data.date = ListingsWidget.util.getFormattedDate(data.date);
				if (data.datetime) data.datetime = ListingsWidget.util.getFormattedDatetime(data.datetime);
				
				//make request
				ListingsWidget.util.httpGet(ListingsWidget.util.buildUrl(url, data), function (xhr) {
					self.request.process.apply(self, [xhr.responseText, callback]);
				})
		
			},
	
			process: function (responseText, callback) {
				
				var self = this;
				
				//unique html id for this SeriesNextShowingObject instance
				var id = document.createAttribute("id");
				id.nodeValue = self.type + "-" + self.instance;
				var cls = document.createAttribute("class");
				cls.nodeValue = "widget-view";
				
				//create widget body with unique id
				var body = document.createElement("div");
				body.setAttributeNode(id);
				body.setAttributeNode(cls);
				body.innerHTML = responseText;
				
				if ((!self.settings.contentLock)
						&&(self.settings.contentLock = true)) {
					ListingsWidget.util.removeChildren(self.container);
					self.container.appendChild(body);
					setTimeout(function(){self.settings.contentLock = false;}, 2000);
				}
				
				if (callback) callback();
		
			}
		}
		
		ListingsWidget.AbstractWidgetFactory = function (listings, freeze) {
			return new WidgetInstance(listings, freeze);
		}
		
		return ListingsWidget.AbstractWidgetFactory(listings_address, freeze_date);
		
	}
	
	
	
	ListingsWidget.SeriesWidgetFactory = function (config) {
		
		var instanceNumber = 0;
		
		function SeriesWidgetInstance (settings) {
			
			this.instance = instanceNumber++;
			
			this.setSeriesId(settings["Series Id"]);
			this.setListingsAddress(settings["Listings URL"]);
			this.setLanguageCode(settings["Language"]||false);
			this.setKeyword(settings["Keyword"]);
			
			if (typeof settings.container == "object") {
				this.getContainer = function () {
					return settings["Container"];
				}
			} else {
				this.getContainer = function () {
					return document.getElementById(settings["Container"]);
				}
			}
		}
		
		
		//prototype setup
		
		SeriesWidgetInstance.prototype = ListingsWidget.AbstractWidgetFactory();
		
		SeriesWidgetInstance.prototype.type = "serieswidget";
		SeriesWidgetInstance.prototype.settings.style = "region-next-showing";
		SeriesWidgetInstance.prototype.settings.service_name = "GetNextShowingInRegion";
		
		SeriesWidgetInstance.prototype.properties.series_id = false;
		SeriesWidgetInstance.prototype.properties.keyword = false;
		
		
		//setters for request parameters
		
		SeriesWidgetInstance.prototype.setListingsAddress = function (value) {
			this.properties.next_showing_url = value;
		}
		
		SeriesWidgetInstance.prototype.setLanguageCode = function (value) {
			this.properties.next_showing_language = value;
		}
		
		SeriesWidgetInstance.prototype.setSeriesId = function (value) {
			this.properties.series_id = value;
		}
		
		SeriesWidgetInstance.prototype.setKeyword = function (value) {
			this.properties.keyword = value;
		}
		
		
		//load method override
		
		SeriesWidgetInstance.prototype.load = function () {
			this.container = this.getContainer();
			this.setDatetime(this.getDate());
			this.request.make.apply(this);
		}
		
		
		ListingsWidget.SeriesWidgetFactory = function (settings) {
			return new SeriesWidgetInstance(settings);
		}
		
		return ListingsWidget.SeriesWidgetFactory(config);
		
	}
	
	ListingsWidget.TimeWidgetFactory = function (config) {
		
		var instanceNumber = 0;
		
		function TimeWidgetInstance (settings) {
			
			this.instance = instanceNumber++;
			
			//create reset method to allow config to be reset 
			this.reset = function () {
				this.setChannelCode(settings["Channel Code"]||false);
				this.setCountryCode(settings["Country Code"]||false);
				this.setListingsAddress(settings["Listings URL"]);
			}
			this.reset();
			
			//set request datetime
			switch (typeof settings["Date & Time"]) {
				case "object":
					this.setDatetime(settings["Date & Time"]);
					break;
				case "string":
					this.setProperties({"date_time": settings["Date & Time"]});
					break;
			}
			
			//allow lazy loading of container if passed its id string
			if (typeof settings["Container"] == "object") {
				this.getContainer = function () { return settings["Container"] }
			} else if (!settings["Fallback"]) {
				this.getContainer = function () {
					return document.getElementById(settings["Container"]);
				}
			} else {
				this.getContainer = function () {
					var elem = document.getElementById(settings["Container"]);
					if (!elem) {
						elem = document.createElement("div");
						document.body.appendChild(elem);
					}
					this.getContainer = function () { return elem }
					return this.getContainer();
				}
			}			
		}
		
		TimeWidgetInstance.prototype = ListingsWidget.AbstractWidgetFactory();
		
		TimeWidgetInstance.prototype.type = "timewidget";
		
		TimeWidgetInstance.prototype.settings.style = "widget";
		TimeWidgetInstance.prototype.settings.service_name = "GetScheduleByTime";
		
		TimeWidgetInstance.prototype.setListingsAddress = function (value) {
			this.settings.listings_address = value;
		}
		
		TimeWidgetInstance.prototype.load = function (dateOverride) {
			this.container = this.getContainer();
			this.setDatetime(dateOverride||this.getDate());
			var this_ = this;
			this.request.make.apply(this, [ function () {
				this_.processDescriptions();
				if (this_.settings.listings_address) {
					this_.parseLinks();
				}
			} ]);
		}
		
		TimeWidgetInstance.prototype.parseLinks = function () {	
			var links = this.container.getElementsByTagName("a");
			var nav_links = this.container.getElementsByTagName("option");			
			for (var i=0,k;k=links[i];i++)
				this.createListingsLink(k);
			for (var i=0,k;k=nav_links[i];i++)
				this.parseNavItem(k);
		}
		
		
		TimeWidgetInstance.prototype.parseNavItem = function (elem) {
			var this_ = this;
			elem.onclick = function () {
				this_.setCountryCode(elem.value);
				this_.setProperties({channel_code:false});
				this_.load();
			}
		}
		
		var link_regex = /([^ ]+(__[^ ]*))/g;

		TimeWidgetInstance.prototype.createListingsLink = function (elem) {
			var text_data = elem.className.match(link_regex);
			if (text_data) {
				var data = {}
				for (var i=text_data.length-1,k;k=text_data[i];i--) {
					var n = k.split("__");
					data[n[0]] = n[1];
				}
				elem.href = ListingsWidget.util.buildUrl(this.settings.listings_address, data);
			}
		}

		var desc_regex = /(?:^| )(description)(?: |$)/;
		var start_regex = /(?:^| )(start-time)(?: |$)/;
		var episode_regex = /(?:^| )(episode-title)(?: |$)/;
		var blank_regex = /^[ ]*$/;
		
		TimeWidgetInstance.prototype.processDescriptions = function () {
			if (($)&&($.tooltip)) {
				var items = this.container.getElementsByTagName("dl");
				for (var i=0,k;k=items[i];i++) {
					var dd = k.getElementsByTagName("dd");
					for (var l=0,m;m=dd[l];l++) {
						if (m.className.match(desc_regex)) {
							generateTooltip(m.parentNode);
							truncDescription(m);
						}
					}
				}
			}
		}
		
		function truncDescription (elem) {
			var suffix = " ...";
			var max = 50 - suffix.length;
			if (elem.innerHTML.length > max) {
				elem.innerHTML = elem.innerHTML.slice(0, max) + suffix; 
			}
		}
		
		function generateTooltip (elem) {
			var title = elem.getElementsByTagName("dt").item(0);
			if (title) title = title.textContent||title.innerText;
			var items = elem.getElementsByTagName("dd");
			var content = "", stitle = "";
			for (var i=0,k;k=items[i];i++) {
				if (k.className.match(start_regex)) {
					stitle = k.innerHTML;
				} else if (k.className.match(desc_regex)) {
					content = k.innerHTML;
				}
			}
			attachTooltip(elem, createTooltip( title, stitle, content), "widget");
		}
		

		
		function createTooltip (title, stitle, content) {
			var elem = document.createElement("dl");
			elem.className = "js_tooltip";
			var titleElem = createTooltipTitle(title);
			elem.appendChild(titleElem);
			
			if (stitle) {
				var stitleElem = createTooltipSubTitle(stitle);
				elem.appendChild(stitleElem);
			}			
			if ((content !== null)&&(!content.match(blank_regex))) {
				elem.appendChild(createTooltipDescription(content));
			}

			return elem;
		}
		
		function attachTooltip (elem, tooltip, type) {
			if (!type) var type = " generic";
			var elem = $(elem).parent();
			elem.tooltip({
				track: true,
				delay: 400,
				extraClass: "js_tooltip " + type,
				bodyHandler: function(){
				return tooltip;
				}
			});
			elem.mouseover(function () { $("#tooltip").css("opacity", ".95")})
		}
		
		function createTooltipTitle (title) {
			var elem = document.createElement("dt");
			var strong = document.createElement("strong");
			strong.innerHTML = title;
			elem.appendChild(strong);
			return elem;
		}
		
		function createTooltipSubTitle (stitle) {
			var elem = document.createElement("dd")
			elem.className = "sub-title";
			elem.innerHTML = stitle;
			return elem;
		}
		
		function createTooltipDescription (content) {
			var elem = document.createElement("dd")
			elem.className= "content";
			elem.innerHTML = content;
			return elem;
		}
				
		ListingsWidget.TimeWidgetFactory = function (settings) {
			return new TimeWidgetInstance(settings);
		}
		
		return ListingsWidget.TimeWidgetFactory(config);
		
	}	
	
	
	
	ListingsWidget.PrimeTimeWidgetFactory = function (config) {
		
		var inst = this.TimeWidgetFactory(config);
		inst.settings.style = "widget-prime-time";
		return inst;
		
	}
	
}



if (!ListingsWidget.geoCode) {
	ListingsWidget.geoCode = function () {
		/*  */ var geocode = "IN"; //
		if (geocode.indexOf("$") == -1) {
			ListingsWidget.geoCode = function() {
				return geocode;
			}
		} else {
			ListingsWidget.geoCode = function () { return false }
		}
	}
}




