<?php
/**
 * This file implements Comment handling functions.
  *
 * This file is part of the b2evolution/evocms project - {@link http://b2evolution.net/}.
 * See also {@link http://sourceforge.net/projects/evocms/}.
 *
 * @copyright (c)2003-2010 by Francois PLANQUE - {@link http://fplanque.net/}.
 * Parts of this file are copyright (c)2004-2005 by Daniel HAHLER - {@link http://thequod.de/contact}.
 *
 * @license http://b2evolution.net/about/license.html GNU General Public License (GPL)
 *
 * {@internal Open Source relicensing agreement:
 * Daniel HAHLER grants Francois PLANQUE the right to license
 * Daniel HAHLER's contributions to this file and the b2evolution project
 * under any OSI approved OSS license (http://www.opensource.org/licenses/).
 * }}
 *
 * @package evocore
 *
 * @todo implement CommentCache based on LinkCache
 *
 * {@internal Below is a list of authors who have contributed to design/coding of this file: }}
 * @author cafelog (team)
 * @author blueyed: Daniel HAHLER.
 * @author fplanque: Francois PLANQUE.
 *
 * @version $Id: _comment.funcs.php,v 1.10.2.12 2011/02/24 18:43:45 sam2kb Exp $
 */
if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );

load_class( 'comments/model/_comment.class.php', 'Comment' );

/**
 * Generic comments/trackbacks/pingbacks counting
 *
 * @todo check this in a multiblog page...
 * @todo This should support visibility: at least in the default front office (_feedback.php), there should only the number of visible comments/trackbacks get used ({@link Item::feedback_link()}).
 *
 * @param integer
 * @param string what to count
 */
function generic_ctp_number( $post_id, $mode = 'comments', $status = 'published' )
{
	global $DB, $debug, $postdata, $cache_ctp_number, $preview;

	if( $preview )
	{ // we are in preview mode, no comments yet!
		return 0;
	}

	/*
	 * Make sure cache is loaded for current display list:
	 */
	if( !isset($cache_ctp_number) )
	{
		global $postIDlist, $postIDarray;

		// if( $debug ) echo "LOADING generic_ctp_number CACHE for posts: $postIDlist<br />";

		if( ! empty( $postIDlist ) )	// This can happen when displaying a featured post of something that's not in the MainList
		{
			foreach( $postIDarray as $tmp_post_id)
			{	// Initializes each post to nocount!
				$cache_ctp_number[$tmp_post_id] = array(
						'comments' => array( 'published' => 0, 'draft' => 0, 'deprecated' => 0, 'total' => 0 ),
						'trackbacks' => array( 'published' => 0, 'draft' => 0, 'deprecated' => 0, 'total' => 0 ),
						'pingbacks' => array( 'published' => 0, 'draft' => 0, 'deprecated' => 0, 'total' => 0 ),
						'feedbacks' => array( 'published' => 0, 'draft' => 0, 'deprecated' => 0, 'total' => 0 )
					);
			}

			$query = 'SELECT comment_post_ID, comment_type, comment_status, COUNT(*) AS type_count
								 FROM T_comments
								 WHERE comment_post_ID IN ('.$postIDlist.')
								 GROUP BY comment_post_ID, comment_type, comment_status';

			foreach( $DB->get_results( $query ) as $row )
			{
				// detail by status, tyep and post:
				$cache_ctp_number[$row->comment_post_ID][$row->comment_type.'s'][$row->comment_status] = $row->type_count;

				// Total for type on post:
				$cache_ctp_number[$row->comment_post_ID][$row->comment_type.'s']['total'] += $row->type_count;

				// Total for status on post:
				$cache_ctp_number[$row->comment_post_ID]['feedbacks'][$row->comment_status] += $row->type_count;

				// Total for post:
				$cache_ctp_number[$row->comment_post_ID]['feedbacks']['total'] += $row->type_count;
			}
		}
	}
	/*	else
	{
		echo "cache set";
	}*/


	if( !isset($cache_ctp_number[$post_id]) )
	{ // this should be extremely rare...
		// echo "CACHE not set for $post_id";

		// Initializes post to nocount!
		$cache_ctp_number[intval($post_id)] = array(
				'comments' => array( 'published' => 0, 'draft' => 0, 'deprecated' => 0, 'total' => 0 ),
				'trackbacks' => array( 'published' => 0, 'draft' => 0, 'deprecated' => 0, 'total' => 0 ),
				'pingbacks' => array( 'published' => 0, 'draft' => 0, 'deprecated' => 0, 'total' => 0 ),
				'feedbacks' => array( 'published' => 0, 'draft' => 0, 'deprecated' => 0, 'total' => 0 )
			);

		$query = 'SELECT comment_post_ID, comment_type, comment_status, COUNT(*) AS type_count
							  FROM T_comments
							 WHERE comment_post_ID = '.intval($post_id).'
							 GROUP BY comment_post_ID, comment_type, comment_status';

		foreach( $DB->get_results( $query ) as $row )
		{
			// detail by status, tyep and post:
			$cache_ctp_number[$row->comment_post_ID][$row->comment_type.'s'][$row->comment_status] = $row->type_count;

			// Total for type on post:
			$cache_ctp_number[$row->comment_post_ID][$row->comment_type.'s']['total'] += $row->type_count;

			// Total for status on post:
			$cache_ctp_number[$row->comment_post_ID]['feedbacks'][$row->comment_status] += $row->type_count;

			// Total for post:
			$cache_ctp_number[$row->comment_post_ID]['feedbacks']['total'] += $row->type_count;
		}
	}

	if( ($mode != 'comments') && ($mode != 'trackbacks') && ($mode != 'pingbacks') )
	{
		$mode = 'feedbacks';
	}

	if( ($status != 'published') && ($status != 'draft') && ($status != 'deprecated') )
	{
		$status = 'total';
	}

	// pre_dump( $cache_ctp_number[$post_id] );

	return $cache_ctp_number[$post_id][$mode][$status];
}


/**
 * Get a Comment by ID. Exits if the requested comment does not exist!
 *
 * @param integer
 * @param boolean
 * @return Comment
 */
function & Comment_get_by_ID( $comment_ID, $halt_on_error = true )
{
	$CommentCache = & get_CommentCache();
	return $CommentCache->get_by_ID( $comment_ID, $halt_on_error );
}


/*
 * last_comments_title(-)
 *
 * @movedTo _obsolete092.php
 */


/***** Comment tags *****/

/**
 * comments_number(-)
 *
 * @deprecated deprecated by {@link Item::feedback_link()}, used in _edit_showposts.php
 */
function comments_number( $zero='#', $one='#', $more='#', $post_ID = NULL )
{
	if( $zero == '#' ) $zero = T_('Leave a comment');
	if( $one == '#' ) $one = T_('1 comment');
	if( $more == '#' ) $more = T_('%d comments');

	// original hack by dodo@regretless.com
	if( empty( $post_ID ) )
	{
		global $id;
		$post_ID = $id;
	}
	// fp>asimo: I'm not sure about this below. It's only in the backoffice where
	// we want to display the total. in the front, we still don't want to count in drafts
	// can you check & confirm?
	// asimo>fp: This function is called only from the backoffice ( _item_list_full.view.php ).
	// There we always have to show all comments.
	$number = generic_ctp_number( $post_ID, 'comments', 'total' );
	if ($number == 0)
	{
		$blah = $zero;
	}
	elseif ($number == 1)
	{
		$blah = $one;
	}
	elseif ($number  > 1)
	{
		$n = $number;
		$more = str_replace('%d', $n, $more);
		$blah = $more;
	}
	echo $blah;
}

/**
 * Get advanced perm for comment moderation on this blog
 *
 * @param int blog ID
 * @return array statuses - current user has permission to moderate comments with these statuses
 */
function get_allowed_statuses( $blog )
{
	global $current_User;
	$statuses = array();

	if( $current_User->check_perm( 'blog_draft_comments', 'edit', false, $blog ) )
	{
		$statuses[] = 'draft';
	}

	if( $current_User->check_perm( 'blog_published_comments', 'edit', false, $blog ) )
	{
		$statuses[] = 'published';
	}

	if( $current_User->check_perm( 'blog_deprecated_comments', 'edit', false, $blog ) )
	{
		$statuses[] = 'deprecated';
	}

	return $statuses;
}

/**
 * Create comment form submit buttons
 *
 * Note: Publsih in only displayed when comment is in draft status
 *
 * @param $Form
 * @param $edited_Comment
 *
 */
function echo_comment_buttons( $Form, $edited_Comment )
{
	global $Blog, $current_User;

	// ---------- SAVE ------------
	$Form->submit( array( 'actionArray[update]', T_('Save!'), 'SaveButton' ) );

	// ---------- PUBLISH ---------
	if( $edited_Comment->status == 'draft'
			&& $current_User->check_perm( 'blog_post!published', 'edit', false, $Blog->ID )	// TODO: if we actually set the primary cat to another blog, we may still get an ugly perm die
			&& $current_User->check_perm( 'edit_timestamp', 'edit', false ) )
	{
		 $publish_style = 'display: inline';
	}
	else
	{
		$publish_style = 'display: none';
	}
	$Form->submit( array(
		'actionArray[update_publish]',
		/* TRANS: This is the value of an input submit button */ T_('Publish!'),
		'SaveButton',
		'',
		$publish_style
	) );
}


/**
 * JS Behaviour: Output JavaScript code to dynamically show or hide the "Publish!"
 * button depending on the selected comment status.
 *
 * This function is used by the comment edit screen.
 */
function echo_comment_publishbt_js()
{
	global $next_action;
	?>
	<script type="text/javascript">
	jQuery( '#commentform_visibility input[type=radio]' ).click( function()
	{
		var commentpublish_btn = jQuery( '.edit_actions input[name=actionArray[update_publish]]' );

		if( this.value != 'draft' )
		{	// Hide the "Publish NOW !" button:
			commentpublish_btn.css( 'display', 'none' );
		}
		else
		{	// Show the button:
			commentpublish_btn.css( 'display', 'inline' );
		}
	} );
	</script>
	<?php
}


/**
 * Add a javascript ban action icon after the given url
 * 
 * @param string url
 * @return string the url with ban icon
 */
function add_jsban( $url )
{
	$url = rawurlencode(get_ban_domain( $url ));
	return '<a id="ban_url" href="javascript:ban_url('.'\''.$url.'\''.');">'.get_icon( 'ban' ).'</a>';
}


/**
 * Add a javascript ban action icon after each url in the given content
 * 
 * @param string Comment content
 * @return string the content with a ban icon after each url if the user has spamblacklist permission, the incoming content otherwise
 */
function add_ban_icons( $content )
{
	global $current_User;
	if( ! $current_User->check_perm( 'spamblacklist', 'edit' ) )
	{
		return $content;
	}

	$atags = get_atags( $content );
	$imgtags = get_imgtags( $content );
	$urls = get_urls( $content );
	$result = '';
	$from = 0; // current processing position
	$length = 0; // current url or tag length
	$i = 0; // url counter
	$j = 0; // "a" tag counter
	$k = 0; // "img" tag counter
	while( isset($urls[$i]) )
	{ // there is unprocessed url
		$url = $urls[$i];
		if( validate_url( $url, 'posting', false ) )
		{ // skip not valid urls
			$i++;
			continue;
		}
		while( isset( $imgtags[$k] ) && ( strpos( $content, $imgtags[$k] ) < $from ) )
		{ // skipp already passed img tags
			$k++;
		}

		$pos = strpos( $content, $url, $from );
		$length = evo_strlen($url);
		$i++;

		// check img tags
		if( isset( $imgtags[$k] ) && ( strpos( $imgtags[$k], $url ) !== false )
			&& ( $pos > strpos( $content, $imgtags[$k], $from ) ) )
		{ // current url is inside the img tag, we need to skip this url.
			$result .= substr( $content, $from, $pos + $length - $from );
			$from = $pos + $length;
			$k++;
			continue;
		}

		// check a tags
		if( isset($atags[$j]) )
		{ // there is unprocessed "a" tag
			$tag = $atags[$j];
			if( ( ( $urlpos = strpos( $tag, $url ) ) !== false ) && ( $pos > strpos( $content, $tag, $from ) ) )
			{ // the url is inside the current tag, we have to add ban icon after the tag
				$pos = strpos( $content, $tag, $from );
				$length = strlen($tag);
				while( isset($urls[$i]) && ( ( $urlpos = strpos( $tag, $urls[$i], $urlpos + 1 ) ) !== false ) )
				{ // skip all other urls from this tag
					$i++;
				}
				$j++;
			}
		}
		// add processed part and ban icon to result and set current position
		$result .= substr( $content, $from, $pos + $length - $from );
		$from = $pos + $length;
		$result .= add_jsban( $url );
	}

	// add the end of the content to the result
	$result .= substr( $content, $from, strlen($content) - $from );
	return $result;
}


/*
 * $Log: _comment.funcs.php,v $
 */
?>
