<?php

/**
* デフォルトのSQLビルダ
*
* PHP version 5
*
* @package    components.db
* @author     stk2k <stk2k@sazysoft.com>
* @copyright  2008 stk2k, sazysoft
*/
abstract class charcoal_DefaultSQLBuilder implements charcoal_ISQLBuilder
{
	private $_type_mapping;

	/*
	 *	コンストラクタ
	 */
	public function __construct()
	{
	}

	/**
	 *  SQLビルダを初期化
	 */
	public function init( charcoal_Config $config )
	{
		$this->_type_mapping = $config->getArray( '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( charcoal_ITableModel $model, charcoal_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( charcoal_ITableModel $model, charcoal_DTO $dto )
	{
		$SQL_params      = array();
		$SQL_set         = array();
		$SQL_key_fields  = array();

		$field_list = $model->getFieldList();

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

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

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

			// @updateアノテーションの値によって分岐
			switch ( $update->getValue() ){
			case 'value':
				// 値で更新
				$SQL_set[] = "$name = ?";
				// パラメータを追加
				$SQL_params[] = $dto->get( $name );
				break;
			case 'function':
				// 関数を決定
				switch( $insert->getParameter() ){
				case 'now':		$function = 'NOW()';	break;
				default:        $function = 'NULL';		break;
				}
				// 関数で更新
				$SQL_set[] = "$name = $function";
				break;
			case 'no':
				// 更新しない
				break;
			default:
				throw new charcoal_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 );
	}

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

		$field_list = $model->getFieldList();

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

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

			// @insertアノテーションの値によって分岐
			switch ( $insert->getValue() ){
			case 'value':
				// 値で更新
				$SQL_field_list[] = $name;
				$SQL_value_list[] = '?';
				// パラメータを追加
				$SQL_params[] = $dto->get( $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 charcoal_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 );
	}

	/*
	 *	SQL作成(count)
	 */
	public  function buildCountSQL( charcoal_ITableModel $model, charcoal_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( charcoal_ITableModel $model, $field_name, charcoal_SQLCriteria $criteria = NULL )
	{
		$table_name = $model->getTableName();

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

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

		return $sql;
	}

	/*
	 *	SQL作成(DELETE)
	 */
	public  function buildDeleteSQL( charcoal_ITableModel $model, charcoal_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;
	}

}
