<?php
#-------------------------------------------------------------------
#
# Confidential - Property of Symcell Corporation
# Do not copy or distribute.
# Copyright 2005-2007 Symcell Corporation. All rights reserved.
#
#-------------------------------------------------------------------

require_once('global.inc.php');
require_once('Exception.class.php');

//http://www.codeproject.com/KB/cs/abstractsvsinterfaces.aspx

abstract class baseClass
{
	protected $table = NULL;
	
	protected $id 		  = NULL;
	protected $timestamp  = NULL;
	protected $created_on = NULL;
	protected $enabled 	  = TRUE;

	/**
	* Constructor
	* 
	* @access 	public
	* @return 	object
	* @param	int $id the ID of the object to load from the database
	* @author 	Daevid Vincent [daevid@symcell.com]
	* @since 	1.0
	* @version 	1.0
	* @date    	12/18/05
	*/
	function __construct($id = NULL)
	{
		if (!is_null($id)) 
			$this->load($id);
		
		if (is_null($this->table)) 
			$this->table = strtolower($this->getClassName()).'s';
	}

	function get_id()			{	return $this->id;			}
	function get_timestamp()	{	return $this->timestamp;	}
	function get_created_on($format = false) {	return ($format) ? $this->format_date($this->created_on) : $this->created_on;	}

	function is_enabled()		{	return ($this->enabled);	}

	/**
	* Format a date in YYYY-MM-DD HH:II:SS format to our 'standard' MM/DD/YY HH:II AM style
	*
	* http://www.php.net/manual/en/function.date.php
	* http://www.php.net/manual/en/function.mktime.php
	*
	* @access 	public
	* @return 	string in MM/DD/YY HH:II(:ss) AM format
	* @param	string $mydate a date in YYYY-MM-DD HH:II:SS format
	* @param	boolean $showSeconds
	* @author 	Daevid Vincent [daevid@symcell.com]
	* @since 	1.0
	* @version 	1.1
	* @date    	07/27/06
	*/
	function format_date($mydate, $showSeconds = false)
	{
		if (!$mydate) return '';
		
		list($date, $hours) = split(' ', $mydate); 
		list($year,$month,$day) = split('-',$date); 
		list($hour,$min,$sec) = split(':',$hours); 
		
		return date('m/d/y h:i'.( ($showSeconds) ? ':s':'' ).' A', mktime($hour, $min, $sec, $month, $day, $year));
	}

	/**
	* generate a key/value pair from the class' variables.
	*
	* @access 	public
	* @return 	array
	* @author 	Daevid Vincent [daevid@symcell.com]
	* @since 	1.0
	* @version 	1.0
	* @date    	01/23/06
	*/
	function get_array()
	{
		$row = array();
		foreach($this as $key => $value) 
			$row[$key] = $value;
		
		return $row;
	}

	/**
	* set the class' values based upon a SQL table which is converted to an array of column(key) value pairs and passed to load_from_array().
	*
	* @access 	public
	* @return 	array or false
	* @param	string $sql SQL schema columns to use as array keys
	* @author 	Daevid Vincent [daevid@symcell.com]
	* @since 	1.0
	* @version 	1.0
	* @date    	01/23/06
	* @see 		load_from_array()
	*/
	function load_from_sql($sql = null)
	{
		if (is_null($sql)) return false;
		
		$result = SQL_QUERY($sql." LIMIT 1");
		if($result && $row = SQL_ASSOC_ARRAY($result))
		{
			return $this->load_from_array($row);
			//$this->iterateVisible();
		}
		else return false;
	}

	/**
	* set the class' values based upon an array.
	*
	* @access 	public
	* @return 	boolean
	* @param	array $row class or SQL schema column/value pairs
	* @author 	Daevid Vincent [daevid@symcell.com]
	* @since 	1.0
	* @version 	1.0
	* @date    	01/23/06
	* @see 		load_from_sql()
	*/
	function load_from_array($row)
	{
		if (intval($row['id']) < 1) return false;
		
		foreach($row as $key => $value)
			$this->$key = $value;
		
		//$this->iterateVisible();
		return true;
	}

	/**
	* INSERT or UPDATE an object's Database row.
	*
	* Pass in an array of column name/value pairs to INSERT/UPDATE those specifically, using schema defaults for the rest.
	* 
	* @access 	public
	* @return 	boolean false on error, true on UPDATE, record ID on INSERT
	* @param	array $row SQL schema column/value pairs
	* @param	boolean $auto_escape (true) will wrap all values in SQL_ESCAPE()
	* @param	boolean $show_errors toggle SQL errors, use SQL_ERROR_NUM() or SQL_ERROR() to handle yourself.
	* @author 	Daevid Vincent [daevid@symcell.com]
	* @since 	1.0
	* @version 	1.5
	* @date    	01/07/08
	*/
	public function sync($row = null, $auto_escape = true, $show_errors = true)
	{
		if (is_null($this->table)) return false;
		
		if (is_null($row)) $row = $this->get_array();
		
		if (count($row) < 1) return;
		
		//[dv] this is a handy way to shortcut and update a record with the passed in array key/vals.
		if ($row['id'] < 1) unset($row['id']);
		if (!$this->id && $row['id'] > 0) $this->id = $row['id'];
		
		//[dv] I thought about scrubbing the $row array of empty values, 
		//     but that causes a problem if you actually DO want to wipe out some values.
		
		if ($row['enabled']) $row['enabled'] = ($row['enabled']) ? 1 : 0;
		
		if (intval($this->id) < 1) 
		{
			$cols = "`".implode("`, `", array_keys($row))."`";
			$temp = array();
			foreach ( $row as $val )
			{
				if (!is_null($val)) $value = trim($val);
				$temp[] = ($auto_escape === true) ? "'".SQL_ESCAPE( $val )."'" : $val;
			}
			$values = implode(', ',$temp);
			$sql = "INSERT INTO ".$this->table." (created_on, ".$cols.") VALUES (NOW(), ".$values.")";	
		}
		else
		{
			$sql = "UPDATE ".$this->table." SET ";
			unset($row['id']);
			$temp = array();
			foreach ($row as $col => $value)
			{
				if (!is_null($value)) $value = trim($value);
				$temp[] = $col." = ".(($auto_escape === true) ? "'".SQL_ESCAPE( $value )."'" : $value);
			}
			$sql .= implode(', ', $temp);
			$sql .= " WHERE id = '".$this->id."' LIMIT 1";
		}
		
		if ($sth = SQL_QUERY($sql, false, $show_errors)) 
		{
			if (intval($this->id) < 1) 
			{
				$this->id = SQL_INSERT_ID();
				$this->load_from_array($row); //[dv] TODO: not sure if this is needed
				return $this->id;
			}
			else
			{
				$this->load_from_array($row); //[dv] TODO: not sure if this is needed
				return true;
			}
		}
		else 
			return false;
	}

	/**
	* Delete the corresponding class object ID from the database.
	*
	* Note: 'delete' is a reserved word in PHP
	*
	* @access 	public
	* @return 	boolean
	* @param	int $id class id corresponding to SQL table PK id
	* @author 	Daevid Vincent [daevid@symcell.com]
	* @since 	1.0
	* @version 	1.1
	* @date    	08/21/07
	*/
	public function delete()
	{
		if (SQL_QUERY("DELETE FROM ".$this->db.".".$this->table." WHERE id = '".$this->id."' LIMIT 1")) 
		{
		    foreach($this as $key => $value) 
				$this->$key = null;
			
			return true;
		}
		else 
			return false;
	}


	/**
	* Shows all exposed variables in this class
	*
	* @access 	public
	* @return	array
	* @param	boolean $print to print out each value
	* @author 	Daevid Vincent [daevid@symcell.com]
	* @since 	1.0
	* @version 	1.1
	* @date    	01/31/06
	*/
	function iterateVisible($print = false) 
	{
	    if ($print) echo "\n<BR><B>".$this->getClassName()."::iterateVisible:</B><BR>\n";
		
		$tmp = array();
	    foreach($this as $key => $value) 
		{
			$tmp[$key] = $value;
			if ($print) print $key." => ".$value."<BR>\n";
		}
		
		return $tmp;
	}

	/**
	* returns the name of this class as a string
	* 
	* @access 	public
	* @return 	string
	* @author 	Daevid Vincent [daevid@symcell.com]
	* @since 	1.0
	* @version 	1.0
	*/
	function getClassName()
	{
		//return __CLASS__;
		return get_class($this);
	}

	/**
	* Provides generic getters and setters
	*
	* @access	public
	* @param    string $method The method name.
	* @param    array $arguments The arguments passed to the method.
	* @return	mixed
	* @author 	Daevid Vincent [daevid@symcell.com]
	* @date     08/21/2007
	* @version	1.1
	* @see		__get(), __set()
	*/
	public function __call( $method, $arguments )
	{
		$prefix = strtolower( substr( $method, 0, 3 ) );
		$property = strtolower( substr( $method, 4 ) );
		
		if ( empty($prefix) || empty($property) ) return;
		
		if ( 'get' == $prefix )
		{ 
			if ( property_exists($this, $property) )
				return $this->$property;
			else
				return $this->__get($property);
		}
		elseif ( 'set' == $prefix )
		{
			if ( property_exists($this, $property) )
				return $this->$property = $arguments[0];
			else
				return $this->__set($property, $arguments[0]);
		}
		
	    echo "<p><font color='#ff0000'>Attempted to '".$method."' variable in class '".$this->getClassName()."'.</font><p>\n";
		backtrace();
	}

	/**
	* magic function to handle any accessing of undefined variables.
	* Since PHP is "lax" this will help prevent stupid mistakes.
	* 
	* @access 	public
	* @return 	void
	* @param	mixed $var name of the variable
	* @author 	Daevid Vincent [daevid@symcell.com]
	* @since 	1.0
	* @version 	1.1
	* @date    	04/22/07
	* @see		__set(), __call()
	*/
	public function __get($var) 
	{
	    echo "<p><font color='#ff0000'>Attempted to __get() variable '".$var."' in class '".$this->getClassName()."'.</font><p>\n";
		backtrace();
	}

	/**
	* magic function to handle any setting of undefined variables.
	* Since PHP is "lax" this will help prevent stupid mistakes.
	* 
	* @access 	public
	* @return 	void
	* @param	mixed $var name of the variable
	* @param	mixed $val value of the variable
	* @author 	Daevid Vincent [daevid@symcell.com]
	* @since 	1.0
	* @version 	1.1
	* @date    	04/22/07
	* @see		__get(), __call()
	*/
	public function __set($var, $val) 
	{
	    echo "<p><font color='#ff0000'>Attempted to __set() variable '".$var."' to '".$val."' in class '".$this->getClassName()."'.</font><p>\n";
		backtrace();
	}

	/**
	* The destructor method will be called as soon as all references to a particular object are removed 
	* or when the object is explicitly destroyed.
	*
	* This End User method will save the $_SESSION first
	* http://www.php.net/session-set-save-handler
	*
	* @access 	public
	* @author 	Daevid Vincent [daevid@]
	* @since 	1.0
	* @version 	1.0
	* @date    	08/13/07
	*/
	/*
	function __destruct() 
	{
		session_write_close();
		
		parent::__destruct();
	}
	*/

}
?>
