<?php

  /**
   * NotebookPages class
   *
   * @package activeCollab.modules.notebooks
   * @subpackage models
   */
  class NotebookPages extends BaseNotebookPages {
  	
    /**
     * Find notebook pages by list of ID-s
     *
     * @param array $ids
     * @param integer $min_state
     * @return DBResult
     */
    static function findByIds($ids, $min_state = STATE_VISIBLE) {
      return NotebookPages::find(array(
        'conditions' => array('id IN (?) AND state >= ?', $ids, $min_state),
        'order' => 'created_on DESC',
      ));
    } // findByIds

    /**
     * Load notebook pages by $notebook
     *
     * @param Notebook $notebook
     * @param integer $min_state
     * @return array
     */
    static function findByNotebook(Notebook $notebook, $min_state = STATE_VISIBLE) {
      return NotebookPages::find(array(
        'conditions' =>  array('parent_type = ? AND parent_id = ? AND state >= ?', 'Notebook', $notebook->getId(), $min_state),
        'order' => 'ISNULL(position) ASC, position'
      ));
    } // findByNotebook
    
    /**
     * Find archived notebook pages by given notebook
     *
     * @param Notebook $notebook
     * @return array
     */
    static function findArchivedByNotebook(Notebook $notebook) {
      return NotebookPages::find(array(
        'conditions' =>  array('parent_type = ? AND parent_id = ? AND state = ?', 'Notebook', $notebook->getId(), STATE_ARCHIVED),
        'order' => 'ISNULL(position) ASC, position'
      ));
    } // findArchivedByNotebook

    /**
     * Return subpages
     *
     * @param NotebookPage $notebook_page
     * @param integer $min_state
     * @return array
     */
    static function findSubpages(NotebookPage $notebook_page, $min_state = STATE_VISIBLE) {
      return NotebookPages::find(array(
        'conditions' => array('parent_type = ? AND parent_id = ? AND state >= ?', 'NotebookPage', $notebook_page->getId(), $min_state),
        'order' => 'ISNULL(position) ASC, position'
      ));
    } // findSubpages
    
    /**
     * Find children tree - for notebooks listing
     * 
     * @param mixed $parent - Notebook, or NotebookPage
     * @param integer $min_state
     * @param boolean $excerpt
     * @param integer $level
     */
    static function findForObjectsList($parent, IUser $user, $min_state = STATE_ARCHIVED, $excerpt = false, $level = -1) {
    	if ($parent instanceof Notebook) {
    		$objects = NotebookPages::findByNotebook($parent, $min_state);
    		$notebook_id = $parent->getId();	
    	} else if ($parent instanceof NotebookPage) {
    		$objects = NotebookPages::findSubpages($parent, $min_state);
    		$notebook_id = $parent->getNotebook()->getId();
    	} else {
    		return null;
    	} // if
    	
    	$level ++;
    	
    	if (is_foreachable($objects)) {
    		$return = array();
    		foreach ($objects as $object) {
    			if ($excerpt) {
						$return[] = array(
							'id' => $object->getId(),
							'name' => $object->getName(),
							'parent_id' => $object->getParentId(),
							'notebook_id' => $notebook_id,
							'revision_num' => $object->getVersion(),
							'depth' => $level,
							'is_archived' => $object->getState() == STATE_ARCHIVED ? 1 : 0,
							'permalink'	=> $object->getViewUrl(), 
						  'is_favorite' => Favorites::isFavorite($object, $user), 
						);
    			} else {
	    			$object->depth_level = $level;
	    			$return[] = $object;
    			} // if
    			$children = NotebookPages::findForObjectsList($object, $user, $min_state, $excerpt, $level);
    			if (is_foreachable($children)) {
    				$return = array_merge($return, $children);
    			} // if
    		} // foreach

				return $return;    		
    	} // if
    	
    	return null;
    } // findSubpagesRecursively
    
    /**
     * Return ID-s of all subpages, regardless of stricture by notebook
     * 
     * This function is used when we need to fetch all pages while ignoring 
     * structure (search index rebuild etc)
     * 
     * $notebook can be instance of Notebook class or notebook ID
     * 
     * @param Notebook $notebook
     * @return array
     */
    static function getAllIdsByNotebook($notebook) {
      $result = array();
      
      $notebook_id = $notebook instanceof Notebook ? $notebook->getId() : $notebook;
      
      $page_ids = DB::executeFirstColumn('SELECT id FROM ' . TABLE_PREFIX . "notebook_pages WHERE parent_type = 'Notebook' AND parent_id = ?", $notebook_id);
      if($page_ids) {
        foreach($page_ids as $page_id) {
          $result[] = (integer) $page_id;
          
          $subpage_ids = self::getAllSubpageIds($page_id);
          if(is_foreachable($subpage_ids)) {
            $result = array_merge($result, $subpage_ids);
          } // if
        } // foreach
      } // if
      
      return count($result) ? $result : null;
    } // getAllIdsByNotebook
    
    /**
     * Return all subpage ID-s based on page ID
     * 
     * @param integer $page_id
     * @return array
     */
    static public function getAllSubpageIds($page_id) {
      $result = array();
      
      $subpage_ids = DB::executeFirstColumn('SELECT id FROM ' . TABLE_PREFIX . "notebook_pages WHERE parent_type = 'NotebookPage' AND parent_id = ?", $page_id);
      if($subpage_ids) {
        foreach($subpage_ids as $subpage_id) {
          $result[] = (integer) $subpage_id;
          
          $sub_subpage_ids = self::getAllSubpageIds($subpage_id);
          if(is_foreachable($sub_subpage_ids)) {
            $result = array_merge($result, $sub_subpage_ids);
          } // if
        } // foreach
      } // if
      
      return $result;
    } // getAllSubpageIds
    
    /**
     * Clone pages from one notebook to another
     * 
     * @param Notebook $from
     * @param Notebook $to
     */
    static function cloneToNotebook(Notebook $from, Notebook $to) {
      try {
        $notebook_pages_table = TABLE_PREFIX . 'notebook_pages';
        
        DB::beginWork('Cloning first level pages @ ' . __CLASS__);
        
        $pages = DB::execute("SELECT id, name, body, state, is_locked, created_on, created_by_id, created_by_name, created_by_email, updated_on, updated_by_id, updated_by_name, updated_by_email, position, version FROM $notebook_pages_table WHERE parent_type = ? AND parent_id = ? AND state >= ?", 'Notebook', $from->getId(), STATE_ARCHIVED);
        if($pages) {
          $parent_id = DB::escape($to->getId());
          
          foreach($pages as $page) {
            DB::execute("INSERT INTO $notebook_pages_table (parent_type, parent_id, name, body, state, is_locked, created_on, created_by_id, created_by_name, created_by_email, updated_on, updated_by_id, updated_by_name, updated_by_email, position, version) VALUES ('Notebook', $parent_id, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
              $page['name'], $page['body'], $page['state'], $page['is_locked'], $page['created_on'], $page['created_by_id'], $page['created_by_name'], $page['created_by_email'], $page['updated_on'], $page['updated_by_id'], $page['updated_by_name'], $page['updated_by_email'], $page['position'], $page['version'] 
            );
            
            self::clonePages($page['id'], DB::lastInsertId());
          } // foreach
        } // if
        
        DB::commit('Notebook first level pages @ ' . __CLASS__);
      } catch(Exception $e) {
        DB::rollback('Failed to clone first level pages @ ' . __CLASS__);
        throw $e;
      } // try
    } // cloneToNotebook
    
    /**
     * Clone notebook pages from one page to another page
     * 
     * @param integer $from_page_id
     * @param integer $to_page_id
     */
    static private function clonePages($from_page_id, $to_page_id) {
      try {
        $notebook_pages_table = TABLE_PREFIX . 'notebook_pages';
        
        DB::beginWork('Cloning subpages @ ' . __CLASS__);
        
        $pages = DB::execute("SELECT id, name, body, state, is_locked, created_on, created_by_id, created_by_name, created_by_email, updated_on, updated_by_id, updated_by_name, updated_by_email, position, version FROM $notebook_pages_table WHERE parent_type = ? AND parent_id = ? AND state >= ?", 'NotebookPage', $from_page_id, STATE_ARCHIVED);
        if($pages) {
          $parent_id = DB::escape($to_page_id);
          
          foreach($pages as $page) {
            DB::execute("INSERT INTO $notebook_pages_table (parent_type, parent_id, name, body, state, is_locked, created_on, created_by_id, created_by_name, created_by_email, updated_on, updated_by_id, updated_by_name, updated_by_email, position, version) VALUES ('NotebookPage', $parent_id, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
              $page['name'], $page['body'], $page['state'], $page['is_locked'], $page['created_on'], $page['created_by_id'], $page['created_by_name'], $page['created_by_email'], $page['updated_on'], $page['updated_by_id'], $page['updated_by_name'], $page['updated_by_email'], $page['position'], $page['version'] 
            );
            
            self::clonePages($page['id'], DB::lastInsertId());
          } // foreach
        } // if
        
        DB::commit('Subpages cloned @ ' . __CLASS__);
      } catch(Exception $e) {
        DB::rollback('Failed to clone subpages @ ' . __CLASS__);
        throw $e;
      } // try
    } // cloneNotebookPages

    // ---------------------------------------------------
    //  Trash
    // ---------------------------------------------------
      
    /**
     * Get trashed map
     * 
     * @param User $user
     * @return array
     */
    static function getTrashedMap($user) {
      return array(
        'notebookpage' => DB::executeFirstColumn('SELECT id FROM ' . TABLE_PREFIX . 'notebook_pages WHERE state = ? ORDER BY created_on DESC', STATE_TRASHED)
      );
    } // getTrashedMap
    
    /**
     * Find trashed notebook pages
     * 
     * @param User $user
     * @param array $map
     * @return array
     */
    static function findTrashed(User $user, &$map) {
    	$query = Trash::getParentQuery($map);

    	if ($query) {
	    	$trashed_notebook_pages = DB::execute('SELECT id, name FROM ' . TABLE_PREFIX . 'notebook_pages WHERE state = ? AND ' . $query . ' ORDER BY created_on DESC', STATE_TRASHED);
    	} else {
	    	$trashed_notebook_pages = DB::execute('SELECT id, name FROM ' . TABLE_PREFIX . 'notebook_pages WHERE state = ? ORDER BY created_on DESC', STATE_TRASHED);
    	} // if

      if($trashed_notebook_pages) {
        $items = array();

        foreach ($trashed_notebook_pages as $trashed_notebook_page) {
          $items[] = array(
            'id' => $trashed_notebook_page['id'],
            'name' => $trashed_notebook_page['name'],
            'type' => 'NotebookPage',
          );
        } // foreach

        return $items;
      } else {
        return null;
      } // if
    } // findTrashed
    
    /**
     * Delete trashed projects
     * 
     * @param User $user
     */
    static function deleteTrashed() {
      $notebook_pages = NotebookPages::find(array(
        'conditions' => array('state = ?', STATE_TRASHED)
      ));

      if ($notebook_pages) {
        try {
          DB::beginWork('Deleting trashed notebook pages @ ' . __CLASS__);

          foreach ($notebook_pages as $notebook_page) {
            $notebook_page->state()->delete();
          } // foreach

          DB::commit('Trashed notebook pages have been deleted @ ' . __CLASS__);
        } catch(Exception $e) {
          DB::rollback('Failed to delete trashed notebook pages @ ' . __CLASS__);
          throw $e;
        } // try
      } // if
    } // deleteTrashed

  }