<?php

/**
* デフォルトのSQLビルダ
*
* PHP version 5
*
* @package    sql_builders
* @author     stk2k <stk2k@sazysoft.com>
* @copyright  2008 stk2k, sazysoft
*/
abstract class DefaultSQLBuilder extends CharcoalComponent implements ISQLBuilder
{
	private $_type_mapping;

	/*
	 *	コンストラクタ
	 */
	public function __construct( String $name = NULL )
	{
		parent::__construct(s($name));
	}

	/**
	 *  SQLビルダを初期化
	 */
	public function init( Config $config )
	{
		$this->_type_mapping = $config->getArray( s('type_mappings') );
	}

	/*
	 * SQLビルダ名を取得
	 */
	public function getSQLBuilderName()
	{
		return "default SQL builder";
	}

	/*
	 * タイプマッピング
	 */
	public function mapType( $type_name )
	{
		return isset($this->_type_mapping[$type_name]) ? $this->_type_mapping[$type_name] : $type_name;
	}

	/*
	 *	SQL作成(SELECT)
	 */
	public  function buildSelectSQL( ITableModel $model, SQLCriteria $criteria = NULL )
	{
		$table = $model->getTableName();

		$sql = "select * from $table";

		if ( !$criteria ){
			return $sql;
		}

		$where_clause = $criteria->getWhereClause();
		$order_by     = $criteria->getOrderBy();
		$limit        = $criteria->getLimit();
		$offset       = $criteria->getOffset();

		if ( $where_clause != NULL ){
			$sql .= " where $where_clause";
		}
		if ( $order_by != NULL ){
			$sql .= " order by $order_by";
		}
		if ( $limit != NULL ){
			$sql .= " limit $limit";
		}
		if ( $offset != NULL ){
			$sql .= " offset $offset";
		}
	
		return $sql;
	}

	/*
	 *	SQL作成(UPDATE)
	 */
	public  function buildUpdateSQL( ITableModel $model, DTO $dto )
	{
		try{
			$SQL_params      = array();
			$SQL_set         = array();
			$SQL_key_fields  = array();

			$field_list = $model->getFieldList();

			foreach( $field_list as $name ) 
			{
				$update = $model->getAnnotation( s($name), s('update') );

				if ( !$update ){
					// 無指定の場合エラー
					_throw( new TableModelException( $model, $name, '[@update] annotation is required' ) );
				}

				// キーフィールドのチェック
				$pk = $model->getAnnotation( s($name), s('pk') );
				if ( $pk ){
					// キーフィールドなので更新しない
					$SQL_key_fields[ $name ] = $dto->getProperty( s($name) );
					continue;
				}

				// @updateアノテーションの値によって分岐
				switch ( $update->getValue() ){
				case 'value':
					// 値で更新
					$SQL_set[] = "$name = ?";
					// パラメータを追加
					$SQL_params[] = $dto->getProperty( s($name) );
					break;
				case 'function':
					// 関数を決定
					switch( $update->getParameter() ){
					case 'now':		$function = 'NOW()';	break;
					default:        $function = 'NULL';		break;
					}
					// 関数で更新
					$SQL_set[] = "$name = $function";
					break;
				case 'no':
					// 更新しない
					break;
				default:
					_throw( new TableModelException( $model, $name, '[@update] value is invalid' ) );
				}
			}

			// WHERE句
			$SQL_where = array();
			foreach( $SQL_key_fields as $name => $value )
			{
				// ステートメントを追加
				$SQL_where[] = "$name = ?";
				// パラメータを追加
				$SQL_params[] = $value;
			}

			$SQL_set    = implode( ',', $SQL_set );
			$SQL_where  = implode( ',', $SQL_where );

			$table = $model->getTableName();

			$sql = "update $table set $SQL_set where $SQL_where";

			return array( $sql, $SQL_params );
		}
		catch ( Exception $e )
		{
			_throw( new SQLBuilderException( "DefaultSQLBuilder#buildUpdateSQL failed" ) );
		}
	}

	/*
	 *	SQL作成(INSERT)
	 */
	public  function buildInsertSQL( ITableModel $model, DTO $dto )
	{
		try{
			$SQL_field_list   = NULL;
			$SQL_value_list   = NULL;
			$SQL_params       = array();

			$field_list = $model->getFieldList();

			foreach( $field_list as $name ) 
			{
				$insert = $model->getAnnotation( s($name), s('insert') );

				if ( !$insert ){
					// 無指定の場合エラー
					_throw( new TableModelException( $model, $name, '[@insert] annotation is required' ) );
				}

				// @insertアノテーションの値によって分岐
				switch ( $insert->getValue() ){
				case 'value':
					// 値で更新
					$SQL_field_list[] = $name;
					$SQL_value_list[] = '?';
					// パラメータを追加
					$SQL_params[] = $dto->getProperty( s($name) );
					break;
				case 'function':
					// 関数を決定
					switch( $insert->getParameter() ){
					case 'now':		$function = 'NOW()';	break;
					default:        $function = 'NULL';		break;
					}
					// 関数で更新
					$SQL_field_list[] = $name;
					$SQL_value_list[] = $function;
					break;
				case 'no':
					// 更新しない
					break;
				default:
					_throw( new TableModelException( $model, $name, '[@insert] value is invalid' ) );
				}
			}

			$SQL_field_list = implode( ',', $SQL_field_list );
			$SQL_value_list = implode( ',', $SQL_value_list );

			$table = $model->getTableName();

			$sql = "insert into $table($SQL_field_list) values($SQL_value_list)";

			return array( $sql, $SQL_params );
		}
		catch ( Exception $e )
		{
			_throw( new SQLBuilderException( "DefaultSQLBuilder#buildInsertSQL failed" ) );
		}
	}

	/*
	 *	SQL作成(count)
	 */
	public  function buildCountSQL( ITableModel $model, SQLCriteria $criteria = NULL )
	{
		$table_name = $model->getTableName();

		$sql = "select count(*) from $table_name";

		if ( $criteria && $criteria->getWhereClause() ){
			$where_clause = $criteria->getWhereClause();
			$sql .= " where $where_clause";
		}

		return $sql;
	}

	/*
	 *	SQL作成(max)
	 */
	public  function buildMaxSQL( ITableModel $model, String $field, SQLCriteria $criteria = NULL )
	{
		$table_name = $model->getTableName();

		$sql = "select max($field) from $table_name";

		if ( $criteria && $criteria->getWhereClause() ){
			$where_clause = $criteria->getWhereClause();
			$sql .= " where $where_clause";
		}

		return $sql;
	}

	/*
	 *	SQL作成(DELETE)
	 */
	public  function buildDeleteSQL( ITableModel $model, SQLCriteria $criteria = NULL )
	{
		$table_name = $model->getTableName();

		$sql = "delete from $table_name";

		if ( !$criteria ){
			return $sql;
		}

		$where_clause = $criteria->getWhereClause();
		$limit        = $criteria->getLimit();
		$offset       = $criteria->getOffset();

		if ( $where_clause != NULL ){
			$sql .= " where $where_clause";
		}
		if ( $limit != NULL ){
			$sql .= " limit $limit";
		}
		if ( $offset != NULL ){
			$sql .= " offset $offset";
		}
	
		return $sql;
	}

}

return __FILE__;