<?php
class MSSQLWinConnection extends Connection
{
	protected $host;

	protected $dbname;

	protected $user = "";

	protected $pwd = "";

	protected $options = "";

	protected $ODBCString;

	/**
	 * A date format string
	 * @type String
	 */
	protected $mssql_dmy;

	protected $errExeprionMess = "";


	function __construct( $params )
	{
		parent::__construct( $params );
	}

	/**
	 * Set db connection's properties
	 * @param Array params
	 */
	protected function assignConnectionParams( $params )
	{
		parent::assignConnectionParams( $params );

		$this->ODBCString = $params["ODBCString"];
		$this->host = $params["connInfo"][0]; 
		//	port number
		$this->host = str_replace( ':', ',', $this->host );
		$this->dbname = $params["connInfo"][3]; 

		if( $params["connInfo"][4] )
		{
			$this->options = 'SSPI';
		}
		else
		{
			$this->user = $params["connInfo"][1];
			$this->pwd = $params["connInfo"][2]; 
		}
	}

	/**
	 * Open a connection to db
	 */
	public function connect()
	{
		global $cCodePage;

		$connStrings = array();
		$savedString = $this->readConnString();
		if( $savedString )
			$connStrings[] = $savedString;

		$connStrings[] = $this->ODBCString;
		$providers = array( "MSOLEDBSQL", "SQLOLEDB", "SQLNCLI" );
		foreach( $providers as $p ) {
			if( $this->options == "SSPI" )
				$connStrings[] = "PROVIDER=".$p.";SERVER=".$this->host.";DATABASE=".$this->dbname.";Integrated Security=SSPI";
			else
				$connStrings[] = "PROVIDER=".$p.";SERVER=".$this->host.";UID=".$this->user.";PWD=".$this->pwd.";DATABASE=".$this->dbname;
		}
	//	go thru connection strings one by one
		$errorString = "";
		foreach($connStrings as $connStr)
		{
			try
			{
				$this->conn = new COM("ADODB.Connection", NULL, $cCodePage);
				$this->conn->Open( $connStr );
				$rs = $this->conn->Execute("select convert(datetime,'2000-11-22',121)");

				$str = $rs->Fields[0]->Value;
				$y = strpos($str, "2000");
				$m = strpos($str, "11");
				$d = strpos($str, "22");

				$this->mssql_dmy = "mdy";
				if( $y < $m && $m < $d )
					$this->mssql_dmy = "ymd";
				if( $d < $m && $m < $y )
					$this->mssql_dmy = "dmy";

				$this->saveConnString( $connStr );
				$this->conn->CommandTimeout = 120;
				return $this->conn;
			}
			catch(com_exception $e)
			{
				$errorString .= "<br>".$e->getMessage();
			}
		}
		$this->triggerError($errorString);
	}

	/**
	 * Close the db connection
	 */
	public function close()
	{
		$this->conn->Close();
	}

	/**
	 * Send an SQL query
	 * @param String sql
	 * @return Mixed
	 */
	public function query( $sql )
	{
		$this->debugInfo($sql);

		try
		{
			$qHandle = new COM("ADODB.Recordset", NULL, 65001 );
			$qHandle->CursorLocation = 3; // adUseClient
			$qHandle->Open( $sql, $this->conn, 3, 1 );
			return new QueryResult( $this, $qHandle );
		}
		catch(com_exception $e)
		{
			$this->triggerError($e->getMessage());
			return FALSE;
		}
	}

	/**
	 * Execute an SQL query
	 * @param String sql
	 */
	public function exec( $sql )
	{
		$this->debugInfo($sql);

		try
		{
			$qHandle = $this->conn->Execute( $sql );
			return new QueryResult( $this, $qHandle );
		}
		catch(com_exception $e)
		{
			$this->triggerError($e->getMessage());
			return FALSE;
		}
	}

	/**
	 * Get a description of the last error
	 * @return String
	 */
	public function lastError()
	{
		if( $this->conn->Errors->Count )
		{
			$errors = array();
			for( $i=0; $i < $this->conn->Errors->Count; ++$i ) {
				$errors[] = $this->conn->Errors[ $i ]->Description;
			}
			return implode( ' ', $errors );
		}

		return '';
	}

	/**
	 * Fetch a result row as an array
	 * @param Mixed qHanle		The query handle
	 * @param Number assoc (optional)
	 * @return Array
	 */
	protected function _fetch_array($qHandle, $assoc = 1)
	{
		$ret = array();

		if( $qHandle->EOF() )
			  return $ret;

		try {
			for( $i = 0; $i < $this->num_fields($qHandle); $i++ )
			{
				if( IsBinaryType( $qHandle->Fields[$i]->Type ) && $qHandle->Fields[$i]->Type != 128 )
				{
					$str = "";
					if( $qHandle->Fields[$i]->ActualSize )
					{
						$val = $qHandle->Fields[$i]->GetChunk( $qHandle->Fields[$i]->ActualSize );
						$str = str_pad("", count($val));
						$j = 0;
						foreach($val as $byte)
						{
							$str[ $j++ ] = chr($byte);
						}
					}

					if( $assoc )
						$ret[ $qHandle->Fields[$i]->Name ] = $str;
					else
						$ret[ $i ] = $str;
				}
				else
				{
					$value = $qHandle->Fields[$i]->Value;
					if( is_null($value) )
						$val = NULL;
					else
					{
						if( isdatefieldtype($qHandle->Fields[$i]->Type) )
							$value = localdatetime2db( (string)$qHandle->Fields[$i]->Value, $this->mssql_dmy );
						if( IsNumberType($qHandle->Fields[$i]->Type) )
							$val = floatval($value);
						else
							$val = strval($value);
					}
					if( $assoc )
						$ret[ $qHandle->Fields[$i]->Name ] = $val;
					else
						$ret[ $i ] = $val;
				}
			}
			$qHandle->MoveNext();
		}
		catch(com_exception $e)
		{
			$this->triggerError( $e->getMessage() );
		}

		return $ret;
	}

	/**
	 * Fetch a result row as an associative array
	 * @param Mixed qHanle		The query handle
	 * @return Array
	 */
	public function fetch_array( $qHandle )
	{
		return $this->_fetch_array( $qHandle );
	}

	/**
	 * Fetch a result row as a numeric array
	 * @param Mixed qHanle		The query handle
	 * @return Array
	 */
	public function fetch_numarray( $qHandle )
	{
		return $this->_fetch_array( $qHandle, 0 );
	}

	/**
	 * Free resources associated with a query result set
	 * @param Mixed qHanle		The query handle
	 */
	public function closeQuery( $qHandle )
	{
		$qHandle->Close();
	}

	/**
	 * Get number of fields in a result
	 * @param Mixed qHanle		The query handle
	 * @return Number
	 */
	public function num_fields( $qHandle )
	{
		return $qHandle->Fields->Count;
	}

	/**
	 * Get the name of the specified field in a result
	 * @param Mixed qHanle		The query handle
	 * @param Number offset
	 * @return String
	 */
	public function field_name( $qHandle, $offset )
	{
		return $qHandle->Fields($offset)->Name;
	}

	/**
	 * @param Mixed qHandle
	 * @param Number pageSize
	 * @param Number page
	 */
	public function seekRecord($qHandle, $n)
	{
		if( !$n )
			return;

		if( $qHandle->EOF() )
			return;

	   $qHandle->Move( $n );
	}

	/**
	 * Execute an SQL query with blob fields processing
	 * @param String sql
	 * @param Array blobs
	 * @param Array blobTypes
	 * @return Boolean
	 */
	public function execWithBlobProcessing( $sql, $blobs, $blobTypes = array(), $autoincField = null )
	{
		$this->debugInfo($sql);

		try
		{
			$this->conn->Execute( $sql );
			return true;
		}
		catch(com_exception $e)
		{
			$this->errExeprionMess = $e->getMessage();
			return false;
		}
	}
}
?>