function VidegoAPIController() {
	this.initialize('0');
}

function VidegoAPIController(apiVersion) {
    this.initialize(apiVersion);
}

/**
 * Static Constants
 */

VidegoAPIController.APP_TOKEN = '54d84550-2e85-102a-a1ba-00e08155b9fb';
VidegoAPIController.API_VERSION = 3;
VidegoAPIController.DEBUG = false;

VidegoAPIController.JSAPI_VERSION_URL = VidegoAPIController.JSAPI_URL + (VidegoAPIController.API_VERSION > 0 ? (VidegoAPIController.API_VERSION + '/') : '');

VidegoAPIController.prototype = {

	async: true,

	requests: [],

    initialize: function() {
		this.async = true;
		this.requests = new Array();
    },

	setLoadingDomain: function(loadingDomain) {
		VidegoAPIController.JSAPI_URL = loadingDomain + '/jsapi/';
		VidegoAPIController.SERVICE_URL = loadingDomain + '/services/';
		VidegoAPIController.JSAPI_VERSION_URL = VidegoAPIController.JSAPI_URL + (VidegoAPIController.API_VERSION > 0 ? (VidegoAPIController.API_VERSION + '/') : '');
		VidegoAPIController.FLASH_FALLBACK_SWF_URL = loadingDomain +'/templates/osmf/osmf_ver1_6_strobemediaPlayback.swf';
	},

	/**
		Bootstraps the embedding of the a player into the webpage.

		params {
			target = The jQuery div to embed into
			requestType = Service name or "custom"
			customRequestFunction = Function to execute on "custom" requestType
			request = Parameters for the request
			onRequest = Callback function hit before a request is made
			onResponse = Callback function hit when the response comes back from the server
			onComplete = Callback function hit when the player has been embedded
			previewFunction = Use preview mode flag
		}
	 */
    bootstrap: function(params) {
		var thisClass = this;

		if (params.debug) {
			VidegoAPIController.DEBUG = true;
		}
		if (params.loadingDomain) {
			this.setLoadingDomain(params.loadingDomain);
		}

		$(function () {
	    	// Include Libraries
			$.getScript(VidegoAPIController.JSAPI_VERSION_URL + 'jQueryPlugins.js', function() {
				$.getScript(VidegoAPIController.JSAPI_VERSION_URL + 'VidegoValueObjects.js', function() {
			    	// Instantiate the WebService
			    	var service = null;
			    	if (params.requestType == VidegoWebService.SERVICE_GET_PLAYER_INFO) {
			    		$.getScript(VidegoAPIController.JSAPI_VERSION_URL + 'GetPlayerInfo.service.js', function () {
			    			service = new GetPlayerInfo(params.request);
			    	    	if (service != null) {
								if (params.target) {
									service.target = params.target;
								}
			    	    		thisClass._continueBootstrap(params, service);
			    	    	}
			    		});
			    	} else if (params.requestType == 'custom') {
			    		if (params.customRequestFunction) {
			    			params.customRequestFunction(params);
			    		}
			    	}
		        	// TODO: Add more services here
				});
			});
		});
	},
	
	_continueBootstrap: function(params, service) {
    	// Execute the WebService
		if(params.onRequest) {
			params.onRequest(service);
		}
    	service.submit(
			function (thisService) {
				if (params.onResponse) {
					params.onResponse(thisService);
				}
				if (service.target) {
					if (params.previewFunction) {
						var previewData = params.previewFunction();
						thisService.embed(true, previewData.html || '', previewData.js || '');
					} else {
						thisService.embed(false);
					}
				}
				if (params.onComplete) {
					params.onComplete(thisService);
				}
			}
		);
    },
    
    // Submits the WebService
    submit: function(service) {
    	var json     = new JSONRequest(VidegoAPIController.SERVICE_URL);
    	json.service = service;

		// Get XML for the specific service request
		var requestXML = service.getRequestXML();
		
		// wrap header + authentication into request
		requestXML = this.wrapXML(requestXML);
		
    	this.requests[json.requestID] = json;
		debug("XML Request: <pre>" + requestXML + "</pre>");
    	json.submit(requestXML);
    	debug("JSON requestID: " + json.requestID);
   	},

    wrapXML: function(xml) {
    	newxml = "<request>"+
    		  "<authentication><app_token>" + VidegoAPIController.APP_TOKEN + "</app_token></authentication>" +
    		  "<header><header_version>1</header_version><api_version>" + VidegoAPIController.API_VERSION + "</api_version></header>" + 
    		  xml +
    		  "</request>";
    		  
    	return newxml;
    },

    JSONResponse: function(response) {
//    	debug("In VidegoAPI.JSONResponse");
//    	debug("Response XML: " + response.xml);
    	
    	// Get a hook to the service call that initiated this request
    	var service = this.requests[response.data.requestID].service;
    	
    	// Gets back an object, not an xmlDoc from the response XML
    	var xml = response.xml;
    	
    	// @todo - add error handling here
		// xml.response.success[i]
		// xml.response.failure[i]
		    	
		// Get the tag Name of the service
		var tagName = service.getXMLTag();

		// TODO: Check if tag exists
		// The $.xmlDOM() function is a plugin used to create an XML DOM object from a string
		var jServiceXML = $("response > " + tagName + "_response", $.xmlDOM(xml));
    	service.handleResponseXML(jServiceXML);
//    	this.detectBandwidth(service);
	},

	parseQueryString: function(name) {
    	name = name.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]"); var regex = new RegExp("[\?&]"+name+"=([^&#]*)"); var results = regex.exec(window.location.href); return results == null ? "" : results[1];
	},

	detectBandwidth: function(service) {

//		debug("Detecting bandwidth...");
		var checkBandwidthImageLoaded = function() {
//			debug("Bandwidth check done");
			var dt2 = new Date();

			var timeDiff = dt2.getTime() - dt.getTime();
			var kbps = (38702 / timeDiff) * 8;
//			console.log("Image Detect 2 - TimeDiff: " + timeDiff + " | bitrate: " + kbps/8 + "KBps | bitrate2: " + kbps + "Kbps");
			$('[msComponent]', service.target).trigger({type: 'player', action: 'bandwidthDetected', value: kbps});
		};

		var bwImage = new Image();
		bwImage.onload = checkBandwidthImageLoaded;

		var dt = new Date();
		bwImage.src = VidegoAPIController.JSAPI_VERSION_URL + 'bwDetectImage.jpg';
	},
	
	prepareView: function(service) {
		if (service.target) {
			var view = $(document.createElement('DIV')).attr('msComponent','jsView').css('display','none');
			service.target.prepend(view);
			service.target[0].view = view[0];
			service.target[0].service = service;

			$.extend(view[0], {
				playerLoaded: false,

				viewLoaded: false,

				uiLoaded: false,

				uiPluginsLoaded: [],

				loadUI: function(plugins, callback) {
					var mySelf = this;

					if (!mySelf.uiLoaded) {
						$.getScript(VidegoAPIController.JSAPI_VERSION_URL + "jQueryUI.js", function() {
							mySelf.uiLoaded = true;
							mySelf.loadUIPlugins(plugins, callback);
						});
					} else {
						mySelf.loadUIPlugins(plugins, callback);
					}
				},
				
				loadUIPlugins: function(plugins, callback) {
					var pluginNames = this.uiPluginsLoaded;

					var pluginCountToLoad = plugins.length;

					while (plugins.length > 0) {
						var pluginName = plugins.pop();
						debug("Checking plugin: " + pluginName);
						if ($.inArray(pluginName, pluginNames) > -1) {
							debug("Plugin already loaded: " + pluginName);
							pluginCountToLoad--;
						} else {
							debug("Loading plugin: " + pluginName);
							$.getScript(VidegoAPIController.JSAPI_VERSION_URL + "jQueryUI." + pluginName + ".js", function() {
								debug("Plugin: " + pluginName + " loaded | remaining: " + pluginCountToLoad);
								pluginNames.push(pluginName);
								pluginCountToLoad--;
							});
						}
					}
					var pluginLoaderPollInverval;
					
					var pluginLoaderPoll = function() {
						debug("Poll - Remaining Plugins to load: " + pluginCountToLoad);
						if (pluginCountToLoad == 0) {
							clearInterval(pluginLoaderPollInverval);
							this.uiPluginsLoaded = pluginNames;
							if (callback != undefined) {
								callback();
							}
						}
					};

					pluginLoaderPollInverval = setInterval(pluginLoaderPoll, 200);
				},
				
				waitFor: function(property, callback) {
					var thisView = this;
					if (thisView[property] == undefined || $.isFunction(thisView[property])) {
						throw "Cannot wait for a function or undefined property";
					}

//					debug("Executing waitFor: " + property);
					var waitForInterval;
					
					var waitForPoll = function() {
//						debug("WaitFor poll executing | property: " + property + " | value: " + thisView[property]);
						if (thisView[property]) {
//							debug("WaitFor condition reached");
							clearInterval(waitForInterval);
							callback();
						}
					};
					
					waitForInterval = setInterval(waitForPoll, 100);
//					debug("WaitFor has returned");
				}
			});
		}
	}
}


// Constructor -- pass a REST request URL to the constructor
function JSONRequest(url) {
	this.initialize(url);
}

/**
 * Static
 */
JSONRequest.requestCount = 0;
JSONRequest.nextRequestID = function() {
	JSONRequest.requestCount++;
	return JSONRequest.requestCount;
}

JSONRequest.prototype = {
	requestID: "",

	url: "",

	data: null,

	scriptObj: null,

	service: null,

	// Create the object
	// We store request IDs so the data can be cross referenced on the
	// return call.
	initialize: function(url) {
		this.url = url;
		this.requestID = "jsonScript_" + JSONRequest.nextRequestID();
	},

	submit: function(data) {
		if (this.scriptObj) {
			return false;
		} else {
			this.data = data;

			// Create a SCRIPT tag with the request in the URL
			this.scriptObj = $(document.createElement('SCRIPT'))
		    	.attr("type", "text/javascript")
		    	.attr("charset", "utf-8")
		    	.attr("id", this.requestID)
		    	.attr("src", this.url + 
							"?mode=jsonXML&enc=rawurl&request=" + this.serializeData() + 
							"&jsonFunc=VidegoAPI.JSONResponse&jsonData={\"requestID\":'" + this.requestID + "'}")
				.appendTo($(document.head));

		    return true;
	    }
	},

	serializeData: function() {
		return encodeURIComponent(this.data);
	},

	cleanup: function() {
		debug("JSON cleanup: " + this.requestID);
		this.scriptObj.remove();
	}
}

var VidegoAPI = new VidegoAPIController();

/**
 * Vidego Web Services Abstract Class
 */
function VidegoWebService() {
};

VidegoWebService.getExtension = function(ServiceClass) {
	var propertyExists = false;
	var classMatch = true;
	var missingMethods = "";
	for (var abstractProperty in VidegoWebService.prototype) {
		propertyExists = false;
		for (var classProperty in ServiceClass.prototype) {
			if(abstractProperty == classProperty) {
				propertyExists = true;
			}
		}
		if(!propertyExists) {
			classMatch = false;
			if(missingMethods.length != 0)
				missingMethods += ", ";
			missingMethods += abstractProperty;
		}
	}

	if (classMatch) {
		var temp = {};
		$.extend(true, temp, VidegoWebService, ServiceClass);
		$.extend(true, ServiceClass, temp);
	} else {
		throw "VidegoWebServices Error: Web service API does not implement following methods - " + missingMethods;
	}
	
	return temp;
};

VidegoWebService.SERVICE_GET_PLAYER_INFO = 'GetPlayerInfo';

VidegoWebService.prototype = {
	serviceName: "",
	onResponseFunction: null,

	request: {},
	response: {},

		
	getRequestXML: function() {
		throw("VidegoWebServices Error: Can't access abstract class methods directly");  
	},
	getXMLTag: function() {
		throw("VidegoWebServices Error: Can't access abstract class methods directly");  
	},
	handleResponseXML: function() {
		throw("VidegoWebServices Error: Can't access abstract class methods directly");  
	},
	embed: function() {
		throw("VidegoWebServices Error: Can't access abstract class methods directly");  
	},
	submit: function() {
		throw("VidegoWebServices Error: Can't access abstract class methods directly");  
	}
};

function debug(str) {
	if (VidegoAPIController.DEBUG) {
		var debugObj = $('#debug');
		if (debugObj.length == 0) {
			debugObj = $('#debug', window.parent.document);
			if (debugObj.length == 0) {
				debugObj = $(document.createElement('DIV')).attr('id','debug').appendTo('body');
			}
		}
		var escapedStr = str.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
		debugObj.append(escapedStr + "<br />");
	}
}

