<?php
/**
 * AgileBill - Open Billing Software
 *
 * This body of work is free software; you can redistribute it and/or
 * modify it under the terms of the Open AgileBill License
 * License as published at http://www.agileco.com/agilebill/license1-4.txt
 *
 * Originally authored by Tony Landis, AgileBill LLC
 *
 * Recent modifications by Deon George
 *
 * @author Deon George <deonATleenooksDOTnet>
 * @copyright 2009 Deon George
 * @link http://osb.leenooks.net
 *
 * @link http://www.agileco.com/
 * @copyright 2004-2008 Agileco, LLC.
 * @license http://www.agileco.com/agilebill/license1-4.txt
 * @author Tony Landis <tony@agileco.com>
 * @package AgileBill
 * @subpackage Core
 */

/**
 * The main AgileBill CORE Database Class
 *
 * @package AgileBill
 * @subpackage Core
 */
class CORE_database {
	public function add($VAR,$construct,$type) {
		include_once(PATH_CORE.'database_add.inc.php');
		return CORE_database_add($VAR,$construct,$type);
	}

	public function update($VAR,$construct,$type) {
		include_once(PATH_CORE.'database_update.inc.php');
		return CORE_database_update($VAR,$construct,$type);
	}

	public function search_form($VAR,$construct,$type) {
		include_once(PATH_CORE.'database_search_form.inc.php');
		return CORE_database_search_form($VAR,$construct,$type);
	}

	public function search($VAR,$construct,$type) {
		include_once(PATH_CORE.'database_search.inc.php');
		return CORE_database_search($VAR,$construct,$type);
	}

	public function search_show($VAR,$construct,$type) {
		include_once(PATH_CORE.'database_search_show.inc.php');
		return CORE_database_search_show($VAR,$construct,$type);
	}

	public function view($VAR,$construct,$type) {
		include_once(PATH_CORE.'database_view.inc.php');
		return CORE_database_view($VAR,$construct,$type);
	}

	public function mass_delete($VAR,$construct,$type) {
		include_once(PATH_CORE.'database_mass_delete.inc.php');
		return CORE_database_mass_delete($VAR,$construct,$type);
	}

	public function delete($VAR,$construct,$type) {
		include_once(PATH_CORE.'database_delete.inc.php');
		return CORE_database_delete($VAR,$construct,$type);
	}

	public function join_fields($result,$linked) {
		include_once(PATH_CORE.'database_join_fields.inc.php');
		return CORE_database_join_fields($result,$linked);
	}

	// replaced in v1.4.91 (use sqlSelect)
	# @todo To deprecate
	public function sql_select($TableList,$FieldList,$Conditions,$Order,&$db) {
		return sqlSelect($db,$TableList,$FieldList,$Conditions,$Order);
	}

	/**
	 * Remove fields from the standard construct type to ignore insert/select/validation rules set in construct
	 *
	 * @param array $ignore_fields
	 * @param string $construct_fields
	 * @return array
	 */
	public function ignore_fields($ignore_fields,$construct_fields) {
		if (! is_array($construct_fields))
			$fields = explode(',',$construct_fields);
		else
			$fields = $construct_fields;

		foreach ($fields as $id=>$fld)
			if (in_array($fld,$ignore_fields))
				unset($fields[$id]);

		return $fields;
	}
}

/**
 * The main AgileBill CORE Debugger Class
 *
 * @package AgileBill
 * @subpackage Core
 */
class CORE_debugger {
	public function alert($message) {
		$this->alert = array($message);
	}

	public function error($module,$method,$message) {
		$this->error = sprintf('%s:%s => %s<br/>',$module,$method,$message);

		if (defined('ERROR_REPORTING') && ERROR_REPORTING > 0)
			$this->alert($this->error);

		$db = &DB();
		$result = $db->Execute(sqlInsert($db,'log_error',array('date_orig'=>time(),'account_id'=>SESS_ACCOUNT,'module'=>$module,'method'=>$method,'message'=>$message)));
	}
}

/**
 * The main AgileBill CORE Database Function
 */
function DB($debug=false) {
	static $saved_db_conn;

	if (isset($saved_db_conn) && defined('AGILE_DB_CACHE')) {
		if ($debug)
			$saved_db_conn->debug = true;
		else
			$saved_db_conn->debug = false;

		return $saved_db_conn;
	}

	$saved_db_conn = NewADOConnection(AGILE_DB_TYPE);
	if (defined('AGILE_DB_PCONNECT') && AGILE_DB_PCONNECT == true)
		$saved_db_conn->PConnect(AGILE_DB_HOST,AGILE_DB_USERNAME,AGILE_DB_PASSWORD,AGILE_DB_DATABASE);
	else
		$saved_db_conn->Connect(AGILE_DB_HOST,AGILE_DB_USERNAME,AGILE_DB_PASSWORD,AGILE_DB_DATABASE);

	if ($debug)
		$saved_db_conn->debug = true;
	else
		$saved_db_conn->debug = false;

	$saved_db_conn->SetFetchMode(ADODB_FETCH_ASSOC);

	return $saved_db_conn;
}

/**
 * Get the next SQL index ID for a table
 *
 * @param $db
 * @param $table
 * @return int
 */
function sqlGenID($db,$table) {
	$id = 0;

	# Check if our ID table exists, and if not
	static $CACHE = array();
	$dbname = md5($db->databaseType.$db->host.$db->database.$db->user);

	if (! isset($CACHE[$dbname][$table])) {
		$CACHE[$dbname][$table] = true;
		$rs = $db->Execute(sprintf('SELECT id FROM %s%s_id WHERE 1=0',AGILE_DB_PREFIX,$table));

		if ($rs) {
			$rs = $db->Execute(sprintf('SELECT MAX(id) AS max FROM %s%s',AGILE_DB_PREFIX,$table));
			if ($rs)
				$id = $rs->fields['max']+1;
		}
	}

	return $db->GenID(sprintf('%s%s_id',AGILE_DB_PREFIX,$table),$id);
}

/**
 * Generate SQL Conditions for a Query
 */
function sqlConditions($db,$Conditions=false,$Tables=false) {
	$db = &DB();
	$where = 'WHERE ';

	if ($Conditions) {
		if (is_array($Conditions)) {
			foreach ($Conditions as $a => $b)
				if (is_array($b))
					$where .= sprintf("%s IN ('%s') AND ",$a,implode("','",$b));
				elseif ($db->qstr($b) == 'NULL')
					$where .= sprintf('%s IS NULL AND ',$a);
				else
					$where .= sprintf('%s=%s AND ',$a,$db->qstr($b));

		} else {
			if (preg_match('/::/',$Conditions)) {
				$s = explode('::',$Conditions);
				$ii = 1;
				$Conditions = '';

				for ($i=0; $i<count($s); $i++) {
					if ($ii==1) {
						$Conditions .= $s[$i];
						$ii++;

					} else {
						$Conditions .= $db->qstr($s[$i]);
						$ii = 1;
					}
				}
			}

			$where .= sprintf('%s AND ',$Conditions);
		}
	}

	# Add the SITE ID
	if (! is_array($Tables) || count($Tables) == 1) {
		if (in_array($Tables,array('setup','currency','tax')))
			$where .= sprintf('id=%s',DEFAULT_SITE);
		else
			$where .= sprintf('site_id=%s',DEFAULT_SITE);

	} else {
		$tbarr = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V');
		for ($i=0; $i<count($Tables); $i++) {
			if ($i>0)
				$where .= ' AND ';

			$where .= sprintf(' %s.site_id = %s',$tbarr[$i],DEFAULT_SITE);
		}
	}

	$where = str_replace('{p}',AGILE_DB_PREFIX,$where);

	return $where;
}

/**
 * Generate SQL to delete from the database
 */
function sqlDelete($db,$table,$where) {
	$db = &DB();
	$where = sqlConditions($db,$where);

	return sprintf('DELETE FROM %s%s %s',AGILE_DB_PREFIX,$table,$where);
}

/**
 * Generate SQL to insert into the database
 */
function sqlInsert($db,$table,$FieldList,$id=false) {
	$db = &DB();

	if (! $id)
		$id = sqlGenID($db,$table);

	$FieldList['id'] = $id;
	if (empty($FieldList['site_id']))
		$FieldList['site_id'] = DEFAULT_SITE;

	$table = AGILE_DB_PREFIX.$table;
	return $db->GetInsertSQL($table,$FieldList,get_magic_quotes_gpc());
}

/**
 * Generate SQL to update records in the database
 */
function sqlUpdate($table,$FieldList,$options=array()) {
	$sql = array();
	$force = false;
	$db = &DB();

	# Transition until all calls to sqlUpdate() are changed
	# @todo To deprecate
	if (func_num_args() >= 4) {
		$args = func_get_args();
		$db = array_shift($args);
		$table = array_shift($args);
		$FieldList = array_shift($args); if (! is_array($FieldList)) $FieldList=array($FieldList);
		$options['where'] = array_shift($args);
		$options['force'] = count($args) ? array_shift($args) : false;
	}

	if (isset($options['force']))
		$force = $options['force'];
	if (isset($options['where']))
		$sql['where'] = $options['where'];

	$rs = $db->Execute(sqlSelect($table,'*',$sql));
	return $db->GetUpdateSQL($rs,$FieldList,$force,get_magic_quotes_gpc());
}

/**
 * Generate SQL to select records from the database
 */
function sqlSelect($TableList,$FieldList,$sql=array()) {
	# Transition until all calls to sqlSelect() are changed
	# @todo To deprecate
	if (func_num_args() >= 4) {
		$sql = array();

		$args = func_get_args();
		$db = array_shift($args);
		$TableList = array_shift($args);
		$FieldList = array_shift($args);
		$sql['where'] = array_shift($args);
		$sql['orderby'] = count($args) ? array_shift($args) : '';
		$sql['limit'] = count($args) ? array_shift($args) : 0;
		$sql['distinct'] = count($args) ? array_shift($args) : false;
		$sql['groupby'] = count($args) ? array_shift($args) : '';
	}

	# Table(s)
	if (is_array($TableList)) {
		$tbarr = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V');
		$table = '';

		$i = 0;
		foreach ($TableList as $index => $value) {
			if ($i++>0)
				$table .= ',';

			$table .= sprintf('%s%s AS %s',AGILE_DB_PREFIX,$value,$tbarr[$index]);
		}
	} else {
		$table = AGILE_DB_PREFIX.$TableList;
	}

	# Field(s)
	if (isset($sql['distinct']) && $sql['distinct'])
		$fields = 'DISTINCT '.$FieldList;
	else
		$fields = $FieldList;

	# Condition(s)
	# @todo to remove sqlConditions() doesnt need $db
	if (! isset($db))
		$db = &DB();
	$where = sqlConditions($db,$sql['where'],$TableList);

	$line = '';
	# Group By
	if (isset($sql['groupby']) && $sql['groupby'])
		$line .= sprintf(' GROUP BY %s',$sql['groupby']);

	# Order By
	if (isset($sql['orderby']) && $sql['orderby'])
		$line .= sprintf(' ORDER BY %s',$sql['orderby']);

	# Limit
	if (isset($sql['limit']) && $sql['limit'])
		$line .= ' LIMIT '.$sql['limit'];

	$SQL = sprintf('SELECT %s FROM %s %s %s',$fields,$table,$where,$line);

	if (isset($sql['debug']))
		printf('<pre>%s</pre>',$SQL);

	return $SQL;
}
?>