<?php
require_once 'Zend/Db/Table/Abstract.php';

abstract class Bullhead_Db_Table_Abstract extends Zend_Db_Table_Abstract
{
    /**
     * 検索条件のAND接続句
     * @see
     */
    const CRITERIA_AND = 'and';
    
    /**
     * 検索条件のOR接続句
     * @see 
     */
    const CRITERIA_OR  = 'or';
    
    /**
     * アクセスするテーブル名
     * @see Zend_Db_Table_Abstract::$_name
     */
    protected $_name;
    
    /**
     * アクセスするテーブルの主キーカラム名
     */
    protected $_primary;
    
    /**
     * デフォルトのソート順
     */
    protected $_order;
    
    /**
     * デフォルトのデータ取得オフセット値
     */
    protected $_offset = 0;
    
    /**
     * デフォルトのデータ取得数
     */
    protected $_count = 0;
    
    /**
     * デフォルトの検索（付加）条件
     */
    protected $_criteria;
    
    /**
     * デフォルトの検索クエリ
     */
    protected $_select;
    
    /**
     * ログ出力インスタンス
     * @var Bullhead_Log
     */
    protected $_logger;
    
    /**
     * Configインスタンス
     */
    protected $_config;
    
    /**
     * 行を追加する
     * 
     * @access public
     * @param mixed $values 追加する行データ
     * @return integer $id 保存された行のIDを返す
     */
    public function create($values)
    {
        $rowset = $this->createRow($values);
        $id = $rowset->save();
        
        return $id;
    }
    
    /**
     * 行を取得する
     * 
     * @access public
     * @param integer $id 取得するデータの主キーの値
     * @param string $order 取得するデータのソート順
     * @param integer $offset 取得するデータのオフセット値
     * @param integer $count 取得するデータ数
     * @param mixed $criteria 検索条件
     * @return 取得した行データを連想配列で返す
     */
    public function read($id=null, $order=null)
    {
//        $rowset = $this->getRowset($id, $order);
//        return $rowset->toArray();
    }
    
    /**
     * 行を更新する
     * 
     * @access public
     * @param mixed $values 更新する行データ
     * @param mixed $criteria 更新する行を特定する付加条件
     * @return integer $id 保存された行のIDを返す
     */
    public function update($values, $criteria=null){
        $db = $this->getAdapter();
        $where = array();
        
        if (isset($values[$this->_primary[1]])) {
            $where[] = $db->quoteInto($this->_primary[1] . '=?', $values[$this->_primary[1]]);
        }
        
        if (!empty($criteria) && is_array($criteria)) {
            foreach ($criteria as $key => $value) {
                $where[] = $db->quoteInto($key . '=?', $value);
            }
        } else {
            $where[] = $db->quoteInto($criteria);
        }
        
        $db->update($this->_name, $values, $where);
    }
    
    /**
     * 行を削除する
     * 
     * @access public
     * @param integer $id 削除する行の主キーの値
     * @param mixed $criteria 削除する行を特定する付加条件
     */
    public function delete($id, $criteria=null){
        $db = $this->getAdapter();
        $where = array();
        
        if ($id != null) {
            $where[] = $db->quoteInto($this->_primary[1] . '=?', $id);
        }
        
        if (!empty($criteria)) {
            foreach ((array) $criteria as $key => $value) {
                $where[] = $db->quoteInto($key . '=?', $value);
            }
        }
        $db->delete($this->_name, $where);
    }
    
    /**
     * テーブルの全レコード件数を取得する
     * 
     * @access public 
     * @return integer $result レコード件数を返す
     */
    public function getTableDataSize()
    {
        $select = empty($this->_select) ? $this->select() : $this->_select;
        $select->from($this, 'count(*)');
        $result = $this->getAdapter()->fetchOne($select);
        
        return $result;
    }
    
    /**
     * 指定された値から行の追加or更新を判別して実行する
     * 
     * @access public
     * @param mixed $valus 追加or更新する行データ
     * 
     */
    public function save($values)
    {
        $id = isset($values[$this->_primary[1]]) ? intval($values[$this->_primary[1]]) : null;
        
        $data = $this->read($id);
        if (!empty($id) && count($data) == 1) {
            $this->update($values);
        } else {
            $this->create($values);
        }
    }

    /**
     * 指定したカラムをKEY,VALUEとする連想配列を取得する
     * 
     * @access public
     * @param string $key KEY値とするカラム名（指定しない場合は主キー）
     * @param string $value VALUE値とするカラム名（指定しない場合はNAME値）
     * @param string $order ソート順
     * @return arrray 連想配列を返す
     */
    public function getOptions($key=null, $value=null, $order=null)
    {
        if(empty($key)) $key = $this->_primary[1];
        if(empty($value)) $value = 'name';
        if(empty($order)) $order = $this->_primary[1];
        
        $db = $this->getAdapter();
        $select = $db->select()
                ->from($this->_name, array($key, $value))
                ->order($order)
        ;
        
        $options = $db->fetchPairs($select);
        return $options;
    }
    
    /**
     * ログ出力インスタンスを設定する
     * 
     * @param Zend_Log $logger
     */
    public function setLogger($logger)
    {
        $this->_logger = $logger;
    }
    
    /**
     * Configインスタンスを設定する
     */
    public function setConfig($config)
    {
        $this->_config = $config;
    }
    
    /** Local Method **/
    
    /**
     * 指定の検索条件で検索結果（ROWSETオブジェクト）を取得する
     * 
     * @access protected
     * @param integer $id 取得するデータの主キーの値
     * @param string $order 取得するデータのソート順
     * @param integer $offset 取得するデータのオフセット値
     * @param integer $count 取得するデータ数
     * @param mixed $criteria 検索条件
     * @return Zend_Db_Table_Rowset 取得した行データをROWSETオブジェクトで返す
     */
    protected function getRowset($id=null, $order=null)
    {
        if (!is_array($id) && intval($id) > 0) {
            $select->where($this->_primary[1] . '=?', $id);
        } else if(is_array($id)) {
            foreach ($id as $value) {
                $select->orWhere($this->_primary[1] . '=?', $value);
            }
        }
        
        if ($count == null)  $count  = $this->_count;
        if ($offset == null) $offset = $this->_offset;
        $select->limit($count, $offset);
        
        $select = $this->_setupCriteria($select, $this->_criteria);
        $select = $this->_setupCriteria($select, $criteria);
        
        if (!empty($this->_logger)) $this->_logger->info($select->__toString());
        
        return $this->fetchAll($select);
    }
    
    /**
     * ソート順を設定する
     * 
     * @access 
     * @param Zend_DB_Select $select SELECTオブジェクト
     * @return Zend_DB_Selec ソート順を設定したSELECTオブジェクトを返す
     */
    protected function _setupOrder($select, $order)
    {
        if (!empty($order)) {
            if (is_array($this->_order)) {
                $select->order($order[0] . " " . $order[1]);
            } else {
                $select->order($order);    
            }
        } else {
            $select->order($this->_primary[1]);
        }
        return $select;
    }
    
    /**
     * 検索（付加）条件を設定する
     * 
     * @param Zend_DB_Select $select SELECTオブジェクト
     * @return Zend_DB_Selec ソート順を設定したSELECTオブジェクトを返す
     */
    protected function _setupCriteria($select, $criteria)
    {
        if (!empty($criteria) && is_array($criteria)) {
            foreach ($criteria as $key => $value) {
                if (self::CRITERIA_AND == $key) {
                    $select->where($value);
                } elseif (self::CRITERIA_OR == $key) {
                    $select->orWhere($value);
                }
            }
        } elseif (!empty($criteria)) {
            $select->where($criteria);
        }
        return $select;
    }
    
    /**
     * デフォルトの検索クエリを設定する
     * 
     * @param Zend_Db_Select $select SELECTオブジェクト
     */
    protected function _setDefaultSelectQuery($select)
    {
        $this->_select = $select;
    }
}
?>
