﻿if (typeof(AC) == "undefined") { AC = {}; }

AC.Quicktime = {
	
	/**
	* Collection of all controllers that have a movie attached
	**/
	controllers: [],
	
	/**
	 * Adds an object param tag to the specified parent
	 * Note that the attributes are added in this seemingly odd order
	 * so they show up in the logical order in the dom
	 */
	_addParameter: function(parent, name, value) {

		if (!parent) {
			return;
		}

		var param = document.createElement('param');
		param.setAttribute('value', value);
		param.setAttribute('name', name);
		parent.appendChild(param);
		
		param = null;

	},
	
	/**
	 * Creates the IE friendly outer object
	 * NOTE Safari and Opera both seem to be able to use this one as well
	 * I'm assuming this is due to some hacking on their part for
	 * compatibility
	 */
	_createOuterObject: function(name, fileUrl, options) {

		var outerObject = document.createElement('object');
		
		if(AC.Detector.isMobile() && options.posterFrame) {
			AC.Quicktime._addParameter(outerObject, 'src', options.posterFrame);
			AC.Quicktime._addParameter(outerObject, 'href', fileUrl);
			AC.Quicktime._addParameter(outerObject, 'target', 'myself');
		} else {
			AC.Quicktime._addParameter(outerObject, 'src', fileUrl);
		}
		
		outerObject.setAttribute('id', name);


		var activexVersion = '7,3,0,0';

		if (null != options && '' != options.codebase && typeof(options.codebase) != 'undefined') {
			activexVersion = options.codeBase;
		}

		outerObject.setAttribute('codebase', 
		    'http://www.apple.com/qtactivex/qtplugin.cab#version=' + activexVersion);

		return outerObject;
	},
	
	/**
	 * Creates the more standards compliant object which Firefox and Netscape
	 * rely on to load the movie
	 */
	_createInnerObject: function(name, fileUrl, options) {

		var innerObject = document.createElement('object');
        
		innerObject.setAttribute('type', 'video/quicktime');
		innerObject.setAttribute('data', fileUrl);
		innerObject.setAttribute('id', name + "Inner");

		return innerObject;
	},
	
	/**
	* Creates a movie just to trigger the native activeX/missing plugin dialog in a browser
	*/
	_createNullMovie: function(width, height) {
		width = 0;
		height = 0;
		var nullContainer = $(document.createElement('div'));
		
		//needed in the object to trigger the missing activeX control in IE
		var classid = "clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B";
		var codebase = 'http://www.apple.com/qtactivex/qtplugin.cab#version=7,3,0,0';
		
		// triggers the missing plugin for other browsers like firefox
		var pluginspage = 'http://www.apple.com/quicktime/download/';

		nullContainer.innerHTML = '<object width="' + width + '" height="' + height + '" classid="' + classid +'" codebase="' + codebase + '"><embed width="' + width + '" height="' + height + '" type="video/quicktime" pluginspage="' + pluginspage + '"></embed></object>'
		
		return nullContainer;
	},
	
	/**
	 * Attaches supplied options as necessary to the movie objects
	 */
	_configureMovieOptions: function(innerObject, outerObject, options) {
		
		if(null == options || typeof(options) == 'undefined') {
			return false;
		}
			
		for (var property in options) {

			var attributeName = property.toLowerCase();

			switch(attributeName) {
				case('type'):
				case('src'):
				case('data'):
				case('classid'):
				case('name'):
				case('id'):
					//do nothing as these shouldn't be overriden
				break;
				case('class'):
					Element.addClassName(outerObject, options[property]);
				break;
				case('innerId'):
					if(innerObject) {
						innerObject.setAttribute('id', options[property]);
					}
				break;
				case('width'):
				case('height'):
					outerObject.setAttribute(attributeName, options[property]);
					if(innerObject) {
						innerObject.setAttribute(attributeName, options[property]);
					}
				break;
				default:
					AC.Quicktime._addParameter(outerObject, attributeName, options[property]);
					AC.Quicktime._addParameter(innerObject, attributeName, options[property]);
				break;
			}

		}
		
	},
	
	/**
	 * Will create an object element to append to the document with the
	 * specified parameters as well as any additional options
	 * 
	 * TODO plenty of work to do with the optional parameters I'm sure
	 * Though I don't know what custom parameters we may need to faciliate
	 * whatever it is we need to do with movies, though tehcnially you can
	 * pass whatever you wantt in here and it'll handle it pretty well
	 * 
	 * It's often just a matter of if we expose a custom parameter we'll
	 * accept as part of the options hash...where/how does that get applied?
	 */
	packageMovie: function(name, fileUrl, options)
	 {
		
		if(name == null || fileUrl == null ) 
		{
			throw new TypeError('Valid Name and File URL are required arguments.');
		}
		
		var minVersion = '7';
		if (options && options.minVersion)
		 {
			minVersion = options.minVersion;
		}
		
		// If required QuickTime is not available provide a link to download instead of a movie object
		if (!AC.Detector.isMobile() && !AC.Detector.isValidQTAvailable(minVersion)) 
		{
			var downloadNotice = $(document.createElement('a'));
			downloadNotice.addClassName('quicktime-download');
			
			downloadNotice.setAttribute('href', 'http://www.apple.com/quicktime/download/');
			downloadNotice.innerHTML = options.downloadText || 'Get the Latest QuickTime.';
			
			// downloadNotice.appendChild(this._createNullMovie(options.width, options.height));
			return downloadNotice;
		}
		
		var outerObject = AC.Quicktime._createOuterObject(name, fileUrl, options);
		
		if (!AC.Detector.isIEStrict())
		 {
			//really imperitive we don't create an inner object for IE
			//this is what causes the N items remaining as it never actually 
			//gets requested bbut IE still decides to report it as 
			//needing to be loaded
			
			var innerObject = AC.Quicktime._createInnerObject(name, fileUrl, options);
			outerObject.appendChild(innerObject);
			
		} else if(options.aggressiveCleanup !== false)
		{
			
			//knowing it's IE at this point, make sure we clear the movie when the page closes
			//we also set our reference to null for good measure
			Event.observe(window, 'unload', function()
			 {
				try 
				{
					outerObject.Stop();
				} catch(e) {;}
				outerObject.style.display = 'none';
				outerObject = null;
				
				//this only masks memory leaks
				//movie could still be present even if hidden
				//if the movie remains in the viewport upon visiting other
				//pages, you have remaining references to the movie somewhere
				//they need to be removed as early as possible preferably
				//or at least before you leave if you have no other choice
				
				//closing the window that is leaking will throw an error message
				//but at least due to the hiding it won't completely interrupt
				//browsing
			}
			
		  );
			
		}

		AC.Quicktime._configureMovieOptions(innerObject, outerObject, options);
		
		//force preservation of existing params even if the movie's URL is changed
		//this is the ooopiste of how QT works by default
		
		AC.Quicktime._addParameter(outerObject, 'saveembedtags', true);
		AC.Quicktime._addParameter(innerObject, 'saveembedtags', true);
		
		//Needs to be last so IE sees all the parameters appended to
		//the object prior to loading the activex control
		outerObject.setAttribute('classid', 
			'clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B');
		
		return outerObject;
	},

	/**
	 * Using this will clear the contents of oldMovie's parentNode and 
	 * insert newMovie into the container
	 */
	swapMovie: function(container, oldMovie, newMovie) {
		
		
		var isIE = AC.Detector.isIEStrict();

		//in IE ensure we hide the old movie, otherwise it kinda ghosts itself
		if(isIE && oldMovie) {
			oldMovie.style.display = 'none';
		}
		
		//Yes, we could preserve the nodes in this container in some browsers
		//but since IE is overwriting the innerHTML we're going to completely
		//empty the container everywhere for the sake of consistency
		Element.removeAllChildNodes(container);
		
		var movieReference = null; 

		if (!isIE) {
			container.appendChild(newMovie);
			movieReference = newMovie;
		} else {
			container.innerHTML = newMovie.toMarkup();
			movieReference = container.firstChild;
			movieReference.style.display = 'block';
		}
		
		//reference to the movie that's actually in the DOM
		return movieReference;
	},
	
	/**
	* Helper to handle a very simple insertion of a movie into a specified 
	* element
	*/
	render: function(movie, element, options) {

		var target = $(element);
		var placeholderContent = target.innerHTML;
		
		if (!AC.Detector.isQTInstalled()) {
			Element.addClassName(target, 'static');
			return
		}
		
		target.innerHTML = '';
		Element.addClassName(target, 'loading');
		target.appendChild(movie);
		
		var options = options ? options : {};
			
		var movieLoaded = function() {
			checkController.monitorMovie();
			Element.removeClassName(element, "loading");
			Element.addClassName(element, "loaded");
		}
		
		var movieFinished = function() {return;}
		
		if("finishedState" in options) {
			
			var showFinishedState = function(target, content) {
				return (function() {
					
					checkController.detachFromMovie();
					
					//ensure movie is hidden in IE
					movie.style.display = 'none';
					movie = null;
					
					target.innerHTML = '';
					
					if (typeof(content) == 'string') {
						target.innerHTML = content;
					} else {
						target.appendChild(content);
					}
				})
			}
			
			movieFinished = showFinishedState(target, options.finishedState)
		}
		
		var checkController = new AC.QuicktimeController(movie, {
			onMoviePlayable: movieLoaded, 
			onMovieFinished: movieFinished})
	}

};

