<?php
/**
  * Ahead WebSoft Technologies Pvt Ltd.
  * @copyright  Copyright 2006-2026 Ahead WebSoft Technologies Pvt Ltd.
  * @license    https://www.socialengine.com/policies
*/
class Core_Model_DbTable_Tags extends Engine_Db_Table
{
  protected $_rowClass = 'Core_Model_Tag';

  /**
   * Get the tag table
   *
   * @return Engine_Db_Table
   */
  public function getTagTable()
  {
    return $this;
  }

  /**
   * Get the tag map table
   *
   * @return Engine_Db_Table
   */
  public function getMapTable()
  {
    return Engine_Api::_()->getDbtable('TagMaps', 'core');
  }



  // Tags

  /**
   * Get an existing or create a new text tag
   *
   * @param string $text The tag text
   * @return Core_Model_Tag
   */
  public function getTag($text, $createNew)
  {
    $text = $this->formatTagText($text);
    if (empty($text)) {
      return;
    }

    $table = $this->getTagTable();
    $select = $table->select()
      ->where('text = ?', $text);

    $row = $table->fetchRow($select);

    if (null === $row && $createNew) {
      $row = $table->createRow();
      $row->text = $text;
      $row->save();
    }

    return $row;
  }

  public function getTagsByTagger($resource, Core_Model_Item_Abstract $tagger)
  {
    if ($resource instanceof Core_Model_Item_Abstract) {
      $resource_type = $resource->getType();
    } else {
      $resource_type = (string) $resource;
    }

    $mapTable = $this->getMapTable();
    $select = $mapTable->select()
      ->where('resource_type = ?', $resource_type)
      //->where('resource_id = ?', $resource->getIdentity())
      ->where('tagger_type = ?', $tagger->getType())
      ->where('tagger_id = ?', $tagger->getIdentity())
      ->where('tag_type = ?', 'core_tag')
      ->order('tag_id ASC');

    $identities = array();
    foreach ($mapTable->fetchAll($select) as $tagmap) {
      $identities[] = $tagmap->tag_id;
    }

    return Engine_Api::_()->getItemMulti('core_tag', $identities);
  }

  public function getTagsByText($text = null, $limit = 10)
  {
    $table = $this->getTagTable();
    $select = $table->select()
      ->order('text ASC')
      ->limit($limit);

    if ($text) {
      $select->where('text LIKE ?', '%' . $text . '%');
    }

    return $table->fetchAll($select);
  }

  /**
   * Called on text tags for formatting
   *
   * @param string $text
   * @return string
   */
  public function formatTagText($text)
  {
    // We can do formatting on tags later
    return trim($text);
  }



  // Tagging

  /**
   * Tag a resource
   *
   * @param Core_Model_Item_Abstract $resource The resource being tagged
   * @param Core_Model_Item_Abstract $tagger The resource doing the tagging
   * @param string|Core_Model_Item_Abstract $tag What is tagged in resource
   * @param array|null $extra
   * @return Engine_Db_Table_Row|null
   */
  public function addTagMap(Core_Model_Item_Abstract $resource, Core_Model_Item_Abstract $tagger, $tag, $extra = null)
  {
    $tag = $this->_getTag($tag, true);

    if (!$tag) {
      return false;
    }

    // Check if resource was already tagged with this
    if (null !== ($tagmap = $this->getTagMap($resource, $tag))) {
      return false; // return $tagmap;
      //throw new Core_Model_Exception('Resource was already tagged as this');
    }

    // Do the tagging
    $table = $this->getMapTable();
    $tagmap = $table->createRow();
    $tagmap->setFromArray(
      array(
        'resource_type' => $resource->getType(),
        'resource_id' => $resource->getIdentity(),
        'tagger_type' => $tagger->getType(),
        'tagger_id' => $tagger->getIdentity(),
        'tag_type' => $tag->getType(),
        'tag_id' => $tag->getIdentity(),
        'creation_date' => new Zend_Db_Expr('NOW()'),
        'extra' => $extra
      )
    );
    $tagmap->save();

    if (isset($tag->tag_count)) {
      $tag->tag_count = $tag->tag_count + 1;
    }
    $tag->modified_date = date('Y-m-d H:i:s');
    $tag->save();

    return $tagmap;
  }

  /**
   * Add multiple tags
   *
   * @param Core_Model_Item_Abstract $resource
   * @param Core_Model_Item_Abstract $tagger
   * @param array $tags
   * @return array
   */
  public function addTagMaps(Core_Model_Item_Abstract $resource, Core_Model_Item_Abstract $tagger, array $tags)
  {
    $tagmaps = array();
    foreach ($tags as $key => $value) {
      // ignore empty tags
      if (empty($value))
        continue;

      if (is_numeric($key)) {
        $tagmaps[] = $this->addTagMap($resource, $tagger, $value);
      } else {
        $tagmaps[] = $this->addTagMap($resource, $tagger, $key, $value);
      }
    }
    return $tagmaps;
  }

  /**
   * Get a tag map on resource and existing tag (for checking if already tagged)
   *
   * @param Core_Model_Item_Abstract $resource
   * @param string|Core_Model_Item_Abstract $tag
   * @return Engine_Db_Table|null
   */
  public function getTagMap(Core_Model_Item_Abstract $resource, $tag)
  {
    $tag = $this->_getTag($tag);

    $table = $this->getMapTable();
    $select = $table->select()
      ->where('resource_type = ?', $resource->getType())
      ->where('resource_id = ?', $resource->getIdentity())
      ->where('tag_type = ?', $tag->getType())
      ->where('tag_id = ?', $tag->getIdentity())
      ->limit(1)
    ;

    $tagmap = $table->fetchRow($select);
    return $tagmap;
  }

  /**
   * Get a tagmap by id that is part of resource
   *
   * @param Core_Model_Item_Abstract $resource
   * @param integer $id
   */
  public function getTagMapById(Core_Model_Item_Abstract $resource, $id)
  {
    $table = $this->getMapTable();
    $select = $table->select()
      ->where('resource_type = ?', $resource->getType())
      ->where('resource_id = ?', $resource->getIdentity())
      ->where('tagmap_id = ?', (int) $id)
      ->limit(1)
    ;

    $tagmap = $table->fetchRow($select);
    return $tagmap;
  }

  /**
   * Get all tags for a resource
   *
   * @param Core_Model_Item_Abstract $resource
   * @return Engine_Db_Table_Rowset
   */
  public function getTagMaps(Core_Model_Item_Abstract $resource)
  {
    return $this->getMapTable()->fetchAll($this->getTagMapSelect($resource));
  }

  /**
   * Get a select object for tags on a resource
   *
   * @param Core_Model_Item_Abstract $resource
   * @return Zend_Db_Table_Select
   */
  public function getTagMapSelect(Core_Model_Item_Abstract $resource)
  {
    $table = $this->getMapTable();
    $select = $table->select()
      ->where('resource_type = ?', $resource->getType())
      ->where('resource_id = ?', $resource->getIdentity())
      ->order('tag_id ASC')
    ;

    return $select;
  }

  public function setTagMaps(Core_Model_Item_Abstract $resource, $tagger, array $tags)
  {
    $existingTagMaps = $this->getTagMaps($resource);
    $added = array();
    $setTagIndex = array();
    $tagObjects = array();
    foreach ($tags as $tag) {
      if (empty($tag)) {
        continue;
      }

      $tagObject = $this->_getTag($tag, true);
      if (empty($tagObject)) {
        continue;
      }

      $tagObjects[] = $tagObject;
      $setTagIndex[$tagObject->getGuid()] = $tagObject;
    }

    // Check for new tags
    foreach ($tagObjects as $tag) {
      if (
        !$existingTagMaps->getRowMatching(
          array(
            'tag_type' => $tag->getType(),
            'tag_id' => $tag->getIdentity(),
          )
        )
      ) {
        $added[] = $this->addTagMap($resource, $tagger, $tag);
      }
    }

    // Check for removed tags
    foreach ($existingTagMaps as $tagmap) {
      $key = $tagmap->tag_type . '_' . $tagmap->tag_id;
      if (empty($setTagIndex[$key])) {
        try {
          $this->removeTagMap($resource, Engine_Api::_()->getItem($tagmap->tag_type, $tagmap->tag_id)->text);
        } catch (Exception $e) {
        }
      }
    }

    return $added;
  }

  public function removeTagMaps(Core_Model_Item_Abstract $resource, $tags)
  {
    foreach ($tags as $key => $tag) {
      $this->removeTagMap($resource, $tag);
    }
  }

  public function removeTagMap(Core_Model_Item_Abstract $resource, $tag)
  {
    $tag = $this->_getTag($tag);
    if (!$tag) {
      return;
    }
    $tagMap = $this->getTagMap($resource, $tag);
    if (!$tagMap) {
      return;
    }

    $tagMap->delete();
    if ($tag->tag_count <= 1) {
      return $tag->delete();
    }
    $tag->tag_count = $tag->tag_count - 1;
    $tag->modified_date = date('Y-m-d H:i:s');
    $tag->save();
  }

  // Resources

  public function getResourcesByTagSelect($tag, array $params = array())
  {
    if (is_string($tag)) {
      $tag = $this->_getTag($tag);
    }

    $table = $this->getMapTable();
    $select = $table->select()
      ->where('tag_type = ?', $tag->getType())
      ->where('tag_id = ?', $tag->getIdentity())
    ;

    if (!empty($params['resource_types'])) {
      $types = array();
      foreach ($params['resource_types'] as $type) {
        if (!Engine_Api::_()->hasItemType($type))
          continue;
        $types[] = $type;
      }
      $select->where('resource_type IN(\'' . join("', '", $types) . '\')')->order('creation_date DESC');
    }

    return $select;
  }


  public function getTopHashtags($limit)
  {
    $hashtagNames = array();
    $mapTableName = $this->getMapTable()->info('name');
    $select = $this->select()
      ->setIntegrityCheck(false)
      ->from($this->info('name'))
      //->join($mapTableName, $this->info('name') . '.tag_id=' . $mapTableName . '.tag_id', array('count(*) as tagmap_count'))
      ->order('tag_count desc')
      ->order('modified_date desc')
      ->group('tag_id')
      ->limit($limit);
    $hashtagMaps = $this->fetchAll($select);
    foreach ($hashtagMaps as $hashtag) {
      $hashtagNames[] = array('tagName' => '#' . $hashtag->text, 'tagCount' => $hashtag->tag_count);
    }
    return $hashtagNames;
  }
  // Utility

  /**
   * Gets an existing string tag or returns the passed item
   *
   * @param string|Core_Model_Item_Abstract $tag
   * @return Core_Model_Item_Abstract
   * @throws Core_Model_Exception If argument is not a string or an item
   */
  protected function _getTag($tag, $createNew = false)
  {
    if (is_string($tag)) {
      $tag = $this->getTag($tag, $createNew);
    }

    if (!($tag instanceof Core_Model_Item_Abstract) || !$tag->getIdentity()) {
      return null;
    }

    return $tag;
  }

  /**
   * Gets an tag id based on text
   *
   * @param string|Core_Model_Item_Abstract $tag
   * @return tag_id
   */
  public function getTagId($tag)
  {

    $tag = str_replace('#', '', $tag);

    return $this->select()
      ->from($this->info('name'), 'tag_id')
      ->where('text = ?', $tag)
      ->query()
      ->fetchColumn();
  }

  public function isExist($params = array())
  {
    $select = $this->select()
      ->from($this->info('name'), 'tag_id');
    if (isset($params['text']))
      $select = $select->where('text = ?', $params['text']);
    return $select->query()->fetchColumn();
  }

  public function tagCloudItem($params = array()) {

    $tableTagmap = Engine_Api::_()->getDbtable('tagMaps', 'core');
    $tableTagName = $tableTagmap->info('name');

    $tableMainTagName = $this->info('name');

    $select = $tableTagmap->select()
            ->from($tableTagName)
            ->setIntegrityCheck(false)
            ->joinLeft($tableMainTagName, $tableMainTagName . '.tag_id=' . $tableTagName . '.tag_id', array('text'))
            ->where('resource_type =?', $params['resource_type'])
            ->where('tag_type =?', 'core_tag')
            ->group($tableTagName . '.tag_id');

    if(isset( $params['resource_id']) && !empty($params['resource_id'])) {
      $select->where($tableTagName.'.resource_id =?', $params['resource_id']);
    }

    $select->columns(array('itemCount' => ("COUNT($tableTagName.tagmap_id)")));

    if (empty($params['fetchtype']))
      return Zend_Paginator::factory($select);
    else
      return $tableTagmap->fetchAll($select);
  }
}
