<?php
    //========================================================================================================================
    /**
     * サイトマップ情報クラス
     *
     * 設定ファイル格納ディレクトリ内のstructure.xmlを取得しアクセス可能にする
     *
     * 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 alpha3
     * @since      -
     * @link       http://labbitbox.org/
     * @see        http://labbitbox.org/
     *
     *------------------------------------------------------------------------------------------------------------------------
     * 〔sitemap.xml の標準的な形式例〕
     * BASE_CONFディレクトリ内に格納されたファイルを下記の順序とルールで読み込む
     *
     * <level id="L100000" title="マイページ" action="ACTION_NAME">
     *     <request>
     *          <url>http://www.labbitbox.org/index.php</url>
     *          <action>ACTION_NAME</action>
     *          <method></method>
     *          <params>
     *              <user_id></user_id>
     *              <xx_no></xx_no>
     *          </params>
     *      </request>
     *  </level>
     * 
     * ◇使用例
     *   $wSiteMap   = new SiteMap(BASE_CONF);
     *   print($wSiteMap->getNodeByLevel('L300000')->getAttribute('id').':'.$wSiteMap->getTitle('L300000'));
     */
    //========================================================================================================================
    class SiteMap {
        private $_structure = NULL; //構造情報DOMオブジェクト
        private $_xpath     = NULL; //検索用xpathオブジェクト
        private $_confDir   = '';   //設定ファイル格納パス
                                    
        /**
         * コンストラクタ/デストラクタ
         *
         * @param string    $confDir  設定ファイル格納ディレクトリ
         */
        public function __construct($confDir){
            $this->_confDir = $confDir;

            //基本設定
            $wPath              = $confDir.'/sitemap.xml';
            $this->_structure   = new DOMDocument('1.0', 'utf-8');
            if (file_exists($wPath)){
                $this->_structure->preserveWhiteSpace = false;
                $this->_structure->load($wPath);
                $this->_xpath  = new DOMXPath($this->_structure);
            }
            else{
                die('Structure file not found : '.$confDir.'/sitemap.xml');
            }
        }
        
        /**
         * DOMエレメント取得
         * @param string    $id     エレメントID
         * @return object   エレメントオブジェクト
         */
        public function getElementById($id){
            return $this->_xpath->query("//*[@id='$id']")->item(0);
        }

        public function getNodeByLevel($levelId){
            return $this->getElementById($levelId);
        }

        public function getTitle($id){
            $wElement   = $this->getElementById($id);
            if ($wElement !== NULL){
                return $wElement->getAttribute('title');
            }
        }

        /**
         * リクエスト情報取得
         * @param string    $id     エレメントID
         * @return array    リクエスト情報の連想配列：エントリー名=>値(params等の場合はデフォルト値)
         */
        public function requestInfo($id){
            $wRequest   = $this->getElementById($id)->getElementsByTagName('request')->item(0);
            return $this->_scanNodes($wRequest);
        }

        private function _scanNodes($targetNode, $tagName = ''){
            $wInfo  = array();
            foreach($targetNode->childNodes as $_node){
                if ($tagName !== ''){
                    if ($_node->nodeName !== $tagName){
                        continue;
                    }
                }

                if ($_node->hasChildNodes() and $_node->firstChild->nodeName !== '#text'){
                    $wInfo[$_node->nodeName]    = $this->_scanNodes($_node);
                }
                else{
                    $wInfo[$_node->nodeName]    = $_node->nodeValue;
                }
            }
            return $wInfo;
        }

        /**
         * パンくずリスト取得
         */
        public function getBreadcrumbList($id, $params = array()){
            $wList      = array();
            $wTree      = $this->getSiteTree($id);
            foreach($wTree as $_levelID => $_req){
                $wUrl       = $_req['url'];
                $wAction    = ($_req['action'] !== '' ? 'action=' : '').$_req['action'];   
                $wMethod    = ($_req['method'] !== '' ? '&method=' : '').$_req['method']; 

                $wParam     = '';
                $wParamList = array();
                if (array_key_exists('params', $_req) && is_array($_req['params'])){
                    foreach($_req['params'] as $_key => $_value){
                        if(array_key_exists($_key, $param)){
                            $wParamList[$_key] = $params[$_key];
                        }else{
                            if($_value==''){
                                $wParamList[$_key] = $_REQUEST[$_key];
                            }else{
                                $wParamList[$_key] = $_value;
                            }
                        }
                    }
                    $wParam = getParamList($wParamList, '=', $connect = '&', $quote = '');
                }
                $wParam     = ($wParam !== '' ? '&' : '').$wParam;

                $mergedParams = $wAction.$wMethod.$wParam;
                $wHref          = $wUrl.($mergedParams ? '?' : NULL ).$mergedParams;
                $wList[$wHref]  = array('LEVEL_ID' => $_levelID, 'TITLE' => $this->getElementById($_levelID)->getAttribute('title')); 
            }

            return $wList;
        }

        /**
         * サイトツリー構造作成
         */
        public function getSiteTree($id){
            $wTree      = array();
            $wTarget    = $this->getElementById($id);
            $this->_makeTree($wTree, $wTarget);
            return $wTree;
        }

        private function _makeTree(&$pageTree, $targetNode){
            $wParentName    = $targetNode->parentNode->nodeName;
            while($wParentName !== 'sitemap'){
                $wParentName    = $this->_makeTree($pageTree, $targetNode->parentNode);
            }
            $wRequest   = $this->_scanNodes($targetNode, 'request');
            $pageTree[$targetNode->getAttribute('id')]  = $wRequest['request'];
            return $wParentName;
        }

    }

?>
