
(function( $ ){

  $.fn.enjinComments = function(options) {
  
		var defaults = { 	
						 
						 /** 
						  * required - comment container Id to display
						  */ 
						 comment_cid: false
						 
						 /**
						  * Object defining comments to display in the initial rendering [will skip ajax
						  * loading step when defined]
						  *
						  * {
						  *		total: Total number of comments
						  *		comments: [ array of comment objects, see @renderComment ]
						  * }
						  */
						 ,data: false
						 
						,locate_comment_id: false
						
						/** 
						 * Header text on the comments container, use the marker {total} to substitute
						 * with the total number of comments available for display
					     */
						,header: "<span class='num'>{total}</span> <span class='numtext'>Comment{plural}</span>"
						
						/* optional extra HTML to append to the end of the header */
						,headerExtra: ''
						
						/**
						 * optional additional CSS classes to use for the primary DIV wrapper for the comments
						 * section, as a single string, as in 'class1 class2 class3'
						 */
						,cssClass: ''
						
						/**
                         *	optional additional CSS classes to use for the primary DIV wrapper for the Add Comments
						 * section, as a single string, as in 'class1 class2 class3'						
						 */
						,addClass: ''
						
						/**
						 * Number of comments to show in each fetch block, either initially or when View More is acivated
						 */
						,pageSize: 15
						
						/**
						 * Number of sub-comments to show in each fetch block, initially or when View More
						 */
						,subPageSize: 3
						
						/**
						 * set this to the to hide the Add Comment container no matter what
						 * this leaves the Add Comment/Reply links alone, just does not render the
						 * seperate Add Comment container 
						 */
						,hideAdd: false		
											
						/**
						 * set this to disable adding/replying on comments no matter what
						 * same as hideAdd + there are no Reply and Add Comment links in comment container either
						 */
						,disableAdd: false	
						
						/** 
						 * Time in milli-seconds for deleted comment blocks to fade out
						 */
						,fadeDelay: 600
						
						/**
						 * Function to be called when a new comment has been posted, this will only be called
						 * for main comments and not sub-comments
						 *
						 * postCallback( comment, total_comments_overall, options );
						 *
						 */
						,postCallback: null
						
						/**
						 * Function to be called when a comment has been deleted, this will only be called
						 * for main comments and not sub-comments
						 *
						 * deleteCallback( total_comments_overall, options );
						 *
						 */
						 ,deleteCallback: null,
						 
						 /**
						  * Function to be called on load to display intial count of comments in the container
						  */
						 countCallback: null
					  };
					  
		 var options = jQuery.extend(defaults, options);

		return this.each( function ()
							{
								// short-cut pointer to the jQuery instance of the DOM element 
								// into which the entire comments module is being rendered
								var self = $(this);
								
								// basic set of params to the ajax loading methods, extended by
								// each individual type of fetch to add in custom fields
								var loadParams = {
													comment_cid: options.comment_cid,
													pageSize: options.pageSize,
													subPageSize: options.subPageSize
												};
											
								// DOM element defining the container for the comments to be displayed
								var commentContainer = null;
								// DOM element inside the commentContainer holding the actual comments
								var commentBlock = null;
								
								// DOM element defining the container for the Add Commment block
								var addContainer = null;								
								
								// this is the total number of comments currently being displayed
								var totalComments = 0;
								
								var hideReplyBox = function()
								{
									// find the reply box, there can only ever be one
									// active at a time in the module
									var replyBox = self.find('.reply');
									
									// check the reply mode, if this is false, then the reply
									// is being used to enter a main comment, and as a result
									// has a fake comment wrapper around it which must be removed
									// as well to prevent css glithes
									if ( replyBox.attr('data-replymode') == 'false' )
									{
										replyBox.closest('.comment').remove();
									}
									else									
									{
										replyBox.remove();
									}
								}
								
								var reply = function()
								{
									hideReplyBox();
									
									var comment = $(this).closest('.comment');
									comment.after( renderReplyBox(true) );
									
									return false;
								};	
								
								var replyComment = function()
								{
									hideReplyBox();
									var box = renderReplyBox(true);

									var comment = $(this).closest('.comment');
									var container = comment.find('.subcomment');
									if ( container.length == 0 )
									{
										container = $("<div class='subcomment'></div>");
										comment.find('.data').append(container);
									}
									
									container.prepend(box);
									return false;
								};
								
								var deleteComment = function(event)
								{
									Enjin_Core.stopBubble(event);

									var container = $(this).closest('.comment');
									var id = container.attr('data-comment_id');
										
									var deleteCallback = function( r )
										{
											if ( typeof response === 'object' && response.success == false )
											{
												Enjin_Core.alert(response.error);
											}
											else
											{		
												var pid = parseInt(container.attr('data-parent_comment_id'),10);
												if ( pid == 0 ) 
												{												
													options.data.total--;
													totalComments--;
													updateHeader();
												}	
												
												// fade out and remve the deleted commented, if this is the last comment on this container
												// then hide the entire comment container instead
												if ( options.data.total == 0 )
												{
													commentContainer.fadeOut(options.fadeDelay, function() { container.remove(); commentContainer.hide(); } ); 
												}
												else
												{
													container.fadeOut(options.fadeDelay, function(){ container.prev().addClass('last'); container.remove(); });
												}															
				
												// if there is a callback for deleting run it now
												if ( pid == 0 && typeof options.deleteCallback === 'function' )
												{
													options.deleteCallback( options.data.total, options );
												}												
											}	
										};
									
									var params = {op:'delete', comment_cid:options.comment_cid, comment_id:id};									
									Enjin_Core.showPopup({message: 'Are you sure you want to delete this comment?'
														 ,callback: function()
																	{
																		$.post('/ajax.php?s=comments', params,
																			deleteCallback
																		);
																	}
														 });
									
									/*
									Enjin_Core.showPopup({message: 'Are you sure you want to delete this comment?',
														  callback:	function() 
															{			
																$.post('/ajax.php?s=comments', params, deleteCallback, 'json');																		
															}	
														});
										*/				
									return false;									
								};
								
								
								var addComment = function()
								{
									hideReplyBox();

									var container = $('<div class="comment"></div>');
									container.append(renderReplyBox(false));
									commentBlock.prepend(container);
									return false;
								};
								
								var postReply = function()
								{
									var val = $(this).closest('.reply-box').find('textarea').val();
									if ( val == "" ) { Enjin_Core.alert("The comment can't be empty."); return; }

									var id = $(this).closest('.comment').attr('data-comment_id');			
									var subContainer = $(this).closest('.reply');
									Enjin_Core.disableButton(this, 2);
									
									$.post('/ajax.php?s=comments', 
										   {op:'reply', comment_cid: options.comment_cid, content: val, parent_comment_id: id}, 
										   function(comment) 
											{
												if ( typeof comment.success !== 'undefined' && comment.success == false )
												{
													Enjin_Core.alert(comment.error);
												}
												else
												{
													comment.comment.last = true;
													var block = renderComment(comment.comment); 
													subContainer.after(block.fadeIn(150)); 
												}
												
												hideReplyBox();
											},
											'json'
										  );
								};
								
								var postComment = function()
								{					
									// flag if the comment is begin added via the Add box below or in the
									// embedded format
									var isReplyFormat = false;
									
									var container = $(this).closest('.addcomment');
									if ( container.length == 0 )
									{
										container = $(this).closest('.reply-box');
										isReplyFormat = true;
									}
									
									var val = container.find('textarea').val();
									if ( val == "" ) { Enjin_Core.alert("The comment can't be empty."); return; }
									
									container.find('textarea').val('');
									Enjin_Core.disableButton(this, 2);
									
									$.post('/ajax.php?s=comments', 
										   {op:'add', comment_cid: options.comment_cid, content: val}, 
										   function(comment) 
											{											
												if ( isReplyFormat ) { hideReplyBox(); }
												
												if ( typeof comment.success !== 'undefined' && comment.success == false )
												{
													Enjin_Core.alert(comment.error);
												}
												else
												{
													options.data.total = comment.total;
													updateHeader();
													commentBlock.prepend( renderComment(comment.comment).fadeIn(600) );
													
													// make sure the comment block is visible in case this was the first
													// comment and it was hidden before
													commentContainer.show();			
					
													// if there is a callback for posting run it now
													if ( typeof options.postCallback === 'function' )
													{
														options.postCallback( comment.comment, options.data.total, options );
													}	
												}	
											},
											'json'
										  );
								};
								
								var getHeaderText = function( data )
								{
									var header = options.header.replace('{total}',data.total);
									header = header.replace('{plural}', data.total > 1 ? 's' : '');
									return header + options.headerExtra;			
								};
								
								var updateHeader = function()
								{
									commentContainer.find('.header').html( getHeaderText(options.data) );
								};
								
								/**
								 * Renders the div showing the More link for the main comments section
								 */
								var renderMoreLink = function()
								{
									var total = options.data.total - totalComments;
									if ( total > options.pageSize ) { total = options.pageSize; } 
									
									var container = $('<div class="more"></div>');
									container.append( $('<a href="#">View ' + total + ' More Comments</a>').click(fetchComments) ); 
									return container;
								}
								
								/**
								 * Get DOM for a comment/reply editor
								 * @param bool replyMode  True if its a sub-comment editor, false if main comment
								 */
								var renderReplyBox = function( replyMode )
								{
									var label = replyMode === true ? 'Post Reply' : 'Add Comment';
									var action = replyMode === true ? postReply : postComment;

									var container = $('<div data-replymode="'+replyMode+'" class="reply"></div>');
									var avatar = $('<div class="avatar">' + options.data.myAvatar + '</div>');
									
									var block = $('<div class="reply-box"></div>');		
									block.append( Enjin_UI.textarea() );
									block.append( Enjin_UI.button({value: label, click: action}) );		
									
									container.append(avatar);
									container.append(block);
									return container;									
								};
								
								/**
								 * comment is an object containing data for a single comment
								 *	{
								 *		avatar: HTML for avatar as generated by UserAvatar helper
								 *		username: HTML for username as generated by Username helper
								 *		content: comment body with BBCode expanded into HTML
								 *		time: comment timestamp in display format
								 *		can_reply: true if the current user can reply on the comment
								 *		can_delete: true if the current user can delete the comment
								 *		last: true if this is the last comment or subcomment in the list
								 *		comments: [ array of comment objects defining sub-commments ]
								 *	}
								 */
								var renderComment =  function(comment)
								{				
									var hasSubComments = ( typeof comment.comments === 'object' && comment.comments.total > 0 );
									var isMain = ( comment.parent_comment_id == 0 || comment.parent_comment_id == null );

									if ( comment.last ) var extraCssClass = ' last';
									else var extraCssClass = '';

									var container = $("<div class='comment" + extraCssClass + "'><table class='comment-table'><tr><td class='a'></td><td class='c'></td></tr></table></div>");
									container.attr('data-comment_id', comment.comment_id);
									container.attr('data-parent_comment_id', isMain ? '0' : comment.parent_comment_id);
									
									var avatar = $('<div class="avatar">' + comment.avatar + '</div>');
									var block = $('<div class="data"></div>');
									
									var user = $("<div class='user'></div>");
									if ( !comment.user_id )
									{
										user.html( "<span class='guest'>" +comment.guest_name + "</span>" );
									}
									else
									{
										user.html( comment.username );
									}
									
									block.append(user);
									
									block.append( $("<div class='content'>" + comment.content + "</div>") );
									
									var tools = $("<div class='tools'></div>") ;
									
									if ( comment.can_reply )
									{	
										tools.append( $("<a href='#'>Reply</a>").click(isMain ? replyComment : reply) );
										tools.append('&nbsp;&middot;&nbsp;');									
									}
									
									if ( comment.can_delete )
									{			
										tools.append( $("<a href='#'>Delete</a>").click(deleteComment) );
										tools.append('&nbsp;&middot;&nbsp;');									
									}
									
									tools.append( comment.time );
									
									block.append( tools );									
									
									if ( hasSubComments )
									{
										var subContainer = $('<div class="subcomment"></div>');
										for ( var i = 0; i < comment.comments.comments.length; i++ )
										{
											if(i == comment.comments.comments.length - 1) comment.comments.comments[i].last = true;
											subContainer.append( renderComment(comment.comments.comments[i]) );
										}	

										if ( comment.comments.total > options.subPageSize )
										{
											var view = 'View ' + (comment.comments.total - options.subPageSize) + ' More';
											var viewLink = $('<div class="viewmore"><a href="#">' + view + '</a></div>');
											viewLink.find('a').click(fetchSubComments);
											subContainer.append( viewLink );	
										}
											
										block.append(subContainer);
									}
									
									container.children('table').children('tbody').children('tr').children('td.a').append(avatar);
									container.children('table').children('tbody').children('tr').children('td.c').append(block);
									
									return container;									
								};								
							
								/**
								 * Render the container for the comments section
								 */
								var renderContainer = function()
								{
								
									commentContainer = $("<div class='dcommentbox contentbox "  + options.cssClass + "'>" +
														 "<div class='block-title'>" +
															"<div class='left graphic'><!-- --></div>" +
															"<div class='right graphic'><!-- --></div>" +
															"<div class='text'>" +
																"<div class='mask header'></div>" +
																"<div class='text-right'></div>" +
															"</div>" +
														 "</div>" +  
														 "</div>");
									
									commentContainer.append( Enjin_UI.blockContainer({cssClass:'comments'}) );						
									
									if ( options.disableAdd === false ) 
									{
										commentContainer.find('.block-title .text-right').append( $('<a href="#">Add Comment</a>').click( addComment ) );
									}									
									
									self.append(commentContainer);
								};
								
								/**
								 * Render the Add Comment section below the comments
								 */
								var renderAddContainer = function( )
								{
									addContainer = $("<div class='contentbox addcomment " + options.addClass + "'>" +
													 "<div class='block-title'>" +
														"<div class='left'><!-- --></div>" +
														"<div class='right'><!-- --></div>" +
														"<div class='text'>" +
															"<div class='mask'>Add Comment</div>" +
														"</div>" +
													 "</div>" +
													 "</div>");
													 
									var form = Enjin_UI.container('form');
									form.append( Enjin_UI.textarea({name:'content'}) );
									form.append( Enjin_UI.button({value:'Post Comment', click:postComment}) );
									
									var block = Enjin_UI.blockContainer();
									block.append(form);
									addContainer.append(block);	 		

									self.append(addContainer);									
								};

								/**
								 * Do the initial generation of the comments DOM
								 */								  
								var renderData = function(data)
								{
									options.data = data;
									
									commentBlock = commentContainer.find('.comments .structure');
									for ( var i = 0; i < data.comments.length; i++ )
									{	
										data.comments[i].parent_comment_id = parseInt(data.comments[i].parent_comment_id,10);

										if(i == data.comments.length - 1) data.comments[i].last = true;
										var comment = renderComment( data.comments[i] );
										commentBlock.append(comment);
										
										totalComments++;
									}

									// if there are no comments to show initially we hide the comments block
									if ( data.comments.length == 0 )
									{
										commentContainer.hide();
									}
									else
									{
										// if there are more comments than being shown add a "More" marker
										if ( options.data.total > totalComments )
										{
											commentBlock.append( renderMoreLink );
										}
										
										if ( typeof options.countCallback == 'function' )
										{
											options.countCallback( options.data.total, options );
										}	
									}
									
									updateHeader();
								};
								
								var renderSubComments = function( data )
								{
									var container = commentBlock.find('.comment[data-comment_id=' + data.comments[0].parent_comment_id + ']');
									var subComments = container.find('.subcomment').empty();
									
									for ( var i = 0; i < data.comments.length; i++ )
									{
										if(i == data.comments.length - 1) data.comments[i].last = true;
										var comment = renderComment( data.comments[i] );
										subComments.append(comment);
									}
								}
								
								/**
								 * Load the inital data to create the comments container
								 */
								var load = function()
								{
									var params = $.extend( {op:'load', locate_comment_id: options.locate_comment_id}, loadParams );
									$.post( '/ajax.php?s=comments', params, renderData, 'json' );
								};
								
								/**
								 * Fetchs a batch of comments for display
								 */							
								var fetchComments = function()
								{
									// remove the "View More" block
									var more = self.find('.more');
									more.prev().removeClass('last');
									more.remove();
									
									var params = $.extend( {op:'load', start: totalComments, parent_comment_id:0}, loadParams );
									$.post( '/ajax.php?s=comments', params, renderData, 'json' );
									
									return false;
								};
								
								var fetchSubComments = function()
								{
									var pid = $(this).closest('.comment').attr('data-comment_id');
									
									// when we request the list of sub-comments we set the page size as "unlimited" so that
									// all the sub-comments will be returned
									var params = $.extend( {op:'load', start: 0, parent_comment_id: pid}, loadParams );
									params.subPageSize = 1000;
									$.post( '/ajax.php?s=comments', params, renderSubComments, 'json' );
									
									return false;
								};

								self.addClass('m_plugin_comment');
									
								// render the container for the 
								renderContainer();
								
								// optionaly put a Add Comment block underneath
								if ( options.disableAdd === false )
								{
									renderAddContainer();
								}									
							
								// if a static list of comments has been given, render these
								// now, otherwise load the comments from the container via ajax								
								if ( options.data !== false )
								{
									renderData(options.data);
								}
								else
								{
									load();
								}								
							}
						);
  };
})( jQuery );
