/*
 * DaiShu CMS 5 Video Vault.
 *
 * Copyright (c) 2010 Scorpion Design, Inc.
 */
(function( $ ) {

$.widget( "cms.videopopup", $.ui.dialog, {
	options: {
		modal: true,
		width: 753,
		height: 570,
		streaming: true,
		theme: window._videoskin || 'Blue',
		categories: null,
		video: null,
		open: function(e, data, widget) {
			widget._open.apply(widget, [e, data]);
		}
	},

	// Open the video vault.
	activate: function(options) {
		$('<div class="ui-dialog-main vv-main"></div>').videopopup(options);
	},

	// Create the wizard.
	_create: function() {
		// Run the base create.
		$.ui.dialog.prototype._create.apply( this, arguments );

		// Set up the title correctly.
		this.elements = {
			main: this.uiDialog.find('div.ui-dialog-main'),
			titlebar: this.uiDialog.find('div.ui-dialog-titlebar').addClass('video-vault')
		};
		this._mainclass = this.elements.main.attr('class');
		this._titleclass = this.elements.titlebar.attr('class');

		// Activate the video fault.
		this.element.videovault({
			categories: this.options.categories,
			video: this.options.video
		});

		// Do not let a mousewheel scroll propagate beyond the wizard itself.
		this.element.captureScroll();
	},

	// Set the main height when the dialog box opens.
	_open: function() {
		this.elements.main
			.css({height:560})
			.attr('class', this._mainclass+" "+(this.options.theme||""));
		this.elements.titlebar.attr('class', this._titleclass+" "+(this.options.theme||""));

		// Place the widget in the middle of the screen.
		this.widget().place({
			my: 'center',
			at: 'center',
			of: window
		});
	},

	// Close the wizard.
	close: function() {
		// Call the default close event.
		$.ui.dialog.prototype.close.apply( this, arguments );

		// Then completely destroy the video vault instance.
		this.element.removeswf().remove();
	}
});

// Create the video vault control and its properties.
$.widget( "cms.videovault", {
	options: {
		streaming: true,
		categories: null,
		video: null,
		autoplay: false,
		cascade: false
	},

	_html: '\
	<div class="vv-video"></div>\
	<div class="vv-details">\
		<h3></h3>\
		<div></div>\
	</div>\
	<div class="vv-buttons">\
		<a class="vv-prev" href="javascript:void(0)" title="Previous Video">&nbsp;</a>\
		<a class="vv-next" href="javascript:void(0)" title="Next Video">&nbsp;</a>\
		<a class="vv-bookmark" href="javascript:void(0)" title="Bookmark Video">&nbsp;</a>\
		<a class="vv-email" href="javascript:void(0)" title="Email to a Friend">&nbsp;</a>\
		<a class="vv-twitter" href="javascript:void(0)" title="Send to Twitter">&nbsp;</a>\
		<a class="vv-facebook" href="javascript:void(0)" title="Send to Facebook">&nbsp;</a>\
	</div>\
	<div class="vv-categories">\
		<a class="vv-prev" href="javascript:void(0)">&nbsp;</a>\
		<div class="vv-panel">\
			<div class="vv-scroller"></div>\
		</div>\
		<a class="vv-next" href="javascript:void(0)">&nbsp;</a>\
	</div>\
	<div class="vv-videos">\
		<a class="vv-prev" href="javascript:void(0)" title="Previous Video">&nbsp;</a>\
		<div class="vv-coverflow">\
			<div class="vv-scroller"></div>\
			<div class="vv-title"></div>\
		</div> \
		<a class="vv-next" href="javascript:void(0)" title="Next Video">&nbsp;</a>\
	</div>',

	// Create the wizard.
	_create: function() {
		var main = this.element.html( this._html );

		// Activate the quality monitor as needed.
		if ( !this.options.plugins && $.toBool( $.getQueryString('bandwidth') ) ) {
			this.options.plugins = 'qualitymonitor';
		}

		// IE7 is a piece of shit and sometimes caches the swf wrong.
		var cover = "/Shared/videovault/lt/Coverflow.swf";
		if ( $.browser.msie && $.browser.version <= 7 ) {
			cover += ( "?rnd="+Math.random() );
		}

		var children = main.children();
		this.elements = {
			main: main,
			video: children.eq(0).embedswf({
						width: 512,
						height: 288,
						swf: "/Shared/videovault/lt/player.swf",
						params: {
							flashvars: {
								file: "/Shared/videovault/empty.flv",
								plugins: this.options.plugins,
								skin: "/Shared/videovault/lt/skins/glow.zip",
								"controlbar.position": "over"
							}
						}
					}).bind('swfready', $.cms.videovault.bindState),
			details: {
				title: children.eq(1).children('h3'),
				caption: children.eq(1).children('div')
			},
			buttons: children.eq(2).click( $.proxy(this._handleButton, this) ),
			categories: children.eq(3).click( $.proxy(this._handleCategory, this) ),
			panel: children.eq(3).find('div.vv-panel'),
			scroller: children.eq(3).find('div.vv-scroller'),
			videos: children.eq(4).children('a').click( $.proxy(this._handleButton, this) ),
			thumbnails: {
				scroller: children.eq(4)
							.children('div.vv-coverflow')
								.children('div.vv-scroller')
									.bind('mouseover mouseout click', $.proxy(this._handleThumbnails, this) ),
				title: children.eq(4).find('div.vv-title')
			}
		};

		this._pid = this.elements.video.attr('_id');
		$.cms.videovault.players[this._pid] = {
			cascade: this.options.cascade
		};

		// Load the videos.
		$.ajax({
			url: $.getAjaxUrl('/CobaltAjax.ashx?M=GetVideoVault&V2=true', { Streaming: this.options.streaming, Cat: this.options.categories } ),
			dataType: 'json',
			success: $.proxy(this._loadCategories, this)
		});

		$(document).bind('keydown', $.proxy(this._handleKey, this));
	},

	// Load the categories.
	_loadCategories: function(categories) {
		if ( !categories || !categories.length ) {
			return;
		}

		this._cposition = 0;
		var cindex = 0;

		// Build the categories.
		for ( var i=0; i<categories.length; i++ ) {
			var cat = categories[i];
			var div = $('<div class="vv-category"><span>'+cat.CategoryName+'</span></div>')
				.appendTo( this.elements.scroller )
				.data('category', cat);
			if ( !$.browser.msie6 && i<=6 ) {
				div.css({marginLeft:800});
			}

			// If we have an auto-start video, look for the matching category.
			if ( this.options.video > 0 ) {
				for ( var j=0;j<cat.Videos.length;j++ ) {
					if ( cat.Videos[j].VideoID === this.options.video ) {
						cindex = i;
						break;
					}
				}
			}
		}

		// Do we have more categories than will fit?
		var children = this.elements.scroller.children();
		var panel = this.elements.panel.width();
		var scroll = this.elements.scroller.offset();
		var pos = children.eq( children.length-1 ).dimensions();
		this._overflow = pos.left+pos.width-scroll.left > panel;

		if ( $.browser.msie6 ) {
			// For IE6, click the first category right away.
			children.eq( cindex ).click();
		} else {
			// Animate the first 7 categories dropping in.
			var time = 0;
			for ( var i=0; i<children.length && i<=6; i++ ) {
				var child = children.eq(i);
				time = (i*75)+50;
				var fn = function(_child){
					return function(){
						_child.animate({marginLeft:0},75);
						_child = null;
					};
				}(child);
				setTimeout(fn, time);
			}

			// Activate the first category once the animation is finished.
			var fn = function(first){
				return function(){
					first.click();
					first = null;
				};
			}(children.eq( cindex ));
			setTimeout(fn, time + 100);
		}
	},

	// Handle a click on the category section.
	_handleCategory: function(e) {
		var target = $(e.target);
		if ( target.is('.vv-next') ) {
			this._advanceCategory(1);
		} else if ( target.is('.vv-prev') ) {
			this._advanceCategory(-1);
		} else {
			var cat = target.closest('div.vv-category');
			if ( cat.length && !cat.is('.active') ) {
				// Activate the category.
				this._selectCategory( cat );
			}
		}
	},

	// Select a specific category.
	_selectCategory: function(cat, categories, start, play) {
		if ( !cat ) {
			return;
		}
		if ( !categories ) {
			categories = this.elements.scroller.children();
		}

		// Assign the active class.
		categories.filter('.active').removeClass('active');
		cat.addClass('active');

		// Record the current category.
		this._cat = categories.index( cat );

		// Load the videos.
		this._loadVideos( cat.data('category'), start, play );

		// Make sure the category is visible.
		this._ensureCategory();
	},

	// Advance the categories.
	_advanceCategory: function(amount, start, play) {
		var categories = this.elements.scroller.children();

		// Advance to the next/prev category, wrapping as needed.
		var index = (this._cat||0) + amount;
		if ( index < 0 ) {
			index = categories.length-1;
		} else if ( index > categories.length-1 ) {
			index = 0;
		}

		// Activate the next category.
		this._selectCategory(categories.eq(index), categories, start, play);
	},

	// Ensure that the active category is fully visible.
	_ensureCategory: function() {
		// No overflow, don't bother.
		if ( !this._overflow ) {
			return;
		}

		// Get the existing categories and the currently selected one.
		var categories = this.elements.scroller.children();
		var cat = categories.filter('.active');
		if ( !categories.length || !cat.length ) {
			return;
		}

		// Get their positions.
		var first = categories.eq(this._cposition).offset().left;
		var index = categories.index(cat);
		var panel = this.elements.panel.width();
		var pos = cat.dimensions();

		// If we're too far to the right.
		var shift = 0;
		while ( pos.left+pos.width-first > panel ) {
			shift++;
			first = categories.eq(this._cposition+shift).offset().left;
		}

		// If we're too far to the left.
		while ( pos.left < first ) {
			shift--;
			first = categories.eq(this._cposition+shift).offset().left;
		}

		// Adjust as needed.
		if ( shift != 0 ) {
			this.shiftCategory(shift);
		}
	},

	// Advance the category panel.
	shiftCategory: function(amount) {
		// Get the existing categories.
		var categories = this.elements.scroller.children();
		if ( !categories.length ) {
			return;
		}

		// And the next position.
		this._cposition += amount;
		if ( this._cposition >= categories.length ) {
			this._cposition = 0;
		} else if ( this._cposition < 0 ) {
			this._cposition = categories.length-1;
		}
		var cat = categories.eq(this._cposition);

		// Calcuate the offset.
		var parent = this.elements.scroller.offset();
		var pos = cat.offset();
		var left = parent.left - pos.left;

		this.elements.scroller.stop().animate( {marginLeft:left}, 400, $.proxy(this._ensureCategory, this) );
	},

	// Load a set of videos in a category.
	_loadVideos: function( cat, start, play ) {
		// Load the videos.
		var sb = [];
		this._tindex = -1;
		var id = this._video && this._video.VideoID;
		for ( var i=0; i<cat.Videos.length; i++ ) {
			var v = cat.Videos[i];
			sb.push('<div class="vv-thumb' );
			if ( v.Thumbnail ) {
				sb.push('" style="background-image:url(\'/images/thumbnail.aspx?I=');
				sb.push( this._encodeThumbnail(v.Thumbnail) );
				sb.push('&W=134&H=133&C=Center&F=Expand&R=.3,.5&D=/Shared/videovault/theme/default.gif');
				sb.push('\')');
			}
			sb.push('"><div _index="');
			sb.push(i);
			if ( v.VideoID === id ) {
				sb.push('" class="active');
				this._tindex = i;
			}
			sb.push('"></div></div>');
		}
		this.elements.thumbnails.scroller.stop().css({marginLeft:0}).html( sb.join("") );
		this._tposition = 0;
		this._videos = cat.Videos;

		// If we have a starting video, get it's position.
		var video;
		var autostart = play || this.options.autoplay;
		if ( !start && !this._video ) {
			start = 0;
		}
		if ( this.options.video || start !== undefined ) {
			for ( var i=0;i<cat.Videos.length;i++ ) {
				if ( cat.Videos[i].VideoID === this.options.video ) {
					start = i;
					autostart = true;
					break;
				}
			}
			this.options.video = null;
		}

		// Then load the start video (unless a video is currently playing.
		if ( !this.isPlaying() && start !== undefined ) {
			this.loadPosition( start < 0 ? cat.Videos.length-1 : start, true, autostart );
		}
	},

	// Encode the thumbnail image.
	_encodeThumbnail: function(thumb) {
		var m = /\/thumbnail.aspx\?.*?\bI=([^&]+)/g.exec(thumb);
		if ( m ) {
			return m[1];
		} else {
			return $.encode(thumb);
		}
	},

	// Handle a button click.
	_handleButton: function(e) {
		var target = $(e.target);
		var buttons = target.parent('.vv-buttons').length>0;
		if ( target.is('a.vv-next') ) {
			if ( buttons ) {
				this.advanceVideo( 'NEXT', true );
			} else {
				this._shiftThumbnail(4);
			}
		} else if (target.is('a.vv-prev') ) {
			if ( buttons ) {
				this.advanceVideo( 'PREV', true );
			} else {
				this._shiftThumbnail(-4);
			}
		}
	},

	// If we've moving outside the boundaries of the current set of videos, advance to the next or previous category.
	_adjustCategory: function(index, force, play) {
		if ( index >= this._videos.length ) {
			// If we're moving past the last video in the category, move to the next category.
			this._advanceCategory(1, force ? 0 : undefined, play);
			return true;
		} else if ( index < 0 ) {
			// If we're moving before the first video in the category, move to the previous one.
			this._advanceCategory(-1, force ? -1 : undefined, play);
			return true;
		} else {
			return false;
		}
	},

	// Advance to the next video.
	advanceVideo: function( dir, force, play ) {
		// Adjust the thumbnail index.
		var index = this._tindex + (dir==='NEXT'?1:-1);

		// Adjust the category as needed.
		if ( this._adjustCategory(index, force, play) ) {
			return;
		}

		// Load the video at the next position.
		this.loadPosition( index, force, play );
	},

	// Handle a keypress.
	_handleKey: function(e) {
		switch (e.which) {
			case $.ui.keyCode.RIGHT:
				this.advanceVideo('NEXT');
				return false;
			case $.ui.keyCode.LEFT:
				this.advanceVideo('PREV');
				return false;
			case $.ui.keyCode.ENTER:
			case $.ui.keyCode.SPACE:
				this.loadPosition( this._tindex, true );
				return false;
		}
	},

	// Find out if a video is currently playing.
	isPlaying: function() {
		var player = $.cms.videovault.players[this._pid];
		if ( player ) {
			switch (player.newstate) {
				case "PLAYING":
				case "BUFFERING":
					return true;
			}
		}
		return false;
	},

	// Load a video at the specified position.
	loadPosition: function( index, force, play ) {
		// If the thumbnail position has changed.
		var newthumb = false;
		if ( index !== this._tindex ) {
			// Update the thumbnail.
			this._updateThumbnail( index );
			newthumb = true;
		}

		// If we're manipulating the current video.
		var video = this._videos && this._videos[index];
		if ( this._video && video && this._video.VideoID === video.VideoID ) {
			if ( newthumb ) {
				// if we've just re-selected the thumbnail of the currently selected video, do nothing.
				return;
			}

			// Play or pause the current video.
			var swf = this.elements.video.data('swf');
			if ( swf && swf.sendEvent ) {
				try {
					swf.sendEvent('PLAY');
				} catch(ex){;}
			}
		} else if ( this.isPlaying() && !force ) {
			// If a video is already playing and we're not forcing a load, do nothing.
			return;
		} else {
			// Load the video.
			this._loadVideo( video, play || this.options.autoplay );
		}
	},

	// Play a specific video.
	_loadVideo: function( video, play ) {
		if ( !video || !video.Levels ) {
			return;
		}
		this._updateVideo( video );

		// Stop any currently playing video and load the next one.
		var swf = this.elements.video.data('swf');
		if ( swf && swf.sendEvent ) {
			try {
				swf.sendEvent('STOP');
				swf.sendEvent('LOAD', {
					streamer: this.options.streaming ? video.RTMPServer : null,
					image: video.Thumbnail,
					file: video.Levels[0].file,
					levels: video.Levels
				});

				this._updateThumbnail( video );

				if ( play ) {
					swf.sendEvent('PLAY',true);
				}
				return;
			} catch(ex){;}
		}

		// If we were unable to load the video, the player may not yet be ready, try again in a moment.
		if ( this._playercount === undefined ) {
			this._playercount = 0;
		}
		this._playercount++;
		if ( this._playercount < 10 ) {
			var fn = function(wizard, _video, _play){
				return function(){
					wizard._loadVideo(_video, _play);
					wizard = null;
					_video = null;
					_cat = null;
				};
			}(this,video,play);
			setTimeout(fn, 250);
		}
	},

	// Update the video preview pane.
	_updateVideo: function( video ) {
		// Record the new video and its index.
		this._video = video;
		for ( var i=0; i<this._videos.length; i++ ) {
			if ( video.VideoID === this._videos[i].VideoID ) {
				this._vindex = i;
				break;
			}
		}

		// Set the preview pane.
		this.elements.details.title.html(video.Title||"");
		this.elements.details.caption.html(video.Caption||"");
		var bookmark = this.elements.buttons.children('a.vv-bookmark');
		var email = this.elements.buttons.children('a.vv-email');
		var facebook = this.elements.buttons.children('a.vv-facebook');
		var twitter = this.elements.buttons.children('a.vv-twitter');
		if ( video.Path ) {
			var title = video.Title.replace(/'/g,'');
			var path = video.Path;
			bookmark.click(function(e){$.bookmark(this,title,path);});
			email.attr('href','mailto:&subject=Check%20out%20this%20video&body='+$.encode(video.Path));
			twitter.attr('href','http://twitter.com/share?original_referer='+$.encode(window.location.href)+'&url='+$.encode(video.Path));
			twitter.attr('target','_blank');
			facebook.attr('href','http://www.facebook.com/sharer.php?u='+$.encode(video.Path));
			facebook.attr('target','_blank');
		} else {
			bookmark.unbind('click');
			bookmark.attr('href','javascript:void(0);');
			email.attr('href','javascript:void(0);');
			twitter.attr('href','javascript:void(0);');
			twitter.removeAttr('target');
			facebook.attr('href','javascript:void(0);');
			facebook.removeAttr('target');
		}
	},

	// Handle video events.
	_handleThumbnails : function(e) {
		if ( e && e.target && e.target.parentNode && e.target.parentNode.className === 'vv-thumb' ) {
			var el = $(e.target);
			var index = $.toInt( el.attr('_index') );
			var video = this._videos[index];
			if ( e.type === 'mouseover' ) {
				el.addClass('over');
				this.elements.thumbnails.title.html(video.Title||"");
			} else if ( e.type === 'mouseout' ) {
				el.removeClass('over');
				this.elements.thumbnails.title.html("");
			} else if ( e.type === 'click' ) {
				this.loadPosition( index, true, true );
			}
		}
	},

	// Update the thumbnail status.
	_updateThumbnail: function( index ) {
		var video;
		if ( typeof index === 'number' ) {
			// If we have a number find the video by position.
			video = this._videos[index];
		} else if ( index ) {
			// Find the matching thumbnail for the current video and ensure it is active.
			video = index;
			index = -1;
			for ( var i=0; i<this._videos.length; i++ ) {
				if ( this._videos[i].VideoID === video.VideoID ) {
					index = i;
					break;
				}
			}
		}

		// If the thumbnail is already selected.
		if ( this._tindex === index ) {
			return;
		} else {
			this._tindex = index;
		}

		// Set the thumbnail state based on the video.
		if ( video ) {
			if ( index >= 0 ) {
				var cover = this.elements.thumbnails.scroller.find('div.vv-thumb>div');
				var el = cover.eq(index);
				if ( !el.is('.active') ) {
					cover.filter('.active').removeClass('active');
					el.addClass('active');
				}
			}
		}

		this._ensureThumbnail();
	},

	// Ensure that the active thumbnail is fully visible.
	_ensureThumbnail : function() {
		// Get the existing categories and the currently selected one.
		var videos = this.elements.thumbnails.scroller.children();
		var vid = videos.filter(':has(.active)');
		if ( !videos.length || !vid.length ) {
			return;
		}

		// Get their positions.
		var first = videos.eq(this._tposition).offset().left;
		var index = videos.index(vid);
		var panel = this.elements.thumbnails.scroller.parent().width();
		var pos = vid.dimensions();

		// If we're too far to the right.
		var shift = 0;
		while ( pos.left+pos.width-first > panel ) {
			shift++;
			first = videos.eq(this._tposition+shift).offset().left;
		}

		// If we're too far to the left.
		while ( pos.left < first ) {
			shift--;
			first = videos.eq(this._tposition+shift).offset().left;
		}

		// Adjust as needed.
		if ( shift != 0 ) {
			this._shiftThumbnail(shift*4);
		}
	},

	// Advance the thumbnail panel.
	_shiftThumbnail: function(amount) {
		// Get the existing categories.
		var videos = this.elements.thumbnails.scroller.children();
		if ( !videos.length ) {
			return;
		}

		// Adjust the position.
		this._tposition += amount;

		// If we needed to move to a different category, stop here.
		if ( this._adjustCategory( this._tposition, false ) ) {
			return;
		}

		var vid = videos.eq(this._tposition);

		// Calcuate the offset.
		var parent = this.elements.thumbnails.scroller.offset();
		var pos = vid.offset();
		var left = parent.left - pos.left + $.toInt(vid.css('marginLeft'));

		//this.elements.thumbnails.scroller.stop().animate( {marginLeft:left}, 400, $.proxy(this._ensureThumbnail, this) );
		this.elements.thumbnails.scroller.stop().animate( {marginLeft:left}, 400 );
	}

});

// Static properties and methods.
$.extend( $.cms.videovault, {
	// Static definition of player states.
	players: {},

	// Bind an event listener to record the player state.
	bindState: function(e) {
		var swf = $(e.target).data('swf');
		if ( swf && swf.addModelListener ) {
			swf.addModelListener("state", "$.cms.videovault.updateState");
		}
	},

	// When the player state is updated.
	updateState: function(p) {
		var player = $.cms.videovault.players[p.id] || {};
		$.extend( player, p );

		if ( player.cascade && p.oldstate === 'PLAYING' && ( p.newstate === 'COMPLETED' || p.newstate === 'IDLE' ) ) {
			$(window.document[p.id]).closest('div.vv-main').videovault('advanceVideo', 'NEXT', true, true);
		}
	},

	// Dispose of resources.
	destroy: function() {
		var swf = this.elements.video.data('swf');
		if ( swf ) {
			try {
				swf.sendEvent('STOP');
			} catch(ex){;}
		}

		$(document).unbind('keydown', this._handleKey);
	}

});


})( jQuery );

