/*jslint laxbreak: true, eqeqeq: true, browser: true, undef: true */
/*extern DR, createUPlayer21, disposeUPlayer */
/*extern $, $A, $type, $defined, Class, Event, Events, Options, Element, Elements, Request, Fx, JSON, Json, XHR, Ajax */
/*global UPlayerClipList, $getParentWithClass */

/* Version 1.1
 * 	- updated the script to work with MooTools 1.2
 */

function drung_log(x)
{
	if (window.console)
	{
		console.log(x);
	}
}

// limited MooTools 1.11 fix for changed get behavior in MooTools 1.2
if (!$defined(Element.prototype.get)) {
	Element.extend({get : function (p) {
		switch (p) {
			case 'tag': return this.getTag();
			case 'html': return this.innerHTML;
		}
	}});
}

// impement Request wrapper for MooTools 1.11
if (!$defined(window.Request)) {
	Request = XHR.extend({
		send: function (data) {
			this.parent(this.options.url, data);
		}
	});
}

// impement Request.HTML wrapper for MooTools 1.11
if (!$defined(window.Request.HTML)) {
	Request.HTML = Ajax.extend({
		initialize: function (options) {
			this.parent(options.url, options);
			this._use_real_send = false;
		}
		,send: function () {
			if (this._use_real_send) {
				this.parent(arguments[0], arguments[1]);
			} else {
				this._use_real_send = true;
				this.request(arguments[0]);
				this._use_real_send = false;
			}
		}
	});
}

// implement $getParentWithClass for MooTools 1.11 or 1.2
if ($defined(Class.prototype.extend)) {
	$getParentWithClass = function (el, classname) {
		el = $(el);
		while (!el.hasClass(classname) && el !== document) {
			el = el.getParent();
		}
		return el;
	};
} else {
	$getParentWithClass = function (el, classname) { return el.getParent('.' + classname); };
}

// implement MooTools 1.2 complient JSON object for MooTools 1.11
if (!($defined(window.JSON) && $defined(window.JSON.encode))) {
	if (!$defined(window.JSON)) {
		window.JSON = {};
	}
	JSON.encode = Json.toString;
	JSON.decode = Json.evaluate;
}

// add support for set('html') to MooTools 1.11
if ($defined(Class.prototype.extend)) {
	var _set = Element.prototype.set;
	Element.extend({set: function (key, val) {
		return key === 'html' ? this.setHTML(val) : _set.apply(this, $A(arguments));
	}});
}

/*
Class: UPlayerClipList
	Managers the cliplist of an UPlayer instance

Options:
	uplayer_options - object, passed on to CreateUPlayer21
	page_url - string, url to page template (must end with '?' or '&'
	playlist_url - string, url to js-playlist template (must end with '?' or '&'
	realm - string, used to generate page_url & playlist_url if they are not provided
*/
UPlayerClipList = new Class({
	
	Implements: [Options, Events],
	
	options: {
		uplayer_options: {}
		,page_url: ''
		,playlist_url: ''
		,realm: 16
		,show_metadata: false
		,show_relations: false
	}
	,initialize: function (id, options) {
		this.setOptions(options);
		if (!this.options.page_url) {
			this.options.page_url = '/php/ung/python/uplaylists/realms/'+ this.options.realm + '/page/';
		}
		if (!this.options.playlist_url) {
			this.options.playlist_url = '/php/ung/python/uplaylists/realms/'+ this.options.realm + '/js-playlist/';
		}

		// find player parts
		this.player_id = id;
		this.root = $getParentWithClass($(id), 'uplayerWrapper');
		this.clipList = this.root.getElement('.uplayerList');
		this.categoryList = this.root.getElement('.uplayerCategories');

		// create global hilight function
		this.hilightFuncName = 'UPlayerClipListHighlightfunc' + UPlayerClipList.counter++;
		window[this.hilightFuncName] = this.hightlightCallback.bind(this);
		this.setupHighlightCallbacks();
		
		this.createUPlayer();
		
		// prepare for AJAX pagination
		var qstr_options = String(document.location).toQueryObject();
		this.current_page = qstr_options.p ? parseInt(qstr_options.p, 10) : 1;
		this.current_clip_page = this.current_page;
		this.current_category = qstr_options.c ? parseInt(qstr_options.c, 10) : 0;
		this.current_clip_category = this.current_category;

		this.scrollfx = new Fx.Scroll(window, { offset: { x: 0, y: -100 }});

		// bind event handlers
		this.bound = {
			pageTurnHandler: this.pageTurnHandler.bindWithEvent(this)
			,playClipHandler: this.playClipHandler.bindWithEvent(this)
		};

		this.attach();
		this.registerUnloadFunction();
	}
	/*
	Function: createUPlayer
		Creates an uplayer and stores it in "this.uplayer"
	*/
	,createUPlayer: function () {
		this.player = createUPlayer21(this.player_id, this.options.uplayer_options);
	}
	/*
	Function: attach
		attaches events to the cliplist.
	*/
	,attach: function () {
		var list = this.root.getElements('div.uplayerPagination a');
		list.extend(this.root.getElements('div.uplayerCategories a'));
		list = new Elements(list)
			.removeEvent('click', this.bound.pageTurnHandler)
			.addEvent('click', this.bound.pageTurnHandler);

		var hest = this.root.getElements('a.uplayerClip');
		this.root.getElements('a.uplayerClip')
			.removeEvent('click', this.bound.playClipHandler)
			.addEvent('click', this.bound.playClipHandler)
			.addEvent('mouseenter', function () {
				this.addClass('uplayerClipHover');
			})
			.addEvent('mouseleave', function () {
				this.removeClass('uplayerClipHover');
			});
	}
	/*
	Function: pageTurn
		provides asynchronous turning of a page, instead of a page reload
	Arguments:
		a - the link element triggering the page turn
	*/
	,pageTurn: function (a) {
		
		// get page from querystring		
		var qs_data = a.getProperty('href').toQueryObject();
		this.current_page = qs_data.p ? parseInt(qs_data.p, 10) : 1;
		this.current_category = qs_data.c ? parseInt(qs_data.c, 10) : 0;
		
		// update classes in category link list
		if (this.categoryList) {
			this.categoryList.getElements('a').each(function (el) {
				el.removeClass('uplayerCurrentCategory');
				if (el.getProperty('href').match(new RegExp('c=' + this.current_category + '(?:&|$)'))) {
					el.addClass('uplayerCurrentCategory');
				}
			}, this);
		}

		// request new page
		var data = a.getProperty('href').split('?')[1];
		var req = new Request({
			method: 'get'
			,url: this.options.page_url
			,onSuccess: function (html) {

				var new_el = new Element('div').set('html', html);

				// update html and attach events
				this.clipList.set('html', new_el.getFirst().get('html'));
				this.attach();
		
				// hilight currently playing clip, if it is visible
				if (this.isCurrentClipPage()) {
					this.clipList.getElements('a.uplayerClip')[this.current_clip_index]
						.addClass('uplayerClipHighlighted');
				}
			}.bind(this)
		}).send(data);
	}
	/*
	Function: pageTurnHandler
		event handler for page turn links (pagination or category links)
	*/
	,pageTurnHandler: function (e) {
		e = new Event(e).stop();
		var el = $(e.target);
		while (el.get('tag') !== 'a') {
			el = $(el.getParent());
		}
		this.pageTurn(el);
	}
	/*
	Function: playClip
		plays a clip on the currently visible page. Handles asynchronous fetching of playlist, recreation of uplayer flash object and scrolls window so player is visible.

	Arguments:
		idx - index of the clip to play (zero based)
	*/
	,playClip: function (idx) {

		this.scrollToPlayer();

		if (this.isCurrentClipPage()) {
			this.player.skipTo(idx);
		} else {
			var req = new Request({
				url: this.options.playlist_url
				,method: 'get'
				,onSuccess: function (text) {
					
					// update playlist
					this.options.uplayer_options.playlist = JSON.decode(text);
					this.options.uplayer_options.playlistOffset = idx;
					this.options.uplayer_options.autoplay = true;
					this.setupHighlightCallbacks();
					
					// rebuild uplayer
					disposeUPlayer(this.player);
					this.player = null;
					this.createUPlayer();

					// update page markers for current clip
					this.current_clip_page = this.current_page;
					this.current_clip_category = this.current_category;
				}.bind(this)
			}).send('c=' + this.current_category + '&p=' + this.current_page);
		}
	}
	/*
	Function: playClipHandler
		event handler for play clip links
	*/
	,playClipHandler: function (e) {
		e = new Event(e).stop();
		var el = $getParentWithClass($(e.target), 'uplayerClip');
		this.playClip(this.clipList.getElements('a.uplayerClip').indexOf(el));
	}
	/*
	Function: setupHighlightCallbacks
		loops through the current uplayer playlist (options.uplayer_options.playlist) and enhances each clip with a callback to <UPlayerClipList.hightlightCallback> when the clip starts
	*/
	,setupHighlightCallbacks: function() {
		this.options.uplayer_options.playlist.forEach( function (o, idx) {
			o.startJavascript = this.hilightFuncName + ',' + idx;
		}, this);
	}
	/*
	Function: hightlightCallback
		called from uplayer when a clip starts playing. Highlights the clip (if visible), and updates current clip properties.
	*/
	,hightlightCallback: function (idx) {
		this.current_clip_index = idx;
		if (this.isCurrentClipPage()) {
			if (this.clipList) {
				var list = this.clipList.getElements('a.uplayerClip');
				list.removeClass('uplayerClipHighlighted');
				list[idx].addClass('uplayerClipHighlighted');
			}
		}
		if (this.options.show_metadata)
		{
			var req = new Request.HTML({
				url: '/php/ung/python/uplaylists/clips/' + this.getClipIDFromIndex(idx) + '/metadata/'
				,method:"get"
				,update:$('uplayerMetadata')
			});
			req.send();
		}
		if (this.options.show_relations)
		{
			var req = new Request.HTML({
				url: '/php/ung/python/uplaylists/clips/' + this.getClipIDFromIndex(idx) + '/related/'
				,method:"get"
				,update:$('uplayerRelations')
			});
			
			req.addEvent('onSuccess', function () {
				this.fireEvent('uplayerRelatedLoaded');
			}.bind(this));
			
			req.send();
		}
	}
	/*
	Function: isCurrentClipPage
		returns true if the currently playing clip is on the currently visible page
	*/
	,isCurrentClipPage: function () {
		return (this.current_category === this.current_clip_category) && (this.current_page === this.current_clip_page);
	}
	/*
	Function: scrollToPlayer
		scrolls the window so the player is visible
	*/
	,scrollToPlayer: function () {
		//var pos = Element.prototype.getPosition.apply($(this.player));
		this.scrollfx.toElement(this.player_id);
	}
	/*
	Function: registerUnloadFunction
		registers a function on the beforeunload event which removes the registered hightlightCallbacks and unloads the object. Prevents leaks in internet explorer.
	*/
	,registerUnloadFunction: function () {
		var self = this;
		window.addEvent('beforeunload', function () {
			window[self.hilightFuncName] = function () {};
			self.player = null;
		});
	}
	/*
	Function: getClipIDFromIndex
		Returns a clip ID based in the clip in the list with index idx.
	*/
	, getClipIDFromIndex: function (idx) {
		var h = this.clipList.getElements('a.uplayerClip')[idx].getProperty('href').split('#');
		return h[1].replace('clip_', '');
	}
});

UPlayerClipList.counter = 0;  // static property needed to register hilight callbacks
UPlayerClipList.implement(new Options());

