<?php
/**
 * Joom!Fish - Multi Lingual extention and translation manager for Joomla!
 * Copyright (C) 2003-2009 Think Network GmbH, Munich
 * 
 * All rights reserved.  The Joom!Fish project is a set of extentions for 
 * the content management system Joomla!. It enables Joomla! 
 * to manage multi lingual sites especially in all dynamic information 
 * which are stored in the database.
 *
 * This program 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.
 *
 * This program 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 program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
 *
 * The "GNU General Public License" (GPL) is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * -----------------------------------------------------------------------------
 * $Id: intercept.jdatabasemysql.php 1394 2009-08-10 13:41:11Z geraint $
 * @package joomfish
 * @subpackage jfdatabase
 * @version 2.0
 *
*/


// Don't allow direct linking
defined( '_JEXEC' ) or die( 'Direct Access to this location is not allowed.' );

class interceptDB extends JDatabaseMySQL {

	/**
	 * This special constructor reuses the existing resource from the existing db connecton
	 *
	 * @param unknown_type $options
	 */
	function __construct($options){
		$db = & JFactory::getDBO();

		$select		= array_key_exists('select', $options)	? $options['select']	: true;
		$database	= array_key_exists('database',$options)	? $options['database']	: '';

		// perform a number of fatality checks, then return gracefully
		if (!function_exists( 'mysql_connect' )) {
			$this->_errorNum = 1;
			$this->_errorMsg = 'The MySQL adapter "mysql" is not available.';
			return;
		}

		// connect to the server
		$this->_resource = & $db->_resource;

		// finalize initialization
		JDatabase::__construct($options);

		// select the database
		if ( $select ) {
			$this->select($database);
		}

	}

	function _getFieldCount(){
		if (!is_resource($this->_cursor)){
			// This is a serious problem since we do not have a valid db connection
			// or there is an error in the query
			if ($this->getErrorNum()>0){
				echo JText::_("No valid database connection")." ".$this->getErrorMsg()."<br/>";
			}
			return 0;
		}

		$fields = mysql_num_fields($this->_cursor);
		return $fields;
	}

	function _getFieldMetaData($i){
		$meta = mysql_fetch_field($this->_cursor, $i);
		return $meta;
	}
	

	function fillRefTableCache($cacheDir,$cacheFile){

		$pfunc = $this->_profile();

		$cacheFileContent = serialize($this->_refTables);
		JFile::write($cacheFile,$cacheFileContent);
		// clean out old cache files
		// This could be very slow for long list of old files -
		// TODO store in database instead
		$this->cleanRefTableCache($cacheDir);
		
		$pfunc = $this->_profile($pfunc);

	}

	function cleanRefTableCache($cacheDir){

		$pfunc = $this->_profile();
		
		$files =JFolder::files($cacheDir); 
		foreach ($files as $file) {
			if (($file != '.') && ($file != '..')) {
				$file = "$cacheDir/$file";
				if (JFile::exists($file) && @filemtime($file) < $this->cacheExpiry) {
					if (!JFile::delete($file)) {
						echo "problems clearing cache file $file";
					}
				}
			}
		}
		
		$pfunc = $this->_profile($pfunc);

		return true;
	}

	function _logSetRefTablecache($action,$tempsql,$sql_exNos,$sqlHash){

		$pfunc = $this->_profile();

		$logfile = dirname(__FILE__)."/qalog.txt";
		$handle = fopen($logfile,"ab");
		// replace tabs and carriage returns with spaces
		fwrite($handle,"$action ");
		fwrite($handle,preg_replace("/([\t\n\r\f])/"," ",$tempsql));
		fwrite($handle," #@�^�@# ");
		fwrite($handle,preg_replace("/([\t\n\r\f])/"," ",$sql_exNos));
		fwrite($handle," #@�^�@# ");
		fwrite($handle,preg_replace("/([\t\n\r\f])/"," ",$sqlHash));
		fwrite($handle," # JF LINE END# \n");

		fclose($handle);
		
		$pfunc = $this->_profile($pfunc);

	}
	
	function setRefTables(){

		$pfunc = $this->_profile();

		// Before joomfish manager is created since we can't translate so skip this anaylsis
		global $_JOOMFISH_MANAGER;
		if (!$_JOOMFISH_MANAGER) return;

		// This could be speeded up by the use of a cache - but only of benefit is global caching is off
		$tempsql = $this->_sql;
		// only needed for selects at present - possibly add for inserts/updates later
		if (strpos(strtoupper($tempsql),"SELECT")===false) {
			$pfunc = $this->_profile($pfunc);
			return;
		}
		
		// Ignore Joomfish translation query	
		if (strpos($tempsql,"SELECT jf_content.reference_field, jf_content.value")===0){
			$pfunc = $this->_profile($pfunc);
			return;
		}
	
		$config =& JFactory::getConfig();
	
		jimport('joomla.client.helper');
		$FTPOptions = JClientHelper::getCredentials('ftp');
		// we won't use this caching if FTP layer ie enabled
		if ($_JOOMFISH_MANAGER->getCfg("qacaching",1) && $FTPOptions['enabled'] == 1){
			$cachepath = JPATH_CACHE;
			$cachetime = $config->getValue('config.cachetime',0);
			// remove time formats (assume all numbers are not necessay - this is experimental
			// for example table names or column names could contain numbers
			// so this version only replaces numbers not adjacent to alpha characters i.e.field2 doesn't become field
			$sql_exNos = preg_replace("/(?![a-z])(.)([0-9]+)(?![a-z]+)/i",'${1}',$tempsql);
			$sql_exNos = preg_replace("/(?![a-z]).([0-9]+)$/i",'${1}',$sql_exNos);

			if ( $config->getValue('config.debug',0)) {
				echo "<p style='background-color:bisque;border:solid 1px black'><strong>setRefTables debug:</strong><br / >"
				. "tempsql   = $tempsql<br />"
				. "sql_exNos = $sql_exNos"
				. "</p>";
			}

			$sqlHash = md5($sql_exNos );

			$this->cacheExpiry = time() - $cachetime;
			$cacheDir = "$cachepath/refTableSQL";
			if (!JFolder::exists($cacheDir)) JFolder::create($cacheDir);
			$cacheFile = "$cacheDir/$sqlHash";
			if (JFile::exists($cacheFile) &&	@filemtime($cacheFile) > $this->cacheExpiry) {
				$cacheFileContent = JFile::read($cacheFile);
				$this->_refTables = unserialize($cacheFileContent);

				if ($_JOOMFISH_MANAGER->getCfg("qalogging",0)){
					$this->_logSetRefTablecache("r",$tempsql,$sql_exNos,$sqlHash);
				}
		
				$pfunc = $this->_profile($pfunc);
	
				return;
			}

			if($this->_cursor===true || $this->_cursor===false) {
				if ($_JOOMFISH_MANAGER->getCfg("qalogging",0)){
					$this->_logSetRefTablecache("wtf",$tempsql,$sql_exNos,$sqlHash);
				}
				$this->fillRefTableCache($cacheDir,$cacheFile);
		
				$pfunc = $this->_profile($pfunc);

				return;
			}
		}

		// get column metadata
		$fields = $this->_getFieldCount();

		//print "<br> $tempsql $this->_cursor $fields";

		if ($_JOOMFISH_MANAGER->getCfg("qacaching",1) && $FTPOptions['enabled'] == 1){
			if ($fields<=0) {
				if ($_JOOMFISH_MANAGER->getCfg("qalogging",0)){
					$this->_logSetRefTablecache("w0f",$tempsql,$sql_exNos,$sqlHash);
				}
				$this->fillRefTableCache($cacheDir,$cacheFile);
		
				$pfunc = $this->_profile($pfunc);

				return;
			}
		}
		if ($fields<=0) {
		
			$pfunc = $this->_profile($pfunc);

			return;
		}
		
		$this->_refTables=array();
		$this->_refTables["fieldTablePairs"]=array();
		$this->_refTables["tableAliases"]=array();
		$this->_refTables["reverseTableAliases"]=array();
		$this->_refTables["fieldAliases"]=array();
		$this->_refTables["fieldTableAliasData"]=array();
		$this->_refTables["fieldCount"]=$fields;
		$this->_refTables["sql"]=$tempsql;
		// local variable to keep track of aliases that have already been analysed
		$tableAliases = array();
		for ($i = 0; $i < $fields; ++$i) {
			$meta = $this->_getFieldMetaData($i);
			if (!$meta) {
				echo "No information available<br />\n";
			}
			else {
				$tempTable =  $meta->table;
				// if I have already found the table alias no need to do it again!
				if (array_key_exists($tempTable,$tableAliases)){
					$value = $tableAliases[$tempTable];
				}
				// mysli only
				else if (isset($meta->orgtable)){
					$value = $meta->orgtable;
					if (isset($this->_table_prefix) && strlen($this->_table_prefix)>0 && strpos($meta->orgtable,$this->_table_prefix)===0) $value = substr($meta->orgtable, strlen( $this->_table_prefix));
					$tableAliases[$tempTable] = $value;
				}
				else {
					if (!isset($tempTable) || strlen($tempTable)==0) {
						continue;
					}
					//echo "<br>Information for column $i of ".($fields-1)." ".$meta->name." : $tempTable=";
					$tempArray=array();
					$prefix = $this->_table_prefix;
					preg_match_all("/`?$prefix(\w+)`?\s+(?:AS\s)?+`?".$tempTable."`?[,\s]/i",$this->_sql, $tempArray, PREG_PATTERN_ORDER);
					//preg_match_all("/`?$prefix(\w+)`?\s+AS\s+`?".$tempTable."`?[,\s]/i",$this->_sql, $tempArray, PREG_PATTERN_ORDER);
					if (count($tempArray)>1 && count($tempArray[1])>0) $value = $tempArray[1][0];
					else $value = null;
					if (isset($this->_table_prefix) && strlen($this->_table_prefix)>0 && strpos($tempTable,$this->_table_prefix)===0) $tempTable = substr($tempTable, strlen( $this->_table_prefix));
					$value = $value?$value:$tempTable;
					$tableAliases[$tempTable]=$value;
				}

				if ((!($value=="session" || strpos($value,"jf_")===0)) && $this->translatedContentAvailable($value)){
					/// ARGH !!! I must also look for aliases for fieldname !!
					if (isset($meta->orgname)){
						$nameValue = $meta->orgname;
					}
					else {
						$tempName = $meta->name;
						$tempArray=array();
						// This is a bad match when we have "SELECT id" at the start of the query
						preg_match_all("/`?(\w+)`?\s+(?:AS\s)?+`?".$tempName."`?[,\s]/i",$this->_sql, $tempArray, PREG_PATTERN_ORDER);
						//preg_match_all("/`?(\w+)`?\1s+AS\s+`?".$tempName."`?[,\s]/i",$this->_sql, $tempArray, PREG_PATTERN_ORDER);
						if (count($tempArray)>1 && count($tempArray[1])>0) {
							//echo "$meta->name is an alias for ".$tempArray[1][0]."<br>";
							// must ignore "SELECT id"
							if (strtolower($tempArray[1][0])=="select"){
								$nameValue = $meta->name;
							}
							else {
								$nameValue = $tempArray[1][0];
							}
						}
						else $nameValue = $meta->name;
					}
					
					if (!array_key_exists($value,$this->_refTables["tableAliases"])) $this->_refTables["tableAliases"][$value]=$meta->table;
					if (!array_key_exists($meta->table,$this->_refTables["reverseTableAliases"])) $this->_refTables["reverseTableAliases"][$meta->table]=$value;
					
					// I can't use the field name as the key since it may not be unique!
					if (!in_array($value,$this->_refTables["fieldTablePairs"])) $this->_refTables["fieldTablePairs"][]=$value;
					if (!array_key_exists($nameValue,$this->_refTables["fieldAliases"])) $this->_refTables["fieldAliases"][$meta->name]=$nameValue;

					// Put all the mapping data together so that everything is in sync and I can check fields vs aliases vs tables in one place
					$this->_refTables["fieldTableAliasData"][$i]=array("fieldNameAlias"=>$meta->name, "fieldName"=>$nameValue,"tableNameAlias"=>$meta->table,"tableName"=>$value);
					
				}

			}
		}
		if ($_JOOMFISH_MANAGER->getCfg("qacaching",1) && $fields>1 && $FTPOptions['enabled'] == 1){
			if ($_JOOMFISH_MANAGER->getCfg("qalogging",0)){
				$this->_logSetRefTablecache("wn",$tempsql,$sql_exNos,$sqlHash);
			}
			$this->fillRefTableCache($cacheDir,$cacheFile);
		}
		
		$pfunc = $this->_profile($pfunc);


	}
	
}
?>
