<?php
/**
 * @version $Id: bfSession.php 117 2009-07-14 20:29:10Z  $
 * @package Blue Flame Framework (bfFramework)
 * @copyright Copyright (C) 2003,2004,2005,2006,2007,2008,2009 Blue Flame IT Ltd. All rights reserved.
 * @license GNU General Public License
 * @link http://www.blueflameit.ltd.uk
 * @author Phil Taylor / Blue Flame IT Ltd.
 *
 * bfFramework 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 3 of the License, or
 * (at your option) any later version.
 *
 * bfFramework 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 this package.  If not, see http://www.gnu.org/licenses/
 */
defined ( '_JEXEC' ) or die ( 'Restricted access' );

final class bfSession {
	
	public $hidden_field_defaults = null;
	public $state_defaults = null;
	public $component_name = null;
	public $session = array ();
	public $mode = 'default'; // This is the tab mode
	public $modelist = array (); // The modes we know about
	

	/**
	 * I store the registry
	 */
	private $_registry = null;
	
	public function __construct($component) {
		if (_BF_PLATFORM == 'JOOMLA1.5') {
				$mainframe = JFactory::getApplication ();
			} else {
				global $mainframe;
			}
		
		$this->component_name = $mainframe->get ( 'component' );
		
		$sn = str_replace ( 'com_', '', $this->component_name );
		$this->shortcomponent = $sn;
		if (! isset ( $_SESSION )) {
			@session_start ();
		}
		$this->session = @$_SESSION ['BF________' . $this->component_name];
		$this->mode = 'default'; // Always reset the mode
		$this->_registry = bfRegistry::getInstance ( $this->component_name, $this->component_name );
		
		//  // $this->log("bfSession __construct");
		$this->hidden_field_defaults = $this->_registry->getValue ( 'bfFramework_' . $this->shortcomponent . '.hidden_field_defaults' );
		$this->state_defaults = $this->_registry->getValue ( 'bfFramework_' . $this->shortcomponent . '.state_defaults' );
		
		if (! is_array ( $this->state_defaults ))
			throw new Exception ( 'You have forgotten to set state_defaults' );
			
		// Set up default values for the state and hidden fields if
		// they are not already set up.
		foreach ( $this->state_defaults as $state_variable => $default ) {
			if (($val = $this->get ( $state_variable, null )) == null) {
				// $this->log("__construct: overwriting state $state_variable $default");
				$this->set ( $state_variable, $default );
			} else {
				// $this->log("__construct: NOT overwriting state $state_variable $val $default as it already has a value");
			}
		}
		
		if (! is_array ( $this->hidden_field_defaults ))
			throw new Exception ( 'You have forgotten to set hidden_field_defaults' );
		
		foreach ( $this->hidden_field_defaults as $variable => $default ) {
			if (($val = $this->get ( $variable, null )) == null) {
				// $this->log("__construct: overwriting hidden $variable $default");
				$this->set ( $variable, $default );
			} else {
				// $this->log("__construct: NOT overwriting hidden $variable $val $default");
			}
		}
		
	// $this->log("constructor called");
	}
	
	/**
	 * Return the state as a list of HTML hidden fields
	 * Implement the singleton design pattern. Calling
	 * getInstance() to construct the bfSession opject causes only one instance of
	 * the state to be active. Just what you need!
	 *
	 * @return unknown
	 */
	public static function &getInstance($component_name = 'bfSession') {
		
		static $instance;
		if (! isset ( $instance )) {
			$c = __CLASS__;
			$instance = new $c ( $component_name );
		} // if
		

		return $instance;
	}
	
	/**
	 * Reset the page state e.g. when a page is loaded from the
	 * menu you usually do not want to recall the old state.
	 *
	 */
	public function reset() {
		
		$this->log ( "--------------- session reset -----------------" );
		return;
		/*
		$this->setMode ( 'default' );
		foreach ( $this->hidden_field_defaults as $state_variable => $default ) {
			// $this->log("resetting $state_variable,$default");
			$this->set ( $state_variable, $default );
		}
		foreach ( $this->state_defaults as $state_variable => $default ) {
			$this->set ( $state_variable, $default );
		}
		// $this->log("Resetting modes:");
		foreach ( $this->modelist as $mode => $value ) {
			// $this->log("  Resetting $mode");
			$this->session [$mode] = array ( );
		}
		*/
	}
	
	/**
	 * Return the state as a list of HTML hidden fields
	 *
	 * @return unknown
	 */
	public function get_hidden_field_defaults_html() {
		$retstr = '';
		foreach ( $this->hidden_field_defaults as $state_variable => $ignoreValue ) {
			/* box checked and task should always be empty hidden fields */
			if ($state_variable == 'boxchecked' or $state_variable == 'task') {
				$state_value = '';
			} else {
				$state_value = $this->get ( $state_variable, '' );
			}
			$retstr .= "<input type=\"hidden\" id=\"$state_variable\" name=\"$state_variable\" value=\"$state_value\">\n";
		}
		return ($retstr);
	}
	
	/**
	 * Return the state as a list of parameters suitable for passing
	 * to a javascript function.
	 *
	 * @return unknown
	 */
	public function get_parameters_list() {
		$retstr = '';
		$first_time_through = 1;
		foreach ( $this->hidden_field_defaults as $state_variable ) {
			$state_value = $this->get ( $state_variable, '' );
			if ($first_time_through) {
				$retstr .= "'$state_variable=$state_value'";
				$first_time_through = 0;
			} else {
				$retstr .= ",'$state_variable=$state_value'";
			}
		}
		return ($retstr);
	
	}
	
	/**
	 * Return a sring containing the session. Needs to be updated to
	 * cope with index tabs.
	 *
	 * @return unknown
	 */
	public function dump() {
		$retstr = "State dump: <br>\n";
		
		foreach ( $this->getSessionArray () as $variable => $value ) {
			$retstr .= "   $variable=$value<br>\n";
		}
		echo ($retstr);
	}
	/**
	 * set the value of a session variable for this component in the required
	 * mode.
	 *
	 * @return old_value
	 */
	public function set($name, $value, $mode = '') {
		$this->session = & $_SESSION ['BF________' . $this->component_name];
		
		$old_value = $this->get ( $name, '' );
		if ($mode == '')
			$mode = $this->mode;
		
		if (! isset ( $this->session [$mode] ))
			$this->session [$mode] = array ();
		
		$this->log ( "setting $name to $value in " . $mode . " mode" );
		$this->session [$mode] [$name] = $value;
		
		return $old_value;
	}
	
	public function parentset($name, $value, $namespace = 'default') {
		$namespace = '__' . $namespace; //add prefix to namespace to avoid collisions
		

		$old = isset ( $_SESSION [$namespace] [$name] ) ? $_SESSION [$namespace] [$name] : null;
		
		if (null === $value) {
			unset ( $_SESSION [$namespace] [$name] );
		} else {
			$_SESSION [$namespace] [$name] = $value;
		}
		
		return $old;
	}
	
	/**
	 * get the value of a session variable for this component
	 *
	 * @return sesion variable value
	 */
	public function get($name, $default = '', $mode = '') {
		
		$this->session = & $_SESSION ['BF________' . $this->component_name];
		if ($mode == '')
			$mode = $this->mode;
		
		if (isset ( $this->session [$mode] [$name] )) {
			//			 $this->log("get: Hit ".$mode." $name = ".$this->session[$mode][$name]);
			return ($this->session [$mode] [$name]);
		} else if (isset ( $this->session ['default'] [$name] )) {
			//			 $this->log("get: Hit (default) $name = ".$this->session['default'][$name]);
			return ($this->session ['default'] [$name]);
		} else {
			//			 $this->log("get: Miss $name defaulting to '$default'");
			return $default;
		}
	}
	
	public function parentget($name, $default = null, $namespace = 'default') {
		$namespace = '__' . $namespace; //add prefix to namespace to avoid collisions
		

		if (isset ( $_SESSION [$namespace] [$name] )) {
			return $_SESSION [$namespace] [$name];
		}
		return $default;
	}
	
	/**
	 * get the session array for this component
	 * giving priority to modal values from the tab/index
	 *
	 * @return sesion array
	 */
	public function getSessionArray() {
		
		if ($this->mode == 'default') {
			return ($this->session ['default']);
		} else {
			$sessionarray = array_merge ( $this->session ['default'], $this->session [$this->mode] );
		}
		return ($sessionarray);
	}
	
	/**
	 * Set the tab mode for index pages. This allows
	 * Different tabs to maintain different states.
	 *
	 * @param unknown_type $msg
	 */
	public function setMode($mode) {
		// $this->log("---------- setting mode to $mode ---------");
		$this->mode = $mode;
		$this->modelist [$mode] = 1;
		if (! isset ( $this->session [$this->mode] ) || ! is_array ( $this->session [$this->mode] ))
			$this->session [$this->mode] = array ();
	}
	
	/**
	 * Return the index tab mode
	 *
	 * @return unknown
	 */
	public function getMode() {
		return $this->mode;
	}
	
	/**
	 * Set the tab index returnto location
	 *
	 * @param location $target
	 */
	public function returnto($target) {
		$this->set ( 'returnto', $target, 'default' );
	}
	
	/**
	 * log for bfSession
	 *
	 * @param unknown_type $msg
	 */
	public function log($msg) {
		$log = &bfLog::getInstance ( $this->component_name );
		$log->log ( __CLASS__ . ":$msg" );
	}

}
?>
