// $E Release H.D$
// $D http://wiki.newsonline.tc.nca.bbc.co.uk/wiki/moin.cgi/HieuLuuDanh/PanelMapFrameworkV2

/**
 * @fileOverview Data/Panel maps helper, version 2
 * @author BBC / Hieu Luu Danh &lt;hieu.danh (at) bbc.co.uk&gt;
 * @version 1.0-rls
 */
 

(function () {
	
	function createObject(strName) {
		var nameParts = strName.split("."),
		i = 0,
		len = nameParts.length,
		obj = window;
		
		for (; i < len; i++){
			if (obj[nameParts[i]] === undefined) {
				obj[nameParts[i]] = {};
			}
			
			obj = obj[nameParts[i]];
		}
	}
	
	createObject("bbc.fmtj.apps");
	
	bbc.fmtj.apps.createObject = createObject;
	
})();

bbc.fmtj.apps.createObject("bbc.fmtj.csd.PanelMapFrameworkV2");

bbc.fmtj.csd.PanelMapFrameworkV2 = {
	Master: function Master(glow) {
		var that = {};
		// is glow passed?
		if (typeof(glow) == 'undefined') {
			throw "Glow instance not passed.";
		}
		// stores glow for use inside this namespace
		bbc.fmtj.csd.PanelMapFrameworkV2.glow = glow;
		// MVC instantiation
		var model = new bbc.fmtj.csd.PanelMapFrameworkV2.Model(),
			controller = new bbc.fmtj.csd.PanelMapFrameworkV2.Controller(model),
			view = new bbc.fmtj.csd.PanelMapFrameworkV2.View(controller);
		
		// Start of program (Place where you start calling it)
		function init(opts) { // [Public] init()
			if (typeof(opts) == 'undefined') {
				throw "Options not passed";
			}
			// MVC framework up
			view.init(opts);
			// Pass on to controller init
			controller.init(opts);
		}
		that.init = init;
		
		return that;
	},
	Model: function Model() {
		var that = {};
		// calls out glow
		var glow = bbc.fmtj.csd.PanelMapFrameworkV2.glow;
		// stores constant
		var D = bbc.fmtj.csd.PanelMapFrameworkV2.Constants.D;
		
		var _type = "Model", // [Public] _type
			opts,
			l,
			htmlElms,
			panelStores = false,
			panelBridges = false;
		// public vars
		that._type = _type;
		
		function init(opts) { // [Public] init()
			opts = opts; // stores specs
			l = opts.model; // quickhand for model
		}
		that.init = init;
		
		function storeHtmlElms(htmlElmsPassed) { // [Public] injectHtmlElms()
			htmlElms = htmlElmsPassed;
		}
		that.injectHtmlElms = storeHtmlElms;
		
		function getPanelStores() { // [Public] getPanelStores()
			if (panelStores === false) {
				createPanelStores();
			}
			return panelStores;
		}
		that.getPanelStores = getPanelStores;
		
		function createPanelStores() { // [Private]
			var pStorage = [];
			
			htmlElms.each(function(i) {
				pStorage[i] = new bbc.fmtj.csd.PanelMapFrameworkV2.Classes.panelStore(this, {});
			});
			
			panelStores = pStorage;
		}
		
		function getPanelBridges() { // [Public] getPanelBridges()
			if (panelBridges === false) {
				createPanelBridges();
			}
			return panelBridges;
		}
		that.getPanelBridges = getPanelBridges;
		
		function createPanelBridges() { // [Private]
			var pBridgeArray = [];
			
			for (var i = 0, il = panelStores.length; i < il; i++) {
				pBridgeArray[i] = new bbc.fmtj.csd.PanelMapFrameworkV2.Classes.panelBridge(panelStores[i], {});
			}
			
			panelBridges = pBridgeArray;
		}
		
		function panelBridgesRegisterEachOther() { // [Public] panelBridgesRegisterEachOther()
			for (var i = 0, il = panelBridges.length; i < il; i++) {
				for (var j = 0, jl = panelBridges.length; j < jl; j++) {
					if (i == j) {
						continue; // can't subscribe itself!
					} else {
						panelBridges[i].subscribe(panelBridges[j]);
					}
				}
			}
		}
		that.panelBridgesRegisterEachOther = panelBridgesRegisterEachOther;
		
		return that;
	},
	Controller: function Controller(model) {
		var that = {};
		// calls out glow
		var glow = bbc.fmtj.csd.PanelMapFrameworkV2.glow;
		// stores constant
		var D = bbc.fmtj.csd.PanelMapFrameworkV2.Constants.D;
		
		var _type = "Controller", // [Public] _type
			model = model,
			view,
			opts,
			l,
			context;
		// public vars
		that._type = _type;
		
		function receive(obj) { // [Public] announce()
			if (obj._type == "View") {
				view = obj;
			}
		}
		that.announce = receive;
		
		function init(opts) { // [Public] init()
			opts = opts; // stores specs
			l = opts.controller; // quickhand for contrl
			
			// variables
			var htmlElms,
				panelStores,
				panelBridges,
				areas,
				image;
			
			// MVC Framework up (final)
			model.init(opts);
			
			// Set up context
			context = view.getContext();
			// Scoop up HTMLElms
			htmlElms = view.getHtmlElms();
			// Remove static
			view.removeStatic(htmlElms);
			// Passes onto Model
			model.injectHtmlElms(htmlElms);
			// Creates panelStores and get them
			panelStores = model.getPanelStores();
			// Creates panelInstances
			panelBridges = model.getPanelBridges();
			// Set them to the correct pos
			view.setPanelPosition(panelStores, panelBridges, context);
			// panelBridges have each other registered (observe = next step?)
			model.panelBridgesRegisterEachOther();
			
			// Hook on areas
			areas = glow.dom.get(D.layout).get("area");
			areas.each(function(i) {
				if (glow.lang.trim(this.className) == D.area_ignore) {
					return;
				}
				var id = this.href.split("#")[1];
				for (var j = 0, jl = panelBridges.length; j < jl; j++) {
					var tId = glow.lang.trim(id);
					var tPId = glow.lang.trim(panelBridges[j].getId());
					if (tId == tPId) {
						var pb = panelBridges[j];
						glow.events.addListener(
							this,
							"click",
							function() {
								pb.interact();
								return false;
							},
							this);
					}
				}
			});
			// Hook on image... if not IE
			if (!glow.env.ie) {
				image = glow.dom.get(D.layout).get("img");
				glow.events.addListener(
					image,
					"click",
					function() {
						for (var i = 0, il = panelBridges.length; i < il; i++) {
							panelBridges[i].hidePanel();
						}
						return false;
					}
				);
			}
			
			
		}
		that.init = init;
		
		return that;
	},
	View: function View(controller) {
		var that = {};
		// calls out glow
		var glow = bbc.fmtj.csd.PanelMapFrameworkV2.glow;
		// stores constant
		var D = bbc.fmtj.csd.PanelMapFrameworkV2.Constants.D;
		
		var _type = "View", // [Public] _type
			controller = controller,
			opts,
			l;
		// public vars
		that._type = _type;
		
		function init(opts) { // [Public] init()
			opts = opts; // stores specs
			l = opts.view; // quickhand for view
			controller.announce(self);
		}
		that.init = init;
		
		function getContext() { // [Public] getContext()
			return glow.dom.get(l.closureId.glow);
		}
		that.getContext = getContext;
		
		function getHtmlElms() { // [Public] getHtmlElms()
			return glow.dom.get(l.closureId.glow).get(D.content).children();
		}
		that.getHtmlElms = getHtmlElms;
		
		function removeStatic(elms) { // [Public] removeStatic()
			elms.each(function(i) {
				var cArray = this.className.split(" ");
				for (var j = 0, jl = cArray.length; j < jl; j++) {
					if (cArray[j].match(new RegExp("static"))) {
						glow.dom.get(this).removeClass(glow.lang.trim(cArray[j]));
					}
				}
			});
		}
		that.removeStatic = removeStatic;
		
		function setPanelPosition(panelStores, panelBridges, context) { // [Public] setPanelPosition()
			for (var i = 0, il = panelStores.length; i < il; i++) {
				var ptop = panelStores[i].getJson("top");
				if (ptop == "auto") {
					ptop = parseInt(context.offset().top) + 4;
				} else {
					ptop = parseInt(context.offset().top) + parseInt(ptop);
				}
				var pleft = panelStores[i].getJson("left");
				if (pleft == "auto") {
					pleft = parseInt(context.offset().left) + 
					((context.width() - parseInt(panelStores[i].getWidth())) / 2);
				} else {
					pleft = parseInt(context.offset().left) + parseInt(pleft);
				}
				panelBridges[i].setTopAndLeft({top: ptop, left: pleft});
			}
		}
		that.setPanelPosition = setPanelPosition;
		
		var self = that; // must be at the end, before return that;
		return that;
	},
	glow: {} // stores passed glow
}

bbc.fmtj.csd.PanelMapFrameworkV2.Classes = {
	panelStore: function panelStore(elm, args) { // classified under M; stores panel data from HtmlElm
		var that = {};
		// calls out glow
		var glow = bbc.fmtj.csd.PanelMapFrameworkV2.glow;
		// constants
		var D = bbc.fmtj.csd.PanelMapFrameworkV2.Constants.D;
		
		// Get type of panel (relies on metadata)
		var mdJson = bbc.fmtj.csd.PanelMapFrameworkV2.Mixins.metadataToJson(glow.dom.get(elm).get(D.metadata));
		var gElm = glow.dom.get(elm);
		
		function getType() { // [Public] getType()
			return glow.lang.trim(mdJson.type);
		}
		that.getType = getType;
		function getElm() { // [Public] getElm()
			return gElm;
		}
		that.getElm = getElm;
		function getWidth() { // [Public] getWidth()
			return glow.lang.trim(mdJson.width);
		}
		that.getWidth = getWidth;
		function getId() { // [Public] getId()
			return glow.lang.trim(mdJson.id);
		}
		that.getId = getId;
		function getJson(key) { // [Public] getJson()
			return glow.lang.trim(mdJson[key]);
		}
		that.getJson = getJson;
		
		return that;
	},
	panelBridge: function panelBridge(pStore, args) { // works with C; bridge for glow.widgets.Overlay.Panel
		var that = {};
		// calls out glow
		var glow = bbc.fmtj.csd.PanelMapFrameworkV2.glow;
		// constants
		var D = bbc.fmtj.csd.PanelMapFrameworkV2.Constants.D;
		// class var
		var bridges = [],
			hiddenOnce = false,
			empDefaultProp = false;
		
		// create a new glow Panel
		var panel;
		panel = new glow.widgets.Panel(pStore.getElm(), {
			width: parseInt(pStore.getWidth()),
			theme: 'light',
			modal: false,
			autoPosition: false
		});
		panel.container.addClass(D.panelPrefix + pStore.getType());
		panel.container.addClass(D.panelClass);
		
		// store the AV if any
		var av;
		av = (pStore.getType() == "av") ? {} : null;
		
		function getId() { // [Public] getId()
			return pStore.getId();
		}
		that.getId = getId;
		
		function showHidePanel() { // [Public] showHidePanel()
			if (panel.isShown) {
				internalHide();
			} else {
				internalShow();
			}
		}
		that.showHidePanel = showHidePanel;
		function showPanel() { // [Public] showPanel()
			if (panel.isShown) {
			} else {
				internalShow();
			}
		}
		that.showPanel = showPanel;
		function hidePanel() { // [Public] hidePanel()
			if (panel.isShown) {
				internalHide();
			} else {
			}
		}
		that.hidePanel = hidePanel;
		
		function setTopAndLeft(hash) { // [Public] setTopAndLeft()
			panel.container.css("top", hash.top + "px");
			panel.container.css("left", hash.left + "px");
		}
		that.setTopAndLeft = setTopAndLeft;
		
		function subscribe(bridge) { // [Public] subscribe()
			bridges.push(bridge);
		}
		that.subscribe = subscribe;
		
		function interact() { // [Public] interact()
			for (var i = 0, il = bridges.length; i < il; i++) {
				bridges[i].hidePanel();
			}
			showHidePanel();
			return false;
		}
		that.interact = interact;
		
		function storeAV() { // [Private]
			av.cloneElm = panel.container.get(D.avdiv).clone();
			if (av.cloneElm.length != 1) {
				throw "AV Item problem";
			}
		}
		
		if (av != null) {
			storeAV();
			// hooks on hide and show
			glow.events.addListener(
				panel,
				"hide",
				function() { internalHide(":glow"); }
			);
		}
		
		function internalHide(s) { // [Private]
			// does not have to worry about isShown
			if (av != null) {
				panel.container.get(D.avdiv).replaceWith("<div class='" + D.avdiv.split(".")[1] + "'></div>");
				hiddenOnce = true;
			}
			if (s != ":glow") {
				panel.hide();
			}
		}
		function internalShow(s) { // [Private]
			panel.show();
			if (av != null && hiddenOnce) {
				if (glow.env.ie) {
					var place = panel.container.get(D.avdiv);
					if (empDefaultProp === false) {
						empDefaultProp = new bbc.emp_fmtj_default_properties();
					}
					new glow.embed.Flash(
						empDefaultProp.swfObj.server + empDefaultProp.swfObj.player9,
						place,
						"9",
						{ width: pStore.getJson("av_width"), height: pStore.getJson("av_height"),
							attributes : {
								id : pStore.getJson("av_id")
							},
							params : { flashVars: {
									config_settings_autoPlay: pStore.getJson("av_config_settings_autoPlay"),
									config_settings_showPopoutButton: pStore.getJson("av_config_settings_showPopoutButton"),
									autoPlay: pStore.getJson("av_autoPlay"),
									config_plugin_fmtjLiveStats_pageType: pStore.getJson("av_config_plugin_fmtjLiveStats_pageType"),
									config_plugin_fmtjLiveStats_edition: pStore.getJson("av_config_plugin_fmtjLiveStats_edition"),
									fmtjDocURI: pStore.getJson("av_fmtjDocURI"),
									playlist: pStore.getJson("av_playlist")
							}},
							message : "<div>You do not seem to have the required Flash version for this media. Please get latest Flash <a href='get.adobe.com/flashplayer/'>here.</a></div>"
						}
					).embed();
				} else {
					panel.container.get(D.avdiv).replaceWith(av.cloneElm);
				}
				av.cloneElm = av.cloneElm.clone();
			}
		}
		
		return that;
	}
}

bbc.fmtj.csd.PanelMapFrameworkV2.Constants = {
	D: {
		content: "div#pmfwk-content-closure",
		metadata: "span.pmfwk-content-metadata",
		panelPrefix: "pmfwk-content-panel-",
		panelClass: "pmfwk-content-panel",
		layout: "div#pmfwk-layout-closure",
		avdiv: "div.pmfwk-av",
		area_ignore: "pmfwk-ignore"
	}
}

bbc.fmtj.csd.PanelMapFrameworkV2.Mixins = {
	metadataToJson: function metadataToJson(metadata) {
		var json = {};
		// calls out glow
		var glow = bbc.fmtj.csd.PanelMapFrameworkV2.glow;
		
		metadata.get("dl").children().each(function(i) {
			var self = glow.dom.get(this);
			if (self.is("dt")) {
				json[self.text()] = self.next().text();
			}
		});
		
		return json;
	}
}