<?php

/**
 * Modal class representing an event or an event instance.
 *
 * @author       Time.ly Network, Inc.
 * @since        2.0
 * @instantiator new
 * @package      Ai1EC
 * @subpackage   Ai1EC.Model
 */

class Ai1ec_Event_Taxonomy extends Ai1ec_Base {

	/**
	 * @var string Name of categories taxonomy.
	 */
	const CATEGORIES    = 'events_categories';

	/**
	 * @var string Name of tags taxonomy.
	 */
	const TAGS          = 'events_tags';

	/**
	 * @var string Name of feeds taxonomy.
	 */
	const FEEDS         = 'events_feeds';

	/**
	 * @var int ID of related post object
	 */
	protected $_post_id = 0;

	/**
	 * Store event ID in local variable.
	 *
	 * @param int $post_id ID of post being managed.
	 *
	 * @return void
	 */
	public function __construct( Ai1ec_Registry_Object $registry, $post_id = 0 ) {
		parent::__construct( $registry );
		$this->_post_id = (int)$post_id;
	}

	/**
	 * Get ID of term. Optionally create it if it doesn't exist.
	 *
	 * @param string $term     Name of term to create.
	 * @param string $taxonomy Name of taxonomy to contain term within.
	 * @param bool   $is_id    Set to true if $term is ID.
	 * @param array  $attrs    Attributes to creatable entity.
	 *
	 * @return array|bool      Associative array with term_id
	 *                         and taxonomy keys or false on error
	 */
	public function initiate_term(
		$term,
		$taxonomy,
		$is_id       = false,
		array $attrs = array()
	) {
		// cast to int to have it working with term_exists
		$term = ( $is_id ) ? (int) $term : $term;
		$term_to_check = term_exists( $term, $taxonomy );
		$to_return = array(
			'taxonomy' => $taxonomy
		);
		// if term doesn't exist, create it.
		if ( 0 === $term_to_check || null === $term_to_check ) {
			$alias_to_use = apply_filters( 'ai1ec_ics_import_alias', $term );
			// the filter will either return null, the term_id to use or the original $term 
			// if the filter is not run. Thus in need to check that $term !== $alias_to_use
			if ( $alias_to_use && $alias_to_use !== $term ) {
				$to_return['term_id'] = (int) $alias_to_use;
				// check that the term matches the taxonomy
				$tax = $this->get_taxonomy_for_term_id( term_exists( (int) $alias_to_use ) );
				$to_return['taxonomy'] = $tax->taxonomy;
			} else {
				$term_to_check = wp_insert_term( $term, $taxonomy, $attrs );
				if ( is_wp_error( $term_to_check ) ) {
					return false;
				}
				$term_to_check = (object)$term_to_check;
				$to_return['term_id'] = (int)$term_to_check->term_id;
			}
		} else {
			$term_id = is_array( $term_to_check )
				? $term_to_check['term_id']
				: $term_to_check;
			$to_return['term_id'] = (int)$term_id;
			// when importing categories, use the mapping of the current site
			// so place the term in the current taxonomy
			if ( self::CATEGORIES === $taxonomy ) {
				// check that the term matches the taxonomy
				$tax = $this->get_taxonomy_for_term_id( $term_id );
				$to_return['taxonomy'] = $tax->taxonomy;
			}

		}
		return $to_return;
	}

	/**
	 * Wrapper for terms setting to post.
	 *
	 * @param array  $terms    List of terms to set.
	 * @param string $taxonomy Name of taxonomy to set terms to.
	 * @param bool   $append   When true post may have multiple same instances.
	 *
	 * @return bool Success.
	 */
	public function set_terms( array $terms, $taxonomy, $append = false ) {
		$result = wp_set_post_terms(
			$this->_post_id,
			$terms,
			$taxonomy,
			$append
		);
		if ( is_wp_error( $result ) ) {
			return false;
		}
		return $result;
	}

	/**
	 * Update event categories.
	 *
	 * @param array $categories List of category IDs.
	 *
	 * @return bool Success.
	 */
	public function set_categories( array $categories ) {
		return $this->set_terms( $categories, self::CATEGORIES );
	}

	/**
	 * Update event tags.
	 *
	 * @param array $tags List of tag IDs.
	 *
	 * @return bool Success.
	 */
	public function set_tags( array $tags ) {
		return $this->set_terms( $tags, self::TAGS );
	}

	/**
	 * Update event feed description.
	 *
	 * @param object $feed Feed object.
	 *
	 * @return bool Success.
	 */
	public function set_feed( $feed ) {
		$feed_name = $feed->feed_url;
		// If the feed is not from an imported file, parse the url.
		if ( ! isset( $feed->feed_imported_file ) ) {
			$url_components = parse_url( $feed->feed_url );
			$feed_name      = $url_components['host'];
		}
		$term = $this->initiate_term(
			$feed_name,
			self::FEEDS,
			false,
			array(
				'description' => $feed->feed_url,
			)
		);
		if ( false === $term ) {
			return false;
		}
		$term_id = $term['term_id'];
		return $this->set_terms( array( $term_id ), self::FEEDS );
	}

	/**
	 * Get the taxonomy name from term id
	 *
	 * @param int $term
	 *
	 * @return stdClass The taxonomy nane
	 */
	public function get_taxonomy_for_term_id( $term_id ) {
		$db = $this->_registry->get( 'dbi.dbi' );
		return $db->get_row(
			$db->prepare(
				'SELECT terms_taxonomy.taxonomy FROM ' .  $db->get_table_name( 'terms' ) .
				' AS terms INNER JOIN ' .
				$db->get_table_name( 'term_taxonomy' ) .
				' AS terms_taxonomy USING(term_id) '.
				'WHERE terms.term_id = %d LIMIT 1', $term_id )
		);
	}
}