<?php 

/**

 * Pagination Component, responsible for managing the DATA required for pagination.

 */

class PaginationComponent extends Object

{

    // Configuration/Default variables

/**

 * Specify whether the component will use AJAX links if available.

 * Tests for the presence of the RequestHandler component and if present will generate

 * AJAX links. However, if the prototype library js has not been included, normal updates

 * will take place.

 *

 * @var boolean

 * @access public

 */

	var $ajaxAutoDetect = true;

/**

 * Specify the div to update if using ajax updates

 *

 * @var string

 * @access public

 */

	var $ajaxDivUpdate = "content";

/**

 * The id of a form ID to be submitted with all pagination ajax links.

 *

 * @var string

 * @access public

 */

	var $ajaxFormId = NULL;

/**

 * Specify link style

 *

 * @var string "html"/"ajax"

 * @access public

 */

	var $style = "html";

/**

 * Specify link parameter style

 *

 * @var string "get"/"pretty"

 * @access public

 */

	var $paramStyle = "get";

/**

 * Used only for pretty style urls - must match the 

 *

 * @var string "get"/"pretty"

 * @access public

 */

	var $paramSeperator = "/";

/**

 * Specify DEFAULT start page number

 *

 * @var integer

 * @access public

 */

	var $page = 1;

/**

 * Specify DEFAULT number of items to be displayed per page. Also used as the limit

 * for the subsequent SQL search.

 *

 * @var integer

 * @access public

 */

	var $show = 5;

/**

 * Specify DEFAULT sort column.

 *

 * @var string

 * @access public

 */

	var $sortBy = 'id';

/**

 * Specify DEFAULT sort direction.

 *

 * @var string

 * @access public

 */

	var $direction = 'ASC';

/**

 * Specify the maximum number of pages to be included in the list of pages. Should be an odd number, otherwise rounded down.

 *

 * @var integer

 * @access public

 */

    var $maxPages = 10;

/**

 * Options for results per page.

 *

 * @var array

 * @access public

 */

    var $resultsPerPage = array(3,5,10,20,50,100,500);

/**

 * Show links to the first and last page, if the number of pages exceeds the maxPage count.

 *

 * @var boolean

 * @access public

 */

	var $showLimits = true;

/**

 * An array of parameter names which cannot be specified by the url

 *

 * @var array

 * @access public

 */

	var $privateParams = Array();



    // Do not edit below this line unless you wish to customize the core functionality of this Component

/**

 * Place holder for the sort class. Irrelavent for models without associations

 *

 * @var boolean

 * @access private

 */

	var $sortByClass = NULL;

/**

 * Place holder for the model class.

 *

 * @var boolean

 * @access private

 */

	var $modelClass = NULL;

/**

 * Place holder for the base url

 *

 * @var boolean

 * @access private

 */

	var $url = NULL;

/**

 * Place holder for the controller

 *

 * @var boolean

 * @access private

 */

    var $controller = true;

/**

 * Place holder for the sanitize object

 *

 * @var boolean

 * @access private

 */

	var $sanitize = true;

/**

 * Place holder for the data array passed to the view

 *

 * @var boolean

 * @access private

 */

	var $paging;



/**

 * Startup - Link the component to the controller.

 *

 * @param controller

 */

    function startup(&$controller)

    {

		$this->controller =& $controller;    	

    }

/**

 * Initialize the pagination data.

 *

 * @param unknown

 * @param array

 * @options array

 * @return array

 */

    function init($criteria=NULL,$parameters=Array(),$options=Array())

    {

		uses('sanitize');

		$this->Sanitize = new Sanitize;



		$this->_initFields($options);

		$this->_checkAjax();

		$this->_initSort();

		$this->_initPaging($parameters);

		$this->_initURL();



		$this->_setParameter("show",$parameters);

		// If the number of results per page isn't in the list, reset to default

		if ((isset($this->paging["show"]))&&(!in_array($this->paging["show"],$this->resultsPerPage)))

		{

			$this->paging["show"]=$this->paging['Defaults']['show'];

		}

		

		$this->_setParameter("page",$parameters);

		$this->_setParameter("sortBy",$parameters);

		$this->_setParameter("sortByClass",$parameters); // Overriding the model class if specified.

		$this->_setParameter("direction",$parameters);



		$this->_check4Form();



		$this->_setPrivateParameter("ajaxDivUpdate");

		$this->_setPrivateParameter("ajaxFormId");

		$this->_setPrivateParameter("maxPages");

		$this->_setPrivateParameter("showLimits");

		$this->_setPrivateParameter("style");

		$this->_setPrivateParameter("paramStyle");

		$this->_setPrivateParameter("paramSeperator");

		$this->_setPrivateParameter("url");



		if (isset($this->total)) // If the field is already set, we  passed in the options the total number of results

		{

			$count = $this->total;

		}

		else

		{

			$count = $this->controller->{$this->modelClass}->findCount($criteria,0);	

		}

		$this->checkPage($count);

		$this->paging['total'] = $count;

		$this->trimResultsPerPage($count);



		$this->_setPrivateParameter("resultsPerPage");



    	$this->paging['pageCount'] = ceil($count / $this->paging['show'] );



    	$this->controller->set('paging',$this->paging);

    	

        $this->order = $this->paging['sortByClass'].".".$this->paging['sortBy'].' '.strtoupper($this->paging['direction']);

        

    	// For backwards compatability & clarity

    	$this->limit = $this->paging['show'];

    	$this->page = $this->paging['page'];

    	

    	// For less code in the calling method..

    	return (Array($this->order,$this->paging['show'],$this->paging['page']));

	}

	

/**

 * Don't give the choice to display pages with no results

 *

 * @param integer

 */

    function trimResultsPerPage ($count = 0)

    {

        while (($limit = current($this->resultsPerPage))&&(!isset($capKey))) 

        {

            if ($limit >= $count) 

            {

                $capKey = key($this->resultsPerPage);

            }

        	next($this->resultsPerPage);

        

	        if (isset($capKey))

        	{

            	array_splice($this->resultsPerPage, ($capKey+1));

            }

        }

    }



/**

 * Set the page to the last if there would be no results, and to 1 if a negetive

 * page number is specified

 *

 * @param integer

 */

    function checkPage ($count = 0) 

    {

      if ((($this->paging['page']-1)*$this->paging['show'])>=$count) 

      {

            $this->paging['page'] = floor($count/$this->paging['show']+0.99);

      }

    }

	

/**

 * Set Object fields

 *

 * @param unknown

 */

	function _initFields($options)

	{

		foreach($options as $option=>$val)

		{

			$this->$option = $val;

		}

	}

/**

 * Set Pagination with default Parameters

 *

 * @param unknown

 */

	function _initPaging($parameters)

	{

		$this->paging['importParams']=$parameters;

		$this->paging['Defaults'] = Array (

										"page"=>$this->page,

										"show"=>$this->show,

										"sortBy"=>$this->sortBy,

										"sortByClass"=>$this->sortByClass,

										"direction"=>$this->direction

											);		

	}

/**

 * If everything is in place, use Ajax by default

 *

 * @param unknown

 */

	function _checkAjax()

	{

		if (($this->ajaxAutoDetect==true)&&(isset($this->controller->RequestHandler)&&(in_array("Ajax",$this->controller->helpers))))

		{

			$this->style = "ajax";			

		}

	}



/**

 * Set the DEFAULT sort class

 *

 * @param unknown

 */

	function _initSort()

	{

		if (!$this->modelClass)

		{

		    $ModelClass = $this->modelClass = $this->controller->modelClass;

		}

		else

		{

			$ModelClass = $this->modelClass;

		}

		if (!$this->sortBy)

		{

		$this->sortBy = $this->controller->$ModelClass->primaryKey;

		}

		if (!$this->sortByClass)

		{

			$this->sortByClass = $ModelClass;

		}

	}



/**

 * Set the base url for updates.

 *

 * @param unknown

 */

	function _initURL()

	{

		if ($this->url) // A url was specified in the paramters

		{

			if (substr($this->url, -1, 1)<>"/")

			{

				$this->url .= "/";

			}

		}

		else // No url in the parameters, derive it.

		{

			if ($this->paramStyle=="get")

			{

				$this->url = str_replace($this->controller->webroot,"/",$this->controller->here);

			}

			else

			{

				$this->url = "";

				if (isset($this->controller->params['admin']))

				{

					$this->url .= "/".$this->controller->params['admin'];

					$action = substr($this->controller->action, strlen($this->controller->params['admin']."_"));

				}

				else

				{

					$action = $this->controller->action;

				}

				if ($this->controller->plugin)

				{

					$this->url .= "/".$this->controller->plugin;

				}

				$this->url .= "/".$this->controller->name;

				$this->url .= "/".$action;

				if (isset($this->paging['importParams']['_unamedParameters']))

				{

					$unnamedString = implode ("/", $this->paging['importParams']['_unamedParameters']);

					$this->url .= "/".$unnamedString;

					unset($this->paging['importParams']['_unamedParameters']);

				}

				$this->url .= "/";

			}

		}

		if (defined('BASE_URL')) { // Hack for no mod_rewrite

			$this->url = preg_replace( "!".BASE_URL."!", '', $this->url); // Remove the base from the url

			$this->url = preg_replace("!\?.*!", '', $this->url); // Remove the get parameters

		}

	}



/**

 * If the parameters have been changed/set by a form action, update the params array.

 * Would perhaps be best to redirect to the equivalent url, which isn't implemented as

 * the relavent method is in the helper and as such inaccessible here.

 *

 * @param unknown

 */

	function _check4Form()

	{

		if(isset($this->controller->data['pagination']))

		{

			if (isset($this->controller->data['pagination']['sortByComposite']))

			{

				$Composite = Array();

				$Composite = explode("::",$this->controller->data['pagination']['sortByComposite']);

				if (isset($Composite[0]))

				{

					$this->controller->data['pagination']['sortBy'] = $Composite[0];	

				}

				if (isset($Composite[1]))

				{

					$this->controller->data['pagination']['direction'] = $Composite[1];	

				}

				if (isset($Composite[2]))

				{

					$this->controller->data['pagination']['sortByClass'] = $Composite[2];	

				}

				else

				{

					$this->controller->data['pagination']['sortByClass'] = $this->paging['Defaults']['sortByClass'];

				}

				unset($this->controller->data['pagination']['sortByComposite']);			

			}

			foreach($this->controller->data['pagination'] as $parameter=>$value)

			{

				

				if (!in_array($parameter, $this->privateParams))

				{

					$this->paging[$parameter] = $this->Sanitize->paranoid($value,array("-","_"));

				}				

			}

		}

	}



/**

 * Set a parameter to be passed to the view which cannot be specified/overriden from the url.

 *

 * @param unknown

 */

	function _setPrivateParameter($parameter)

	{

		$this->paging[$parameter]= $this->$parameter;

	}



/**

 * Set a parameter to be passed to the view overriden from the url if present.

 *

 * @param unknown

 * @param array

 * @param field

 */

	function _setParameter($parameter,$parameters=Array(),$field=NULL)

	{

		$field = $field?$field:$parameter;



		if (in_array($parameter, $this->privateParams))

		{

			$this->paging[$field] = $this->paging['Defaults'][$field];

		}

		else

		{

			if ($this->paramStyle=="get")

			{

				if (isset($_GET[$parameter]))

				{

					$this->paging[$field] = $this->Sanitize->paranoid($_GET[$parameter],array("-","_"));		

				}

				else

				{

					$this->paging[$field]= $this->$field;

				}

			}

			elseif ($this->paramStyle=="pretty")

			{

				if (isset($parameters[$parameter]))

				{

					$this->paging[$field] = $this->Sanitize->paranoid($parameters[$parameter],array("-","_"));		

				}

				else

				{

					$this->paging[$field]= $this->$field;

				}

			}

			else

			{

				echo ("parameter error");

				die;

			}

		}

	}

}

?>