<?php
    //========================================================================================================================
    /**
     * DOMエレメントクラス
     *
     * LICENSE: This source file is subject to GNU GENERAL PUBLIC LICENSE Version 3
     * http://www.gnu.org/licenses/gpl-3.0.txt.
     *
     * @package    LabbitBox
     * @subpackage core
     * @copyright  2010 LabbitBox Development Team.
     * @license    GPL v3 http://www.gnu.org/licenses/gpl-3.0.txt
     * @author     neobaba <neobaba@labbitbox.org>
     * @version    v0.1
     * @since      2010/2/26
     * @link       http://labbitbox.org/
     * @see        http://labbitbox.org/
     */
    //========================================================================================================================
    class HtmlElement{
        //プロパティ
        public $id;
        
        protected $_elementID;
        private $_tagName;
        protected $_attrList    = array();
        protected $_styleList   = array();
        protected $_eventList   = array();

        //-------------------------------------------------------------------------------------------------------------------
        /**
         * コンストラクタ/デストラクタ
         *
         * @param string    $elementID  エレメントID
         * @param string    $tagName    HTMLタグ名(input,select等)
         * @param array     $attrList   属性値リスト(属性名=>値 の連想配列)
         */
        //-------------------------------------------------------------------------------------------------------------------
        public function __construct($elementID, $tagName, $attrList = array()){
            $this->id           = $elementID;
            $this->_elementID   = $elementID;
            $this->_tagName     = $tagName;
            $this->_attrList    = array_merge(array('style' => ''), (is_array($attrList) ? $attrList : array($attrList)));
        }
        
        //-------------------------------------------------------------------------------------------------------------------
        /**
         * テキストノード追加
         * @param string    $text  従属させるテキストノードの文字列  
         */
        //-------------------------------------------------------------------------------------------------------------------
        public function text($text){
            $this->attribute('TEXT_NODE', $text);
        }
        
        //-------------------------------------------------------------------------------------------------------------------
        /**
         * 属性追加
         * @param string    $attr   属性名：配列の場合は追加属性リスト（属性名=>値の連想配列）
         * @param string    $value  スタイル値
         */
        //-------------------------------------------------------------------------------------------------------------------
        public function attribute($attr, $value = NULL){
            $cExList    = array('selected', 'checked');
            
            if (is_array($attr)){
                $this->_attrList        = array_merge($this->_attrList, $attr);
            }
            else{
                if (in_array($attr, $cExList)){
                    if ($value === NULL || $value === true || $attr == $value){
                        $this->_attrList[$attr] = $attr;
                    }
                    else{
                        $this->_attrList[$attr] = FALSE;
                    }
                }
                else{
                    $this->_attrList[$attr] = $value;
                }
            }
        }

        //-------------------------------------------------------------------------------------------------------------------
        /**
         * スタイル追加
         *
         * @param string    $style  スタイル名：配列の場合は追加スタイルリスト（スタイル名=>値の連想配列）
         * @param string    $value  スタイル値
         */
        //-------------------------------------------------------------------------------------------------------------------
        public function style($style, $value = NULL){
            if (is_array($style)){
                $this->_styleList           = array_merge($this->_styleList, $style);
            }
            else{
                $this->_styleList[$style]   = $value;
            }
        }

        //---------------------------------------------------------------------------------------------
        /**
         * イベント追加
         */
        //---------------------------------------------------------------------------------------------
        public function __call($name, $params){
            //イベント動作モード
            if (substr($name, 0, strlen('onAjax')) == 'onAjax')
                $wMode  = 'A';  //Ajax
            elseif (substr($name, 0, strlen('onGridAjax')) == 'onGridAjax')
                $wMode  = 'G';  //Grid(Ajax)
            elseif (substr($name, 0, strlen('onHttp')) == 'onHttp')
                $wMode  = 'H';  //Http
            elseif (substr($name, 0, strlen('onGroupAjax')) == 'onGroupAjax')
                $wMode  = 'GA'; //グループAjax  2011/1/23:使用禁止
            elseif (substr($name, 0, strlen('onGroup')) == 'onGroup')
                $wMode  = 'GU'; //グループ汎用
            elseif (substr($name, 0, strlen('on')) == 'on')
                $wMode  = 'U';  //汎用
            else{
                die(sprintf('## Class "%s" has not method "%s" ##', get_class($this), $name));
            }

            //イベント追加
            $wTargetList    = array();
            $wServerList    = array();
            $wHandlerList   = array();
            $wGroupNames    = array();
            
            $wEventType     = $this->_getEventType($name);
            switch ($wMode){
                case 'A':   //Ajax
                case 'G':   //HtmlGrid(Ajax)
                case 'H':   //Http
                    $wTargetList    = (count($params) > 0 ? ($params[0] !== NULL ? $params[0] : array()) : array());
                    $wServerList    = (count($params) > 1 ? ($params[1] !== NULL ? $params[1] : array()) : array());
                    $wHandlerList   = (count($params) > 2 ? ($params[2] !== NULL ? $params[2] : array()) : array());
                    $this->_setDebugProc($name, $wEventType, $wHandlerList);
                    break;

                case 'U':   //汎用
                    $wHandlerList   = (count($params) > 0 ? array($wEventType => $params[0]) : array());
                    break;

                case 'GU':  //グループ汎用
                    $wGroupNames    = $this->_getGroupNames($params);
                    $wHandlerList   = (count($params) > 2 ? array($wEventType => $params[2]) : array());
                    break;
            
                //2011/1/23:使用禁止
                case 'GA':  //グループAjax
                    $wGroupNames    = $this->_getGroupNames($params);
                    $wHandlerList   = (count($params) > 2 ? array($wEventType => $params[2]) : array());
                    $this->_setDebugProc($name, $wEventType, $wHandlerList);
                    break;
            }
                    
            return $this->eventCommon($wMode, $wEventType, $wHandlerList, $wTargetList, $wServerList, $wGroupNames);
        }

        /**
         * イベントタイプ取得
         */
        private function _getEventType($name){
            $wEventType    = str_replace('onAjax',     '', $name);
            $wEventType    = str_replace('onGridAjax', '', $wEventType);
            $wEventType    = str_replace('onHttp',     '', $wEventType);
            $wEventType    = str_replace('onGroupAjax','', $wEventType);
            $wEventType    = str_replace('onGroup',    '', $wEventType);
            $wEventType    = str_replace('on',         '', $wEventType);
            $wEventType    = str_replace('_debugReq',  '', $wEventType);
            $wEventType    = str_replace('_debugRes',  '', $wEventType);
            $wEventType    = str_replace('_debugBoth', '', $wEventType);
            $wEventType    = strtolower($wEventType);
            return $wEventType;
        }

        /**
         * グループイベント情報取得
         */
        private function _getGroupNames($params){
            $wGroupPrefix   = (count($params) > 0 ? ($params[0] !== NULL ? $params[0] : '') : '');
            $wGroupSuffix   = (count($params) > 1 ? ($params[1] !== NULL ? $params[1] : '') : '');
            return array($wGroupPrefix, $wGroupSuffix);
        }

        /**
         * Ajaxデバッグ用処理
         */
        private function _setDebugProc($name, $eventType, &$handlerList){
            if (substr($name, strlen($name) - strlen('_debugReq'), strlen('_debugReq')) == '_debugReq'){
                $handlerList['debugRequest']    = $this->id.'_'.$eventType.'_'.'debugRequest';
            }
            if (substr($name, strlen($name) - strlen('_debugRes'), strlen('_debugRes')) == '_debugRes'){
                $handlerList['debugResponse']   = $this->id.'_'.$eventType.'_'.'debugResponse';
            }
            if (substr($name, strlen($name) - strlen('_debugBoth'), strlen('_debugBoth')) == '_debugBoth'){
                $handlerList['debugRequest']    = $this->id.'_'.$eventType.'_'.'debugRequest';
                $handlerList['debugResponse']   = $this->id.'_'.$eventType.'_'.'debugResponse';
            }
        }

        /**
         * イベント追加共通処理
         * @param string    $type           種類：'A'(Ajax用)/'U'(汎用)
         * @param string    $eventType      イベント種類
         * @param array     $targetList     Ajax送信対象エレメントの配列
         * @param array     $handlerList    イベントハンドラの連想配列（イベントポイント => イベントハンドラ）
         */
        public function eventCommon($type, $eventType, $handlerList = array(), $targetList = array(), $serverList = array(), $groupNames = array()){
            require_once(BASE_LIB.'/EventManager.php');
            
            $wEvent     = new Event($this->_elementID, $eventType, $type, $handlerList, $targetList, $serverList, $groupNames);
            $this->_eventList[] = $wEvent;
            return $wEvent;
        }

        //-------------------------------------------------------------------------------------------------------------------
        /**
         * イベントリスト取得
         * @return array    イベントオブジェクトリスト
         */
        //-------------------------------------------------------------------------------------------------------------------
        public function eventList(){
            return $this->_eventList;
        }

        //----------------------------------------------------------------------
        /**
         * イベント追加
         * @param object    $parent   親オブジェクト
         */
        //----------------------------------------------------------------------
        public function entryEvent($parent){
            foreach ($this->eventList() as $_event){
                $parent->getTopRegion()->eventManager()->addEvent($_event);
            }
        }

        //-------------------------------------------------------------------------------------------------------------------
        /**
         * HTMLエレメント取得
         * DOMエレメントのオブジェクトを取得する
         * @param object    $region   追加先Regionオブジェクト
         */
        //-------------------------------------------------------------------------------------------------------------------
        public function get($region){
            //テキストノード以外
            if ($this->_tagName != 'TEXT_NODE'){
                $element    = $region->doc()->createElement($this->_tagName);
            }
            //テキストノード('TEXT_NODE'は予約語)
            else{
                return  $region->doc()->createTextNode($this->_attrList[0]);
            }
            
            //属性セット
            $element->setAttribute('id', $this->_elementID);
            foreach($this->_attrList as $_name => $_value){
                switch ($_name){
                    //テキストノード('TEXT_NODE'は予約語)
                    case 'TEXT_NODE':
                        $wkTextNode = $region->doc()->createTextNode($_value);
                        $element->appendChild($wkTextNode);
                        break;
                        
                    //スタイル(タグにstyle属性を直書き)
                    case 'style':
                        if (count($this->_styleList) == 0){
                            $wkStyleText    = $_value;
                        }
                        else{
                            //生成時指定スタイルを配列に格納
                            $wkStyleList    = array();
                            $wkList         = explode(';', $_value);
                            foreach ($wkList as $_styleName => $_styleValue){
                                if ($_styleValue != ''){
                                    $wkStyle    = explode(':', $_styleValue);
                                    $wkStyleList[$wkStyle[0]]   = $wkStyle[1];
                                }
                            }
                        
                            //追加されたスタイルとマージ
                            $wkStyleList    = array_merge($wkStyleList, $this->_styleList);
                            
                            //スタイル値セット
                            $wkStyleText    = '';
                            foreach ($wkStyleList as $_styleName => $_styleValue){
                                $wkStyleText    .= $_styleName.':'.$_styleValue.';';
                            }
                        }
                        
                        //スタイルが空でなければ属性styleをセット
                        if ($wkStyleText !== ''){
                            $element->setAttribute('style', $wkStyleText);
                        }
                        break;
                        
                    default:
                        $element->setAttribute($_name, $_value);
                }
            }
            return $element;
        }
    }
    
    //========================================================================================================================
    /**
     * テキストノード
     *
     * DOMエレメントラッパークラス
     * 
     * LICENSE: This source file is subject to GNU GENERAL PUBLIC LICENSE Version 3
     * http://www.gnu.org/licenses/gpl-3.0.txt.
     *
     * @package    LabbitBox
     * @subpackage core
     * @copyright  2010 LabbitBox Development Team.
     * @license    GPL v3 http://www.gnu.org/licenses/gpl-3.0.txt
     * @author     neobaba <neobaba@labbitbox.org>
     * @version    v0.1
     * @since      2010/2/26
     * @link       http://labbitbox.org/
     * @see        http://labbitbox.org/
     */
    //========================================================================================================================
    class TextNode extends HtmlElement{
        public function __construct($text){
            parent::__construct(uniqid(substr($text, 0, 3)), 'TEXT_NODE', $text);
        }
    }
        
?>
