<?php
/*
 * This file is part of the easy-CMS project.
 * easy-CMS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * easy-CMS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with easy-CMS; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
 
/**
 * @package    Core
 * @subpackage ContainersLists
 */

include_once('classes/core/DBAccessorObject.class.php');
include_once('classes/core/DBManipulator.class.php');
include_once('classes/core/ACL/ACL.class.php');
include_once('classes/core/ACL/ACLManager.class.php');
include_once('classes/core/containersLists/ContainersList.class.php');
include_once('classes/core/containers/ContainersManager.class.php');
include_once('classes/core/containers/Container.class.php');

/**
 * ContainersListsManager Class
 *
 * Manages ContainersList objects
 *
 * @access     public
 * @author	   Cedric Francoys <cedric.francoys@easy-cms.org>
 * @version    Container.class,v 0.1
 * @package	   Core
 * @subpackage ContainersLists
 */
class ContainersListsManager extends DBAccessorObject {
	/**
	 * @var object
	 */
  var $aclManager;
	
	/**
	 * @var object
	 */
  var $containersManager;
	
	/**
	 * @var array
	 */
  var $containersListsTable;
	
	/**
	 * Constructor
	 *
	 * @param object $dbManipulator
	 * @param object $aclManager
	 * @param object $containersManager
	 */
	function ContainersListsManager(&$dbManipulator, &$aclManager, &$containersManager) {
    $this->debug('ContainersListsManager::ContainersListsManager, status : function invoked', 10, DBG_OPEN);
		parent::DBAccessorObject($dbManipulator);
		$this->aclManager = &$aclManager;		
		$this->containersManager = &$containersManager;
		$this->containersListsTable = array();
    $this->debug('ContainersListsManager::ContainersListsManager, status : function completed', 10, DBG_CLOSE);
	}
	
	/**
	 * Gets ACLManager
	 *
	 * @return object
	 */
	function &getAclManager() {
		return $this->aclManager;
	}
	
	/**
	 * Gets ContainersManager
	 *
	 * @return object
	 */
	function &getContainersManager() {
		return $this->containersManager;
	}
	
	/**
	 * Loads ContainersList
	 *
	 * @param  boolean $loadContainers
	 * @param  boolean $loadDeleted
	 * @param  boolean $loadAcl
	 * @return boolean
	 */
	function loadContainersList($id, $loadContainers=true, $loadDeleted=false, $loadAcl=true) {
    $this->debug('ContainersListsManager::loadContainersList, status : function invoked', 10, DBG_OPEN);
    $result = false;
		$containersListsIdList = (array)$id;
		$csv = implode(',', $containersListsIdList);
		$db = &$this->getDBManipulator();
		$res = $db->getRecord(CONTAINERS_LISTS_TABLE, -1, '`id` in ('.$csv.')');
		
		$containersManager = &$this->getContainersManager();
		$aclManager = &$this->getAclManager();
		
		if (!$res || !$db->getNumRows()) {
			$this->debug('ContainersListsManager::loadContainersList, error : unable to load ContainersList(id='.$csv.')', 3);

		}
		else {
  		while ($record = $db->fetchArray($res)) {
  			$clId          = $record['id'];
  			$clSortingType = $record['sorting_type'];
  			$clSortField   = $record['sort_field'];
  			$clSortOrder   = $record['sort_order'];
  			$clCountShown  = $record['count_shown'];
  			$clCloneId     = $record['clone_id'];
  			$clAclId       = $record['acl_id'];
  			$clDeleted     = $record['deleted'];
  			$clPublished   = $record['published'];

  			if (!$loadDeleted && $clDeleted) {
  				$this->debug('ContainersListsManager::loadContainersList, warning : ContainersList(id='.$clId.') is deleted', 4);
  				continue;
  			}

  			$containersList = &new ContainersList($clId, $clSortingType, $clSortField, $clSortOrder, $clCountShown, $clCloneId, $clAclId, $clDeleted);
  			$containersList->setContainersListPublished($clPublished);

  			if ($loadContainers) {
  				$loadId = $clCloneId? $clCloneId : $clId;
  				if ($table = &$this->getContainersTable($loadId)) {
  					$containersList->setContainersTable($table);
  				}
  			}

  			if ($loadAcl) {
  				if ($acl = &$this->getContainersListAcl($clAclId)) {
  					$containersList->setContainersListAcl($acl);
  				}
  			}

  			$this->addContainersList($containersList);
        $result = true;
      }
		}
    $this->debug('ContainersListsManager::loadContainersList, status : function completed', 10, DBG_CLOSE);
		return $result;
  }
	
	/**
	 * Loads ContainersList Containers
	 *
	 * @param  integer $containersListId
	 * @return boolean
	 */
	function loadContainers($containersListId){
    $this->debug('ContainersListsManager::loadContainers, status : function invoked', 10, DBG_OPEN);
		$loaded = false;
		$db = &$this->getDBManipulator();
		$res = $db->getRecord(CONTAINERS_LISTS_CONTAINERS_TABLE, $containersListId, '', 'containers_list_id', '`index`');
		if($res && $db->getNumRows()){
			$containersIdList = array();
			while($record = $db->fetchArray($res)){
				$containersIdList[] = (int)$record['container_id'];
			}
			if($this->containersManager->loadContainer($containersIdList)){
				$containersTable = array();
				foreach($containersIdList as $containerId){
					$containersTable[] = &$this->containersManager->getContainer($containerId);
				}
				$this->containersListsTable[$containersListId]->setContainersTable($containersTable);
				$loaded = true;
			}
		}
    $this->debug('ContainersListsManager::loadContainers, status : function completed', 10, DBG_CLOSE);
		return $loaded;
	}
	
	/**
	 * Gets Containers Table
	 *
	 * @param  integer $clId ContainersList Id
	 * @return array
	 */
	function &getContainersTable($containersListId) {
    $this->debug('ContainersListsManager::getContainersTable, status : function invoked', 10, DBG_OPEN);
		$containersTable = array();
		$db = &$this->getDBManipulator();
		if($res = $db->getRecord(CONTAINERS_LISTS_CONTAINERS_TABLE, $containersListId, '', 'containers_list_id', '`index`')) {
			$containerIdList = array();
			while ($fields = $db->fetchArray($res)) {
      	$index = $fields['index'];
				$containerIdList[$index] = $fields['container_id'];
			}
			if(count($containerIdList) > 0){
				ksort($containerIdList);
				if ($this->containersManager->loadContainer($containerIdList)) {
					foreach ($containerIdList as $containerId) {
						if ($container = &$this->containersManager->getContainer($containerId)) {
							$container->setContainersListId($containersListId);
							$containersTable[] = &$container;
							unset($container);
						}
					}
				}
			}
		}
    $this->debug('ContainersListsManager::getContainersTable, status : function completed', 10, DBG_CLOSE);
		return $containersTable;
	}
	
	/**
	 * Gets ContainersList ACL
	 *
	 * @param  integer $aclId ACL Id
	 * @return object
	 */
	function &getContainersListAcl($aclId) {
    $this->debug('ContainersListsManager::getContainersListAcl, status : function invoked', 10, DBG_OPEN);
		$acl = &$this->aclManager->getACL($aclId);
    $this->debug('ContainersListsManager::getContainersListAcl, status : function completed', 10, DBG_CLOSE);
		return $acl;
	}
	
	/**
	 * Stores ContainersList
	 *
	 * @param  integer $id
	 * @return boolean
	 */
	function storeContainersList($id) {
    $this->debug('ContainersListsManager::storeContainersList, status : function invoked', 10, DBG_OPEN);
    $result = -1;
		$containersList = &$this->getContainersList($id);
		
		$fieldsArray = array();
		$fieldsArray['sorting_type'] = $containersList->getContainersListSortingType();
		$fieldsArray['sort_field']   = $containersList->getContainersListSortField();
		$fieldsArray['sort_order']   = $containersList->getContainersListSortOrder();
		$fieldsArray['count_shown']  = $containersList->getContainersListCountShown();
		$fieldsArray['clone_id']     = $containersList->getContainersListCloneId();
		$fieldsArray['acl_id']       = $containersList->getContainersListAclId();
		$fieldsArray['deleted']      = $containersList->getContainersListDeleted();
		$fieldsArray['published']    = $containersList->getContainersListPublished();


    // check if the clone_id matches an existing containersList
    if(!is_numeric($fieldsArray['clone_id'])) {
      $fieldsArray['clone_id'] = 0;
    }
    else {
      if($fieldsArray['clone_id'] <= 0 || !$this->containersListExists($fieldsArray['clone_id'])) {
        $fieldsArray['clone_id'] = 0;
      }
    }

    if(!is_numeric($fieldsArray['count_shown'])) {
      $fieldsArray['count_shown'] = 0;
    }

		// new containersList : id 0 is not allowed in the DB
		if($id == 0){
			if( ($this->dbManipulator->addRecord(CONTAINERS_LISTS_TABLE, $fieldsArray)) <= 0){
				$this->debug("ContainersListsManager::storeContainersList, error : unable to create new containersList.", 1);
			}
			else {
  			$this->debug("ContainersListsManager::storeContainersList, new containersList created successfully.", 10);
  			$containersListId = $this->dbManipulator->getLastId();
  			$containersList->setContainersListId($containersListId);
  			// register the containersList with its new id
  			$this->setContainersList($containersList);
  			// free the temporary containersList entry (0)
  			unset($this->containersListsTable[0]);
  			// return a value > 0, the id of the new containersList
  			$result = $containersListId;
			}
		}
		else {
			if(!$this->dbManipulator->setRecord(CONTAINERS_LISTS_TABLE, $id, $fieldsArray)) {
				$this->debug('ContainersListsManager::storeContainersList, error : unable to update containersList #'.$id, 1);
			}
			else {

        $cloneId  = $fieldsArray['clone_id'];
     		$loadId   = $id;

    		if($cloneId > 0) {
    			$loadId = $cloneId;
    		}

    		$result_array = $this->dbManipulator->getRecord(CONTAINERS_LISTS_CONTAINERS_TABLE, $loadId, '', 'containers_list_id', '`index`');

    		if ($result_array === false) {
          $this->debug('ContainersListsManager::storeContainer, error : unable to get containers list for containersList #'.$id.' (load skipped)', 2);
    		}
    		else {

    			$containersTableBool = array();
    			while ($row = $this->dbManipulator->fetchArray($result_array)) {
    				$containerId = $row['container_id'];
    				$containersTableBool[$containerId] = true;
    			}

      		$containersTable = &$containersList->getContainersTable();
      		$numContainers = count($containersTable);

      		for($i = 0; $i < $numContainers; ++$i) {
            $containerId = $containersTable[$i]->getContainerId();
            $fieldsArray = array();
            $fieldsArray['index'] = $i+1;

            if($containersTableBool[$containerId]) {
              if (($result_array = &$this->dbManipulator->setRecord(CONTAINERS_LISTS_CONTAINERS_TABLE, $loadId, $fieldsArray, "`container_id` = '$containerId'", "containers_list_id")) < 0 ){
                $this->debug("ContainersManager::storeContainersList, error : unable to update index of container ($containerId) in containersList ($loadId).", 2);
                $result = -1;
      				}
            }
            else {
              $fieldsArray["container_id"] = $containerId;
      			 	$fieldsArray["containers_list_id"] = $loadId;

      			 	if (($result_array = &$this->dbManipulator->addRecord(CONTAINERS_LISTS_CONTAINERS_TABLE, $fieldsArray)) < 0 ) {
      					$this->debug("ContainersManager::storeContainersList, error : unable to add container ($containerId) to containersList ($id).", 2);
                $result = -1;
              }
            }
      		}
    		}
			}
		}
		
    $this->debug('ContainersListsManager::storeContainersList, status : function completed', 10, DBG_CLOSE);
		return $result;
	}

	/**
	 * Sets ContainersList For Deletion
	 *
	 * @param  integer $id ContainersList Id
	 * @return boolean
	 */
  function removeContainersList($id) {
    $this->debug('ContainersListsManager::removeContainersList, status : function invoked', 10, DBG_OPEN);
    $result = true;
		if (!($cl = &$this->getContainersList($id))) {
			$result = false;
		}
		$cl->setContainersListDeleted(1);
		if (!$this->storeContainersList($id)) {
			$result = false;
		}
    $this->debug('ContainersListsManager::removeContainersList, status : function completed', 10, DBG_CLOSE);
		return $result;
  }
    
	/**
	 * Adds Container To ContainersList
	 *
	 * @param  integer $clId ContainersList Id
	 * @param  integer $ctId Container Id
	 * @return boolean
	 */
	function addContainer($containersListId, $containerId) {
    $this->debug('ContainersListsManager::addContainer, status : function invoked ('.$containersListId.', '.$containerId.')', 10, DBG_OPEN);
    $result = true;
		$dbManipulator = &$this->getDBManipulator();

		if (!($containersList = &$this->getContainersList($containersListId))) {
			$this->debug('ContainersListsManager::addContainer, error :  unable to add Container(id='.$containerId.') into ContainersList(id='.$containersListId.')', 3);
			$result = false;
		}
		else {
      $cloneId  = $containersList->getContainersListCloneId();
   		$loadId   = $containersListId;

  		if($cloneId > 0) {
  			$loadId = $cloneId;
  		}

  		$record = array();
  		$record['containers_list_id'] = $loadId;
  		$record['container_id']       = $containerId;

  		$result_array = $dbManipulator->sendQuery("SELECT max(`index`) as `index` FROM `".CONTAINERS_LISTS_CONTAINERS_TABLE."` WHERE `containers_list_id` = $loadId;");

  		if(!($row = $dbManipulator->fetchArray($result_array))){
  			$result = false;
  		}
  		else {
    		$record['index'] = $row['index']+1;

    		$res = $dbManipulator->addRecord(CONTAINERS_LISTS_CONTAINERS_TABLE, $record);
    		if (!$res || !$dbManipulator->getAffectedRows()) {
    			$this->debug('ContainersListsManager::addContainer, error : unable to add Container(id='.$containerId.') into ContainersList(id='.$loadId.')', 3);
    			$result = false;
    		}
  		}
    }
		
    $this->debug('ContainersListsManager::addContainer, status : function completed', 10, DBG_CLOSE);
		return $result;
	}

	/**
	 * Removes Container From ContainersList
	 *
	 * @param  integer $containersListId
	 * @param  integer $containerId
	 * @return boolean
	 */
  function removeContainer($clId, $ctId) {
    $this->debug('ContainersListsManager::removeContainer, status : function invoked ('.$clId.', '.$ctId.')', 10, DBG_OPEN);
    $result = true;
		$db = &$this->getDBManipulator();
		$res = $db->delRecord(CONTAINERS_LISTS_CONTAINERS_TABLE, $clId, '`container_id`='.$db->quoteSmart($ctId), 'containers_list_id');
		if (!$res || !$db->getAffectedRows()) {
			$this->debug('ContainersListsManager::removeContainer, error : unable to remove Container(id='.$ctId.') from ContainersList(id='.$clId.')', 3);
			$result = false;
		}
    $this->debug('ContainersListsManager::removeContainer, status : function completed', 10, DBG_CLOSE);
		return $result;
  }

	/**
	 * @param  integer $id containers list id
	 * @return boolean
	 */
	function checkContainersList($id) {
		return isset($this->containersListsTable[$id]);
	}

	function containersListExists($id) {
		return $this->dbManipulator->containersListExists($id);
	}
	
	function &getContainersList($id, $loadContent=true, $loadDeleted=false, $reload=false) {
    $this->debug('ContainersListsManager::getContainersList, status : function invoked', 10, DBG_OPEN);
    $result = null;
		if($reload || !$this->checkContainersList($id)){
			if(!($this->loadContainersList($id, $loadContent, $loadDeleted))) {
		    $this->debug('ContainersListsManager::getContainersList, error : unable to load containerslist ('.$id.')', 3);
			}
			else {
        $result = &$this->containersListsTable[$id];
			}
		}
		else {
      $result = &$this->containersListsTable[$id];
		}
    $this->debug('ContainersListsManager::getContainersList, status : function completed', 10, DBG_CLOSE);
		return $result;
	}
	
	/**
	 * @param object $containersList
	 */
	function setContainersList(&$containersList) {
    $this->debug('ContainersListsManager::setContainersList, status : function invoked', 10, DBG_OPEN);
		if (!is_object($containersList)) {
			$this->debug('ContainersListsManager::setContainersList, error : not an object (skipped)', 3);
		}
		else {
			$id = $containersList->getContainersListId();
			$this->containersListsTable[$id] = &$containersList;
		}
    $this->debug('ContainersListsManager::setContainersList, status : function completed', 10, DBG_CLOSE);
	}

	/**
	 * Adds ContainersList Into Manager
	 *
	 * @param  object $containersList
	 * @return boolean
	 */
	function addContainersList(&$containersList){
    $this->debug('ContainersListsManager::addContainersList, status : function invoked', 10, DBG_OPEN);
		if ($this->checkContainersList($containersList->getContainersListId())){
			$this->debug("ContainersListsManager::addContainersList, warning : container (".$containersList->getContainersListId().") already loaded in containersLists manager : value overwritten.", 5);
		}
    $result = $this->setContainersList($containersList);
    $this->debug('ContainersListsManager::addContainersList, status : function completed', 10, DBG_CLOSE);
		return $result;
	}
	
	/**
	 * Gets New ContainersList
	 *
	 * @param  integer $aclId
	 * @return object
	 */
	function &getNewContainersList($aclId=1) {
    $this->debug('ContainersListsManager::getNewContainersList, status : function invoked', 10, DBG_OPEN);
		$id          = 0;
		$sortingType = SORTING_BY_LIST;
		$sortField   = 'id';
		$sortOrder   = SORT_ASCENDING;
		$countShown  = 0;
		$cloneId     = 0;
		$deleted     = 0;
		$this->containersListsTable[0] = &new ContainersList($id, $sortingType, $sortField, $sortOrder, $countShown, $cloneId, $aclId, $deleted);
    $this->containersListsTable[0]->setContainersListPublished(PUBLICATION_DEFAULT_VALUE);
    $this->debug('ContainersListsManager::getNewContainersList, status : function completed', 10, DBG_CLOSE);
		return $this->containersListsTable[0];
	}
	
	/**
	 * @param  integer $containersListId
	 * @param  integer $pageId
	 * @param  integer $frameId
	 * @return mixed resource or false
	 */
	function getParentObjectValuesArray($containersListId, $pageId, $frameId) {
    $this->debug('ContainersListsManager::getParentObjectValuesArray, status : function invoked', 10, DBG_OPEN);
    $result = null;
		$result_array = $this->dbManipulator->queryGetPageOfContainersList($pageId, $frameId, $containersListId);
		
		if (!$result || !$this->dbManipulator->getNumRows()) {
      $this->debug('ContainersListsManager::getParentObjectValuesArray, error : unable to get page ('.$pageId.') for containersList ('.$containersListId.')', 2);
		}
		else {
		  $esult = $this->dbManipulator->fetchArray($result_array);
		}
		
    $this->debug('ContainersListsManager::getParentObjectValuesArray, status : function completed', 10, DBG_CLOSE);
		return $row;
	}
	
	/**
	 * Updates ContainersList ACL
	 * 
	 * @param  integer $containersListId ContainersList Id
	 * @param  integer $aclId ACl Id
	 * @return boolean	 	 	 	 
	 */	 	
	function updateContainersListACL($containersListId, $aclId){
    $this->debug('ContainersListsManager::updateContainersListACL, status : function invoked', 10, DBG_OPEN);
    $result = true;
		$containersList = &$this->getContainersList($containersListId);
		$oldAclId = $containersList->getContainersListAclId();

    $db = &$this->getDBManipulator();
    $fields = array('acl_id' => $aclId);

    if(!$db->setRecord(CONTAINERS_LISTS_TABLE, -1, $fields, "`id`= '$containersListId'")){
			$this->debug("ContainersListsManager::updateContainersListACL : error, unable to set new acl_id for containersList (id=$containersListId).", 3);
			$result = false;
		}
    else {
      if($containersList->getContainersListCloneId() == 0) {
    		$containersTable = &$this->getContainersTable($containersListId);

    		for($i=0; $i < count($containersTable); ++$i) {
    			$container = &$containersTable[$i];
    			if($container->getContainerAclId() == $oldAclId) {
    				$this->containersManager->updateContainerACL($container->getContainerId(), $aclId);
    			}
    		}
      }
    }
    $this->debug('ContainersListsManager::updateContainersListACL, status : function completed', 10, DBG_CLOSE);
		return $result;
	}
	
	function _updateContainerACL($containerId, $typeName, $oldAclId, $newAclId) {
    $this->debug('ContainersListsManager::_updateContainerACL, status : function invoked', 10, DBG_OPEN);
    $result = true;
    $result_array = $this->dbManipulator->setRecord(CONTAINERS_TABLE, $containerId, array('acl_id' => $newAclId));
		
		if (!$result_array || !$this->dbManipulator->getAffectedRows()) {
			$result = false;
		}
    else {
  		$result_array = $this->dbManipulator->queryGetContents($containerId, $typeName);

  		if (!$result_array) {
  			$result = false;
  		}
      else {
    		$contentIds = array();
    		$aclIds = array();

    		while ($row = $this->dbManipulator->fetchArray($result_array)) {
    			$contentId = (int )$row['id'];
    			$contentAclId = (int )$row['acl_id'];

    			if ($contentAclId == $oldAclId) {
    				$contentIds[] = $contentId;
    			}
          else {
    				$aclIds[] = $contentAclId;
    			}
    		}

    		if ($contentIds) {
    			$result_array = $this->dbManipulator->setRecord(TYPE_TABLES_PREFIX.$typeName, $contentIds, array('acl_id' => $newAclId));

    			if (!$result_array || !$this->dbManipulator->getAffectedRows()) {
    				$result = false;
    			}
    		}

    		if ($aclIds && $result) {
    			$result_array = $this->dbManipulator->setRecord(ACL_TABLE, array_unique($aclIds), array('parent_id' => $newAclId));

    			if (!$result_array || !$this->dbManipulator->getAffectedRows()) {
    				$result = false;
    			}
    		}
      }
    }
    $this->debug('ContainersListsManager::_updateContainerACL, status : function completed', 10, DBG_CLOSE);
		return $result;
	}
} 
?>