<?php

abstract class Atmail_Update_Abstract
{
	public $dbAdapter;
	public	$originalVersion;
	public	$currentVersion;
	public 	$localCodeBase;
	public $logFile;	// log file in use for tracking output / debug
	public $myKeyname;
	
	public function __construct(&$dbAdapter)
	{
		$this->dbAdapter = $dbAdapter;
		$this->myKeyname = 'version';
		$this->originalVersion = $this->currentVersion = generateVersionString($this->dbAdapter->fetchOne("select keyValue from Config where keyName = 'version'"), true);
		$this->localCodeBase = generateVersionString(getVersionCurrentLocalCodebase(), true);
		$this->setLogFile(false);
	}
	
	public function getAdminEmail()
	{
		return $this->dbAdapter->fetchOne("select keyValue from Config where keyName = 'admin_email'");
	}
	
	public function setKeyname($keyname)
	{
		$this->myKeyname = $keyname;
		$this->originalVersion = $this->currentVersion = generateVersionString($this->dbAdapter->fetchOne("select keyValue from Config where keyName = '" . $this->myKeyname . "'"), true);	
	}
	/*********************************** LOGGING FUNCTIONS *************************************/
	public function log($str, $append = true)
	{
		if($this->logFile !== false)
		{
			file_put_contents($this->logFile, ($append ? file_get_contents($this->logFile) : '') . $str . "\n");
		}
	}
	
	public function setLogFile($filename)
	{
		$this->logFile = $filename;
		$this->log("Atmail Update Log\n--------------------------------", false);
	}
	
	public function getLogFile()
	{
		return $this->logFile;	
	}
	
	/************************************* UPDATE FUNCTIONS ***************************************/
	function pre_update()
	{
		$this->dbAdapter->beginTransaction();
	}

	function post_update($version)
	{
		$this->dbAdapter->update('Config', array('keyValue' => $version), "section = 'global' AND keyName = '" . $this->myKeyname . "'");
		$this->currentVersion = $version;
		$this->dbAdapter->commit();
	}
	
	function update($version)
	{
		$result = false;
		if (version_compare($this->currentVersion, $version, '<'))
		{
			$methodname = str_replace('.', "_", "_" . generateVersionString($version, true) );
			$this->log("Attempting update from " . $this->currentVersion . " to " . $version);
			$this->pre_update();
			try
			{
				if(method_exists($this, $methodname))
				{
					$this->$methodname();
				}
				$result = method_exists('Atmail_Update_Cli', $methodname );
				$this->post_update($version);
			}
			catch(Exception $e)
			{
				// oh no, something is wrong
				$this->log("");
				$this->log("***********************************");
				$this->log("************* ERROR ***************");
				$this->log("During update for " . $version . "\n" . "Details : " . $e->getMessage());
				$this->log("A copy of this log can be found at : " . $this->getLogFile()); 
				// throw the same exception
				throw $e;		
			}
			$this->log("Update complete for " . $version);
		}
		return $result;
	}
	
	function filterVersions($versions)
	{
		return $versions;	
	}
	
	function updateAll()
	{
		$result = false;
		$versions = $this->filterVersions(Atmail_Update_Versions::$versions);
		$this->log("Updating from " . $this->currentVersion . " to " . $this->localCodeBase);

		foreach($versions as $versionCheckpoint)
		{
			$versionCheckpoint = generateVersionString($versionCheckpoint, true);
			if( version_compare($this->currentVersion, $versionCheckpoint, '<'))
			{
				$this->log("Found update for " . $versionCheckpoint);
				$result |= $this->update($versionCheckpoint);
			}
		}
		$this->pre_update();
		$this->post_update($this->localCodeBase);
		return $result;
	}
	
	// tests if an update is available for the class
	public function isUpdateAvailable($testVersion = false)
	{
        return false;
		$testVersion = ($testVersion === false ? generateVersionString(Zend_Registry::get('config')->global[$this->myKeyname], true) : $testVersion);
		if($testVersion != '' && $testVersion != generateVersionString(getVersionCurrentLocalCodebase(), true))
		{
			// our version string indicates that a new version is available.
			// lets search ask the update class to see if there is any updates to run
			foreach(Atmail_Update_Versions::$versions as $version)
			{
				if (version_compare($testVersion, $version, '<'))
				{
					$methodname = str_replace('.', "_", "_" . generateVersionString($version, true) );
					if(method_exists($this, $methodname))
					{
						return true;
					}
				}
			}
		}
		return false;
	}
	
	
	/****************************************** DB HELPER FUNCTIONS **********************************************/
	/**
	 * Try a query, wrap in an exception, to avoid an error
	 *
	 */
	public function exceptionQuery($sql)
	{
		try
		{
			$this->dbAdapter->query($sql);
		}
		catch (Exception $e)
		{
			$this->log("Query failed: $sql\nReason: " . $e->getMessage() . "\n");
            // dont throw an error
			// throw $e;
		}
	}

	public function ignorableQuery($sql)
	{
		try
		{
			$this->dbAdapter->query($sql);
		}
		catch (Exception $e)
		{
			$this->log("Query failed: $sql\nReason: " . $e->getMessage() . "\n");
		}
	}
	
	public function testConfig($section, $keyName, $keyValue, $testSql = '')
	{
		if ($testSql == '')
		{
			$testSql = 'select keyValue from Config where ';
		}

		$extra = array();
		if ( $section != null)
			$extra[] =  'section = "' . $section . '"';
		if ( $keyName != null)
			$extra[] =  'keyName = "' . $keyName . '"';
		if ( $keyValue != null)
			$extra[] =  'keyValue = "' . $keyValue . '"';

		if (!count($extra))
			return false;
			
		$testSql .= join(" and ", $extra);
			
		try
		{
			$row = $this->dbAdapter->fetchOne($testSql);
		}
		catch (Exception $e)
		{
		}
		
		return ($row != "");
	}

	public function updateConfig($section, $keyName, $keyValue, $keyType, $testSql = '')
	{
		return $this->insertConfig($section, $keyName, $keyValue, $keyType, $testSql);
	}

    public function insertConfig($section, $keyName, $keyValue, $keyType, $testSql = '')
    {
        return $this->changeConfig($section, $keyName, $keyValue, $keyType, $testSql, true);
    }

	public function changeConfig($section, $keyName, $keyValue, $keyType, $testSql = '', $update = false)
	{
		if ($testSql == '')
		{
			$testSql = 'select keyValue from Config where keyName="' . $keyName . '"';
		}

		try
		{
			$row = $this->dbAdapter->fetchOne($testSql);
			if ($row === false)
			{
				if ($keyType == 'Integer')
				{
					$this->exceptionQuery('insert into Config (section, keyName, keyValue, keyType) values ("' . $section . '", "' . $keyName . '", ' . $keyValue . ', "' . $keyType . '")');
				}
				else
				{
					$this->exceptionQuery('insert into Config (section, keyName, keyValue, keyType) values ("' . $section . '", "' . $keyName . '", "' . $keyValue . '", "' . $keyType . '")');
				}
			}
			else if ($update)
			{
				if ($keyType == 'Integer' || $keyType == 'Boolean')
				{
					$this->exceptionQuery('update Config set keyValue = ' . $keyValue . ' where section = "' . $section . '" and keyName = "' . $keyName . '"');
				}
				else
				{
					$this->exceptionQuery('update Config set keyValue = "' . $keyValue . '" where section = "' . $section . '" and keyName = "' . $keyName . '"');
				}
			}
		}
		catch (Exception $e)
		{
			$this->log("Failed to update/insert (" . $section . ", ". $keyName . ", " . $keyValue . ", " . $keyType . ") into Config table.");
			throw $e;
		}
	}

	public function fieldExists($tablename, $fieldname)
	{
		$describeUserSettings = $this->dbAdapter->query('DESCRIBE `' . $tablename . '`')->fetchAll();
		$found = false;
		foreach ($describeUserSettings as $field)
		{
			if ($field['Field'] == $fieldname)
			{
				$found = true;
				break;
			}
		}

		return $found;
	}
}

