<?php

  /**
   * Foundation class that every search index extends
   * 
   * @package angie.frameworks.search
   * @subpackage models
   */
  abstract class SearchIndex {
    
    // Index filed types
    const FIELD_NUMERIC = 'numeric';
    const FIELD_DATE = 'date';
    const FIELD_DATETIME = 'datetime';
    const FIELD_STRING = 'string';
    const FIELD_TEXT = 'text';
    
    /**
     * Provider used to store and query the data
     *
     * @var SearchProvider
     */
    protected $provider;
    
    /**
     * Construct search index
     * 
     * @param SearchProvider $provider
     */
    function __construct(SearchProvider &$provider) {
      $this->provider = $provider;
    } // __construct
    
    /**
     * Return short name of this index
     * 
     * @return string
     */
    abstract function getShortName();
  
    /**
     * Return index name
     * 
     * @return string
     */
    abstract function getName();
    
    /**
     * Return index fields
     */
    abstract function getFields();
    
    /**
     * Return array of available filters
     * 
     * Filters are indexed by field and can be either array of values or array 
     * of arrays of values
     * 
     * @return array
     */
    function getFilters() {
      return array();
    } // getFilters
    
    /**
     * Return object context domains that this index searchs through
     * 
     * @return string
     */
    function getObjectContextDomains() {
      return null;
    } // getObjectContextDomains
    
    /**
     * Return context filter for a given user
     * 
     * @param IUser $user
     * @return string
     */
    function getUserFilter(IUser $user) {
      return null;
    } // getUserFilter
    
    /**
     * Return true if this index is considered advanced search
     * 
     * @return boolean
     */
    function isAdvanced() {
      return true;
    } // isAdvanced
    
    /**
     * Return true if this search index is initialized
     * 
     * @param boolean $use_cache
     * @return boolean
     */
    function isInitialized($use_cache = true) {
      return $this->provider->isInitialized($this, $use_cache);
    } // isInitialized
    
    /**
     * Initialize this search index
     */
    function initialize() {
      return $this->provider->initialize($this);
    } // initialize
    
    /**
     * Tear down index
     */
    function tearDown() {
      return $this->provider->tearDown($this);
    } // tearDown
    
    /**
     * Return total number of records in this index
     * 
     * @return integer
     */
    function countRecords() {
      return $this->provider->countRecords($this);
    } // countRecords
    
    /**
     * Return file size of this index
     * 
     * @return integer
     */
    function calculateSize() {
      return $this->provider->calculateSize($this);
    } // calculateSize
    
    /**
     * Query index for the given terms
     * 
     * @param string $string
     * @param array $constraints
     * @return mixed
     */
    function query($string, $constraints = null) {
      return $this->provider->query($this->getShortName(), $string, $constraints);
    } // query
    
    /**
     * Return number of items in the interface
     * 
     * @param integer $constraints
     * @return integer
     */
    function count($constraints = null) {
      return $this->provider->count($this->getShortName(), $constraints);
    } // count
    
    /**
     * Add or update item in the index
     * 
     * $item can implement ISearchItem interface or be an array of fields that 
     * need to be added to the interface
     * 
     * @param mixed $item
     */
    function set($item) {
      if($item instanceof ISearchItem) {
        $data = $item->getSearchFields();
      } elseif(is_int($item)) {
        $data = $item;
      } else {
        throw new InvalidParamError('item', $item, "'$item' is not valid searchable object");
      } // if
      
      $this->provider->set($this->getShortName(), $data);
    } // set
    
    /**
     * Remove an item from the interface
     * 
     * $item can be an instance of ISearchItem interface, or item ID that needs 
     * to be removed from the index
     * 
     * @param unknown_type $item
     */
    function remove($item) {
      if($item instanceof ISearchItem) {
        $item_id = $item->getId();
      } elseif(is_int($item)) {
        $item_id = $item;
      } else {
        throw new InvalidParamError('item', $item, "'$item' is not valid search engine item ID");
      } // if
      
      $this->provider->remove($this, $item_id);
    } // remove
    
    /**
     * Drop all items from the interface
     */
    function clear() {
      $this->provider->clear($this->getShortName());
    } // clear
    
    // ---------------------------------------------------
    //  Rebuild
    // ---------------------------------------------------
    
    /**
     * Return steps to rebuild this search index
     */
    function getRebuildSteps() {
      return array(
        array(
          'text' => lang('Initialize Index'), 
        	'url' => $this->getReinitUrl(),
        ),
      );
    } // getRebuildSteps
    
    // ---------------------------------------------------
    //  URL-s
    // ---------------------------------------------------
    
    /**
     * Return rebuild index URL
     * 
     * @return string
     */
    function getRebuildUrl() {
      return Router::assemble('search_index_admin_rebuild', array('search_index_name' => $this->getShortName()));
    } // getRebuildUrl
    
    /**
     * Return check index URL
     * 
     * @return string
     */
    function getReinitUrl() {
      return Router::assemble('search_index_admin_reinit', array('search_index_name' => $this->getShortName()));
    } // getReinitUrl
    
  }