/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Gdata
 * @subpackage Demos
 * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */

/**
 * @fileoverview Provides functions for browsing and searching YouTube 
 * data API feeds using a PHP backend powered by the Zend_Gdata component
 * of the Zend Framework.
 */

/**
 * provides namespacing for the user clips
 */
var userClips = {};

/**
 * maximum number of results to return for list of videos / comments
 * @type Number
 */
userClips.MAX_RESULTS_LIST = 5;
userClips.MAX_COMMENTS_LIST = 8;

/**
 * navigation button id used to page to the previous page of
 * results in the list of videos / the comments list
 * @type String
 */
userClips.VIDEOS_PREVIOUS_PAGE_BUTTON = 'videosPreviousPageButton';
userClips.COMMENTS_PREVIOUS_PAGE_BUTTON = 'commentsPreviousPageButton';

/**
 * navigation button id used to page to the next page of
 * results in the list of videos / the comments list
 * @type String
 */
userClips.VIDEOS_NEXT_PAGE_BUTTON = 'videosNextPageButton';
userClips.COMMENTS_NEXT_PAGE_BUTTON = 'commentsNextPageButton';

/**
 * container div IDs used to hold list of videos / comments 
 * or where the upload process takes place
 * @type String
 */
userClips.VIDEO_LIST_CONTAINER_DIV = 'searchResultsVideoList';
userClips.COMMENTS_LIST_CONTAINER_DIV = 'commentsList';
userClips.UPLOADING_DIV = 'videoUpload';

/**
 * container div id used to hold the video player
 * @type String
 */
userClips.VIDEO_PLAYER_DIV = 'video'; //'videoPlayer';

/**
 * container div id used to hold the search box which displays when the page
 * first loads
 * @type String
 */
userClips.MAIN_SEARCH_CONTAINER_DIV = 'mainSearchBox';

/** 
 * container div id used to hold the search box displayed at the top of
 * the browser after one search has already been performed
 * @type String
 */
userClips.TOP_SEARCH_CONTAINER_DIV = 'searchBox';

/**
 * Maximum number of tokens accepted for comments.
 * @type Number
 */
userClips.COMMENT_MAX_CHARS = 500;

/**
 * the page number to use for the next page navigation button
 * @type Number
 */
userClips.nextVideoPage = 2;
userClips.nextCommentPage = 2;

/**
 * the page number to use for the previous page navigation button
 * @type Number
 */
userClips.previousVideoPage = 0;
userClips.previousCommentPage = 0;

/** 
 * the last search term used to query - allows for the navigation
 * buttons to know what string query to perform when clicked
 * @type String
 */
userClips.previousSearchTerm = '';

/**
 * the last query type used for querying - allows for the navigation
 * buttons to know what type of query to perform when clicked
 * @type String
 */
userClips.previousQueryType = 'all';

/**
 * ID of the YouTube video that is currently (dis)played
 * @type String
 */
userClips.playingVideoId = '';

/**
 * the last ordering (relevance, published, viewCount and rating) 
 * used for a query
 * @type String
 */
userClips.previousOrder = '';


/**
 * User clips init function that is called on 'domready' event.
 * Lists videos and comments for the start video and registers events 
 * for the user clips.
 * 
 * @param {String} channel The channel name.
 * @param {String} videoId The video entry ID of the video to play.
 */
userClips.init = function(channel, videoId) 
{
	
	userClips.listVideos(channel, null, 1, 'published');
	userClips.listComments(videoId, 1);
	
	// Track the number of characters that are filled into the textarea 
	$('comment').addEvent('keyup', function() {
		videoCenter.tokenTracker(
			'comment', userClips.COMMENT_MAX_CHARS, 'cCounter', 'cCounterLabel'
		);
	});
	
	// Close comment overlay and reset input when cancelComment is clicked
	$('cancelComment').addEvent('click', function() {
		userClips.resetComment(
			'commentOverlay', 'comment', 'cCounter', 'cCounterLabel'
		);
	});

	$('commentForm').addEvent('submit', function(event) {
		// The passed event parameter is an instance of the Event class
		var isValid = userClips.validateComment('comment', event);
		if (isValid)
			userClips.saveComment('comment', event);
	});

}
/** EOF function */


/**
 * Simple function that performs some statements when user clip commenting
 * is canceled.
 *
 * @param {String} overlay      DOM id of the overlay window
 * @param {String} text         DOM id of the comment textarea
 * @param {String} counter      DOM id of the counter element
 * @param {String} counterLabel DOM id of the element that labels the counter
 */
userClips.resetComment = function(overlay, text, counter, counterLabel)
{
	if (!overlay || !text || !counter || !counterLabel)
		return alert("Wrong parameters!");
		
	$(overlay).setStyle('display', 'none');
	$(text).value = '';
	$(counterLabel).innerHTML = "Verbleibende Zeichen: ";
	$(counter).innerHTML = userClips.COMMENT_MAX_CHARS;
}

/**
 * Validate the comment. There's not much to validate – actually it's just the 
 * length...
 *
 * @param {String} text  DOM id of the comment textarea
 * @param {Object} event Instance of the Event class
 */
userClips.validateComment = function(text, event)
{
	if (!text)
		return alert("Wrong parameters!");
	
	var comment = $(text).value;
	
	// Remove all extraneous whitespace and trim the comment
	comment = comment.clean();
	
	var commentLength = comment.length;
	
	/*
	 * If comment is too long or empty, stop submission and show alert
	 */
	
	if (commentLength > userClips.COMMENT_MAX_CHARS) {
		event.stop();
		alert("Der Kommentar ist zu lang (max. 500 Zeichen).");
		return false;
	} else if (commentLength == 0) {
		event.stop();
		alert("Da steht doch noch gar nichts!");
		return false;
	} else {
		return true;
	}
}

/**
 * Prepares the comment for saving and starts the corresponding AJAX request.
 *
 * @param {String} text  DOM id of the comment textarea
 * @param {Object} event Instance of the Event class
 */
userClips.saveComment = function(text, event)
{
	if (!text)
		return alert("Wrong parameters!");
	
	event.stop();
	
	var cleanedComment;
	var params;

	// Remove all extraneous whitespace and trim the comment
	cleanedComment = $(text).value.clean();

	// Strip the comment of <script> tags and anything in between them
	cleanedComment = cleanedComment.stripScripts();
	
	/*
	 * AJAX request Mootools style
	 */ 
	
	params = {
		comment : cleanedComment,
		videoId : userClips.playingVideoId
	};
	
	var options = {
		url  : '/userclips/savecomment',
		data : params,
		onRequest : function() {
			$('commentStatus').innerHTML = '<b>Saving ... </b>&nbsp;' + 
				'<img src="../gfx/loader.gif" alt="" />';
		},
		onComplete : function() {
			userClips.resetComment('commentOverlay', 
				'comment', 'cCounter', 'cCounterLabel');
			$('commentStatus').innerHTML = '';
		},
		onSuccess : function(responseText, responseXML) {
			userClips.listComments(userClips.playingVideoId, 1);
		}
	};
	
	var request = new Request(options);
	request.send();
}

/**
 * Helper method that removes unwanted tokens from the searchTerm.
 * 
 * @param {String} searchTerm The search term entered by a user.
 * @return {String} searchTerm The sanitized string.
 */
userClips.sanitizeSearchTerm = function(searchTerm) {	
	var sanitizedSearchTerm; 
	
	// Remove whitespaces from beginning and end
	sanitizedSearchTerm = searchTerm.strip();
	
	// Remove any HTML tags
	sanitizedSearchTerm = sanitizedSearchTerm.stripTags();
	
	// Remove any scripts
	sanitizedSearchTerm = sanitizedSearchTerm.stripScripts();
	
	// Replace whitespaces
	sanitizedSearchTerm = sanitizedSearchTerm.gsub(' ', '+');
	
	return sanitizedSearchTerm;
}


/**
 * Retrieves a list of videos matching the provided criteria. The list of
 * videos can be restricted to a particular standard feed or search criteria.
 *
 * @param {String} channel The channel to search in - either 'all'
 *     for querying all channels, or the name of a channel.
 * @param {String} searchTerm The search term(s) to use for querying as the
 *     'vq' query parameter value
 * @param {Number} page The 1-based page of results to return.
 * @param {String} order The ordering (relevance, published, viewCount and rating).
 */
userClips.listVideos = function(channel, searchTerm, page, order) {
  userClips.previousSearchTerm = searchTerm; 
  userClips.previousQueryType = channel; 
	userClips.previousOrder = order;
	
  var maxResults = userClips.MAX_RESULTS_LIST;
  var startIndex =  (((page - 1) * userClips.MAX_RESULTS_LIST) + 1);
	
	/*
	if (searchTerm && !searchTerm.blank())
	{
	  searchTerm = userClips.sanitizeSearchTerm(searchTerm);
  }
	*/
	
	if (searchTerm) {
		// Removes all extraneous whitespace from a string and trims it
		searchTerm = searchTerm.clean();
	}

	userClips.presentFeed(channel, searchTerm, maxResults, startIndex, order);
  userClips.updateVideoNavigation(page, 
		userClips.VIDEOS_PREVIOUS_PAGE_BUTTON, 
		userClips.VIDEOS_NEXT_PAGE_BUTTON);
};


/**
 * listComments()
 *
 * Retrieves an Id of a video entry object and shows the
 * corresponding comments on that video.
 *
 * @param {String} videoId The video entry Id.
 * @param {Number} page The 1-based page of results to return.
 */
userClips.listComments = function(videoId, page) {
	var videoId = videoId;
	
	// Make current videoId available in global scope
	userClips.playingVideoId = videoId;
	
	var maxResults = userClips.MAX_COMMENTS_LIST;
  var startIndex =  (((page - 1) * userClips.MAX_COMMENTS_LIST) + 1);
	var resultDiv = userClips.COMMENTS_LIST_CONTAINER_DIV;
	var params = 'videoId=' + videoId +
							 '&maxResults=' + maxResults +
							 '&startIndex=' + startIndex;
	var filePath = '/userclips/echocomments';
	
	// Send an AJAX request
	userClips.sendRequest(filePath, params, resultDiv, 0, 1);
	
	// Update the previous and next buttons and keep track of the current page
	userClips.updateCommentNavigation(
		page,
		userClips.COMMENTS_PREVIOUS_PAGE_BUTTON,
		userClips.COMMENTS_NEXT_PAGE_BUTTON
	);
};


/**
 * Sends an AJAX request to the server to retrieve a list of videos, comments 
 * or the video player/metadata. Sends the request to the specified filePath
 * on the same host, passing the specified params, and filling the specified
 * resultDivName with the resutls upon success.
 *
 * @param {String}  filePath      The path to which the request should be sent
 * @param {String}  params        The URL encoded POST params
 * @param {String}  resultDivName The name of the DIV used to hold the results
 * @param {Boolean} loadClip      If true, request a specific clip
 * @param {Boolean} loadList      If true, request a video feed
 */
userClips.sendRequest = function(filePath, params, resultDivName, loadClip, loadList) 
{	
	var resultDiv = $(resultDivName);
	var headlineDiv = $('videosHeadline');
	/*
	var options = {
		parameters : params,
		onLoading : resultDiv.innerHTML = '<b>Loading ...</b>',
		onSuccess : function(transport) {
			//var json = transport.responseText.evalJSON(true);
			var html = transport.responseText;	
		},
		onComplete : function(transport) {
			if (!params.searchTerm.blank()) {
				headlineDiv.innerHTML = 'Suchergebnisse...';
				Effect.ScrollTo(headlineDiv);
			}
		}
	};
	*/
	
	var options = {
		url : filePath,
		data : params,
		update : resultDiv,
		onRequest : function() {
			if (loadClip) {
				resultDiv.innerHTML = '<h2>Loading ... &nbsp;' + 
					'<img src="../gfx/loader.gif" alt="" /></h2>';
			}
			if (loadList) {
				resultDiv.innerHTML = '<b>Loading ...</b>&nbsp;' + 
					'<img src="../gfx/loader.gif" alt="" />';
			}
		},
		onSuccess : function(responseTree, responseElements, responseHTML, responseJavaScript) {
			if (loadList) {
				if (results) {
					(results > 1) || (results == 0) ? 
						$('videosHeadline').innerHTML = 'Clips ' + von + 
							' bis ' + bis + ' von ' + results : 
						$('videosHeadline').innerHTML = '1 Clip';
				}
			}
		},
		onComplete : function() {
			var scrollWindow = new Fx.Scroll(window);
			if (params.searchTerm && !params.searchTerm == '') {
				headlineDiv.innerHTML = 'Suchergebnisse';
				// Effect.ScrollTo(headlineDiv);
				scrollWindow.toElement(headlineDiv);
			}
			if (loadClip) {
				scrollWindow.toElement(resultDiv);				
			}
		}
	};
	
	// Prototype notation:
	// new Ajax.Updater(resultDivName, filePath, options);
	
	// Mootools notation:
	var request = new Request.HTML(options);
	request.send();
}

/**
 * Uses userClips.sendRequest to display a YT video player and metadata for the
 * specified video ID.
 * @param {String} videoId The ID of the YouTube video to show
 */
userClips.presentVideo = function(videoId) {
  var params = { videoId : videoId };
  var filePath = '/userclips/echovideoplayer';
	
  userClips.sendRequest(filePath, params, userClips.VIDEO_PLAYER_DIV, 1, 0);
	userClips.listComments(videoId, 1);
}

/**
 * Uses userClips.sendRequest to display a list of of YT videos.
 *
 * @param {String} channel The channel to search in - either 'all'
 *     for querying all channels, or the name of a channel.
 * @param {String} searchTerm The search terms to pass to the specified feed
 * @param {Number} maxResults The maximum number of videos to list
 * @param {Number} startIndex The first video to include in the list
 * @param {String} order The ordering (relevance, published, viewCount and rating).
 */
userClips.presentFeed = function(channel, searchTerm, maxResults, startIndex, order) {
	var params = {
		channel 	 : channel, 
		searchTerm : searchTerm,
    maxResults : maxResults,
    startIndex : startIndex, 
		orderBy		 : order
	}
	
	// If search was performed on start page
	try {
		// If search was performed on start page
		$('standard-layout').hide();
		$('after-search-layout').show();
	} catch (e) {
		// do nothing;
	}
	
  var filePath = '/userclips/echovideolist';
  userClips.sendRequest(
		filePath, params, userClips.VIDEO_LIST_CONTAINER_DIV, 0, 1
	);
}


/**
 * Updates the variables used by the navigation buttons and the 'enabled' 
 * status of the buttons based upon the current page number passed in.
 * 
 * @param {Number} page The current page number
 * @param {String} prevButton The DOM id of the previous button
 * @param {String} nextButton The DOM id of the next button
 */
userClips.updateVideoNavigation = function(page, prevButton, nextButton) {
	userClips.nextVideoPage = page + 1;
  userClips.previousVideoPage = page - 1;
  document.getElementById(nextButton).style.display = 'inline';
  document.getElementById(prevButton).style.display = 'inline';
  if (userClips.previousVideoPage < 1) {
    document.getElementById(prevButton).disabled = true;
  } else {
    document.getElementById(prevButton).disabled = false;
  }
  document.getElementById(nextButton).disabled = false;
};


/**
 * Updates the variables used by the navigation buttons and the 'enabled' 
 * status of the buttons based upon the current page number passed in.
 * 
 * @param {Number} page The current page number
 * @param {String} prevButton The DOM id of the previous button
 * @param {String} nextButton The DOM id of the next button
 */
userClips.updateCommentNavigation = function(page, prevButton, nextButton) {
  userClips.nextCommentPage = page + 1;
  userClips.previousCommentPage = page - 1;
  document.getElementById(nextButton).style.display = 'inline';
  document.getElementById(prevButton).style.display = 'inline';
  if (userClips.previousCommentPage < 1) {
    document.getElementById(prevButton).disabled = true;
  } else {
    document.getElementById(prevButton).disabled = false;
  }
  document.getElementById(nextButton).disabled = false;
};