<?php
/**
* デフォルトのテーブルモデル実装
*
* PHP version 5
*
* @package    components.db
* @author     stk2k <stk2k@sazysoft.com>
* @copyright  2008 stk2k, sazysoft
*/
class DefaultTableModel implements ITableModel
{
	private $_model_id;
	private $_class_name;
	private $_class_vars;
	private $_annotations;

	/*
	 *	コンストラクタ
	 */
	public function __construct()
	{
		$this->_model_id    = NULL;
		$this->_class_name  = get_class($this);
		$this->_class_vars  = get_class_vars($this->_class_name);

		$this->_annotation_list = array();
		foreach( $this->_class_vars as $key => $var ){
			$this->_annotations[$key] = AnnotationUtil::parse( $key, $var );
		}
	}

	/**
	 * モデルIDを設定
	 */
	public function setModelID( $model_id )
	{
		$this->_model_id = $model_id;
	}

	/**
	 * モデルIDを取得
	 */
	public function getModelID()
	{
		return $this->_model_id;
	}

	/*
	 *	テーブル名を取得
	 */
	public function getTableName()
	{
		if ( property_exists($this,'___table_name') ){
			$table_name = $this->___table_name;
		}
		else{
			$table_name = $this->_class_name;
		}
		return $table_name;
	}

	/*
	 *   プライマリキーフィールド名を取得
	 */
	public function getPrimaryKey()
	{
		$field_list = $this->getFieldList();

		foreach( $field_list as $field ){
			$annot_map = $this->getAnnotationMap( $field );
			if ( isset($annot_map['pk']) ){
				// @pkが指定されていたら外部キー
				return $field;
			}
		}

		throw new TableModelException( $this, NULL, 'no primary key' );
	}

	/*
	 *   外部キーフィールド名を取得
	 */
	public function getForeignKey( $model_name )
	{
		$field_list = $this->getFieldList();

		foreach( $field_list as $field ){
			$annot_map = $this->getAnnotationMap( $field );
			if ( isset($annot_map['fk']) ){
				// @fkが指定されていたら外部キー
				$fk = $annot_map[ 'fk' ];
				if ( $fk->getValue() === $model_name ){
					return $field;
				}
			}
		}

		throw new TableModelException( $this, NULL, "no foreign key for:$model_name" );
	}

	/*
	 *   展開フィールドを取得
	 */
	public function getExtractField( $model_name, $field )
	{
		$extract_list = $this->getExtractFieldList();

		foreach( $extract_list as $extract ){
			// @source:model_name/fieldを検索
			$annot = $this->getAnnotation( $extract, 'source' );
			if ( $annot && $annot->getValue() === "$model_name/$field" ){
				return $extract;
			}
		}

		return NULL;
	}

	/*
	 *   関連一覧を取得
	 */
	public function getRelationList()
	{
		$result = array();

		$annotations = $this->_annotations;
		if ( $annotations ){
			foreach( $annotations as $field => $annot_list ){
				foreach( $annot_list as $annot ){
					// @relationが指定されていたら関連
					if ( $annot && $annot->getName() === 'relation' && $annot->getValue() === NULL ){
						$result[] = $field;
					}
				}
			}
		}

		return $result;
	}

	/**
	 * フィールドが存在するか
	 */
	public function fieldExists( $field_name )
	{
		return isset($this->_class_vars[$field_name]);
	}

	/*
	 *   属性一覧を取得
	 */
	private function getAttributeList( $name, $value )
	{
		$result = array();

		$annotations = $this->_annotations;
		if ( $annotations ){
			foreach( $annotations as $attr => $annot_list ){
				foreach( $annot_list as $annot ){
					// 属性の条件判定
					if ( $annot && $annot->getName() === $name && $annot->getValue() === $value ){
						$result[] = $attr;
					}
				}
			}
		}

		return $result;
	}

	/*
	 *   フィールド一覧を取得
	 */
	public function getFieldList()
	{
		return $this->getAttributeList( 'field', NULL );
	}
	/*
	 *   展開フィールド一覧を取得
	 */
	public function getExtractFieldList()
	{
		return $this->getAttributeList( 'extract', NULL );
	}

	/*
	 *   アノテーションを取得
	 */
	public function getAnnotation( $field, $annotation_name )
	{
		$annot_map = $this->getAnnotationMap( $field );
		if ( is_null($annot_map) || !isset($annot_map[$annotation_name]) ){
			return NULL;
		}
		return $annot_map[$annotation_name];
	}

	/*
	 *   指定したフィールドのアノテーションマップを取得
	 */
	public function getAnnotationMap( $field )
	{
		if ( !isset($this->_annotations[$field]) ){
			return NULL;
		}
		return $this->_annotations[$field];
	}

	/*
	 *   アノテーション設定値を取得
	 */
	public function getAnnotationValue( $field, $annotation_name, $defaultValue = NULL )
	{
		$annot = $this->getAnnotation( $field, $annotation_name );

		return $annot ? $annot->getValue() : $defaultValue;
	}

	/*
	 *   文字列化
	 */
	public function __toString()
	{
		return "[TableModel:" . get_class($this) . "]";
	}

}
