<?php
/**
 * @package Habari
 *
 */

/**
* Habari Tags Class
*
*/
class Tags extends Vocabulary
{
	protected static $vocabulary = 'tags';
	protected static $object_type = 'post';

	/**
	 * Return a tag based on an id, tag text or slug
	 *
	 * @return Tag The tag object
	 */
	public static function get_one( $tag )
	{
		$term = self::vocabulary()->get_term( $tag );
		if ( !$term instanceOf Term ) {
			return false;
		}
		return $term;
	}

	/**
	 * Return a tag based on a tag's text
	 *
	 * @return	A Tag object
	 */
	public static function get_by_text( $tag )
	{
		return self::get_one( $tag );
	}

	/**
	 * Return a tag based on a tag's text
	 *
	 * @return	A Tag object
	 */
	public static function get_by_slug( $tag )
	{
		return self::get_one( $tag );
	}

	/**
	 * Returns a Tag object based on a supplied ID
	 *
	 * @param Integer tag_id The ID of the tag to retrieve
	 * @return	A Tag object
	 */
	public static function get_by_id( $tag )
	{
		return self::get_one( (int) $tag );
	}

	/**
	 * Returns the tags vocabulary
	 *
	 * @return String The tags vocabulary
	 */
	public static function vocabulary()
	{
		return Vocabulary::get( self::$vocabulary );
	}

	/**
	 * Returns a list of terms from this vocabulary ordered by frequency of use on the post type specified
	 *
	 * @param int $limit If supplied, limits the results to the specified number
	 * @param mixed $post_type If a name or id of a post type is supplied, limits the results to the terms applying to that type
	 * @return Tags A Tags instance containing the terms, each having an additional property of "count" that tells how many times the term was used
	 */
	public static function get_by_frequency($limit = null, $post_type = null)
	{
		$query = '
			SELECT t.*, count(*) as `count`
			FROM {terms} t
			INNER JOIN {object_terms} tp ON t.id=tp.term_id
			INNER JOIN {posts} p ON tp.object_id=p.id
			INNER JOIN {object_types} ot ON tp.object_type_id=ot.id and ot.name="post"
			WHERE t.vocabulary_id = ?';

		$params = array(Tags::vocabulary()->id);

		if ( isset($post_type) ) {
			$query .= ' AND p.content_type = ?';
			$params[] = Post::type($post_type);
		}

		$query .= '
			GROUP BY t.id
			ORDER BY `count` DESC, term_display ASC';

		if ( is_int($limit) ) {
			$query .= ' LIMIT ' . $limit;
		}

		$tags = DB::get_results(
			$query,
			$params,
			'Term'
		);

		return $tags ? new Terms($tags) : false;
	}

	/**
	 * Returns the default type Tags uses
	 *
	 * @return String The default type name
	 */
	public static function object_type()
	{
		return self::$object_type;
	}

	/**
	 * Save the tags associated to this object into the terms and object_terms tables
	 *
	 * @param Array $tags strings. The tag names to associate to the object
	 * @param Integer $object_id. The id of the object being tagged
	 * @param String $object_type. The name of the type of the object being tagged. Defaults to post
	 *
	 * @return boolean. Whether the associating succeeded or not. true
	 */
	public static function save_associations( $terms, $object_id, $object_type = 'post' )
	{
		if ( ! $terms instanceof Terms ) {
			$terms = Terms::parse( $terms, 'Tag', Tags::vocabulary() );
		}
		return self::vocabulary()->set_object_terms( $object_type, $object_id, $terms );
	}

	/**
	 * Parse tag parameters from a URL string
	 *
	 * @param String $tags The URL parameter string
	 *
	 * @return Array. Associative array of included and excluded tags
	 */
	public static function parse_url_tags( $tags, $objectify = false )
	{
		$tags = explode( ' ', $tags );
		$exclude_tag = array();
		$include_tag = array();
		foreach ( $tags as $tag ) {
			if ( MultiByte::substr( $tag, 0, 1 ) == '-' ) {
				$tag = MultiByte::substr( $tag, 1 );
				$exclude_tag[] = $objectify ? Tags::get_one(Utils::slugify( $tag )) : Utils::slugify( $tag );
			}
			else {
				$include_tag[] = $objectify ? Tags::get_one(Utils::slugify( $tag )) : Utils::slugify( $tag );
			}
		}

		return compact('include_tag', 'exclude_tag');
	}
}
?>
