/*
 * @(#)GenerateParser.java
 *
 * Copyright 2001 Nomura Research Institute, LTD. All rights reserved.
 *
 * RID-X : XMLファイルの解析
 *
 * @author  Intelligent Technology Inc.
 * @version 1.01 2002/05/13
 */
package jp.co.nri.rid.generator;


import java.io.*;
import java.util.*;
import org.w3c.dom.*;
import org.apache.xpath.XPathAPI;

import jp.co.nri.rid.mapper.*;

import jp.co.iti.fagot.ZApp;
import jp.co.iti.fagot.doc.DocDocument;
import jp.co.iti.fagot.doc.DocManager;
import jp.co.iti.fagot.util.ZDebug;
import jp.co.iti.fagot.util.ZResource;
import jp.co.iti.fagot.util.ZProperties;
import jp.co.iti.fagot.util.ZString;

/* t3-nishimura@nri added */
import jp.co.nri.rid.xml.elementBooster;

/**
 * XMLファイルの解析
 */
public class GenerateParser {

    /* RCS ID */
    private static final String RCSID =
        "$Id: GenerateParser.java,v 1.3 2003/01/24 15:21:18 nsmr Exp $";

    // Project Information
    class ProjectInfo {
        ZoneInfo      zone;                 // _top ZoneUnit
    }

    // Zone Information
    class ZoneInfo {
        boolean       top;                  // TOP_ZONEの判断(true:top / false :top以外)
        String        name;                 // ディレクトリ名
        String        file;                 // HTMLディレクトリからの相対パス
        String        title;                // タイトル
        String        template1;            // テンプレートファイル１
        String        template2;            // テンプレートファイル２
        String        parent;               // TOPへのパス
        Vector        attr_lst;             // 全属性のリスト
        Vector        page_lst;             // page_info リスト
        Vector        zone_lst;             // zone_info リスト
        Vector        resource_lst;         // resource_info リスト
        Vector        document_lst;         // resource_info リスト

	// t3-nishimura@nri added
	elementBooster element;             // element の実体
    }

    // Page Information
    class PageInfo {
        String        name;                 // ページ名
        String        file;                 // HTMLディレクトリからの相対パス
        String        title;                // タイトル
        String        url;                  // URL（ブラウザで表示する際のパス）
        String        path;                 // [HTML]ディレクトリへのパス
        String        svg;                  // SVGファイル名 Data\_svgディレクトリのファイル名
        String        doc;                  // ファイル名 Data\_svgディレクトリのファイル名
        Vector        attr_lst;             // 全属性のリスト

	// t3-nishimura@nri added
	elementBooster element;             // element の実体
    }

    // Resource Information
    class ResourceInfo {
        Vector        attr_lst;             // 全属性のリスト
    }

    // Document Information
    class DocumentInfo {
        Vector        attr_lst;             // 全属性のリスト
    }

    // Attribute Information
    class Attribute {
        String        name;                 // 属性名
        String        value;                // 属性値
    }

    /** 製作指示書のディレクトリ名 **/
    static final String puProductDir      = "PortalTeam";
    /** 紙芝居のディレクトリ名 **/
    static final String puPresentDir      = "PortalPublic";

    /** フレームテンプレート名（製作指示書）**/
    static final String puTemplProFrame   = "_frameProduct.html";
    /** フレームテンプレート名（紙芝居）**/
    static final String puTemplPreFrame   = "_framePresent.html";
    /** ナビテンプレート名**/
    static final String puTemplNavi       = "_navi.html";
    /** ポンチ絵テンプレート名**/
    static final String puTemplSample     = "_sample.html";
    /** ページ情報テンプレート名**/
    static final String puTemplInfo       = "_info.html";
    /** ページテンプレート名**/
    static final String puTemplPage       = "_page.html";
    /** サイトマップテンプレート名**/
    static final String puTemplSitemap    = "_sitemap.html";
    /** リフレッシュテンプレート名**/
    static final String puTemplRefresh    = "_refresh.html";

    /** 空白フレーム名  **/
    static final String puBlank           = "Blank";

    /** MAPファイル フレームＭＡＰ名 **/
    static final String puMapFrame        = "_frame_map.xml";
    /** MAPファイル frame_data属性  **/
    static final String puMapFrameData    = "frame_data";
    /** MAPファイル name属性 **/
    static final String puMapFrameDataKey = "name";
    /** MAPファイル src属性 **/
    static final String puMapFrameInTag   = "src";

    /** 出力時の付加名（フレーム出力ファイル名） **/
    static final String puOutFrame        = "_frame.html";
    /** 出力時の付加名（ナビ出力ファイル名） **/
    static final String puOutNavi         = "_navi.html";
    /** 出力時の付加名（ポンチ絵出力ファイル名） **/
    static final String puOutSample       = "_sample.html";
    /** 出力時の付加名（SVG出力ファイル名） **/
    static final String puOutSvg          = "_svg.svg";
    /** 出力時の付加名（ページ情報出力ファイル名） **/
    static final String puOutInfo         = "_info.html";
    /** 出力時の付加名（リフレッシュファイル名） **/
    static final String puOutRefresh      = "html_navi.html";
    /** 出力時の付加名（サイトマップファイル名） **/
    static final String puOutSitemap      = "_ridSitemap.html";

    /** Mapperの[Data.xml]のrootタグ  **/
    static final String puRootTag         = "RidProject";         

    /**　RidProjectの定義 **/
    private static final String pf_rootTag      = "RidProject";
    /**　ZoneUnitの定義 **/
    private static final String prZoneUnit      = "ZoneUnit";
    /**　PageUnitの定義 **/
    private static final String prPageUnit      = "PageUnit";
    /**　ResourceUnitの定義 **/
    private static final String prResourceUnit  = "ResourceUnit";
    /**　DocumentUnitの定義 **/
    private static final String prDocumentUnit  = "DocumentUnit";
    /**　Name属性の定義 **/
    private static final String prNameAttr      = "Name";
    /**　File属性の定義 **/
    private static final String prFileAttr      = "File";
    /**　Title属性の定義 **/
    private static final String prTitleAttr     = "Title";
    /**　Svg属性の定義 **/
    private static final String prSvgAttr       = "Svg";
    /**　Doc属性の定義 **/
    private static final String prDocAttr       = "Doc"; 
    /**　Template1属性の定義 **/
    private static final String prTemplate1Attr = "Template1";
    /**　Template2属性の定義 **/
    private static final String prTemplate2Attr = "Template2";
    /**　PageType属性の定義 **/
    private static final String prPageTypeAttr  = "PageType";

    /** 親ディレクトルのパス  **/
    private static final String prParentPath   = "..";

    /** 読飛ばしの先頭文字列  **/
    private String[] prIgnoreLst;

/**
  * デフォルトコンストラクタ
  */
    public GenerateParser() { }


/**
  * ドキュメント解析
  *
  * @param  Document    doc             ドキュメント
  * @param  String      parent          出力ディレクト
  * @param  String      path            HTMLディレクト
  * @return void
  */
    public  ProjectInfo documentParser(Document doc, String parent, String path) throws Exception {

        // Project General Information
        ProjectInfo  project_info = new ProjectInfo();

        ZoneInfo zone_info = new  ZoneInfo();
        boolean ret = false;

        // 読飛ばしを取得
        prIgnoreLst = getIgnore();

        //ルートのエレメント取得
        Element root_elem = doc.getDocumentElement();
        ret = checkRootElement(root_elem, pf_rootTag);
        if (ret){

            // TOP Zoneの取得
            Element zone_elem = (Element)XPathAPI.selectSingleNode(root_elem, prZoneUnit);
            if ( zone_elem != null) {
                // ZoneUnitの解析
                // RidProjectの配下には ZONEUNITが1つしか存在しないのでこれが TOP
                zone_info = zoneParser(zone_elem, parent, path, true);
                // Top ZoneUnitの設定
                project_info.zone = zone_info;
            }
        }
        return project_info;
   }

/**

  * String型がＮＵＬＬか判断する
  *
  * @param  String      str           ファイル名
  * @return boolean     true (null)/false(not null)
  */
    public boolean isNullString(String str) throws Exception {

        boolean ret;
        if ( (str == null) || (str.equals("")) ) {
            ret = true;
        } else {
            ret = false;
        } 
        return ret;
    }

/**
  * システムデフォルトのパスの区切り文字を"/"に変換する
  *
  * @param  String      navitePath      パス文字列
  * @return void
  */
    public String replaceWebFileSeparator(String path) {
        return path.replace(File.separatorChar, '/');
    }

/**
  * [出力ディレクトリ]から[HTML]へのパス解析
  *
  * @param  String      outDir          出力ディレクト
  * @param  String      htmlDir         HTMLディレクト
  * @return String      [出力ディレクトリ]から[HTML]へのパス
  */
    public String parentPath(String outDir, String htmlDir) throws Exception {

        int i, pos, p_out, p_html;
        String  outDirUpper  = outDir.toUpperCase();
        String  htmlDirUpper = htmlDir.toUpperCase();
        String  htmlPath = "", outPath = "", outParentPath = "";

        p_out   = outDirUpper.length();
        p_html  = htmlDirUpper.length();
        if ( p_out < p_html) {
            pos = p_out;
        } else {
            pos = p_html;
        }

        for ( i = 0; i < pos; i++ ) {
            if(  outDirUpper.charAt(i) != htmlDirUpper.charAt(i)) {
                break;
            }
        }
        htmlPath = htmlDir.substring(i);
        outPath  = outDir.substring(i);

        if (outPath.length() != 0) {
            outParentPath = prParentPath;
            for ( i = 0; i < outPath.length(); i++ ) {
                if(outPath.charAt(i) == File.separatorChar) {
                    outParentPath = outParentPath + File.separator + prParentPath;
                }
            }
            outParentPath = outParentPath + File.separator + htmlPath;
        }

        return outParentPath;
   }

/**
  * ZoneUnitの解析
  *
  * @param  Element     elem            ZoneUnitのElement
  * @return ZoneInfo    ZoneUnitの情報
  */
    private ZoneInfo zoneParser(Element elem, String parent, String path, boolean top) throws Exception {

        //ZoneUnitの属性を取得
        Vector attr_lst = setAttributes(elem, prZoneUnit);

        //子のZoneUnitの取得
        Vector  zone_lst = new Vector();
        NodeList zone_elem_lst = XPathAPI.selectNodeList(elem, prZoneUnit);
        for ( int n = 0; n < zone_elem_lst.getLength(); n++ ) {
            Element zone_elem = (Element)zone_elem_lst.item(n);
            ZoneInfo zone = zoneParser(zone_elem, (prParentPath + File.separator + parent), (prParentPath + File.separator + path), false);
            if (zone != null) zone_lst.add(zone);
        }

        ZoneInfo zone_info = new  ZoneInfo();
        String name = getAttributeValue(attr_lst, prNameAttr);
        if ( !(IsIgnore(name)) ) {
            zone_info.top          = top;
            zone_info.name         = name;
            zone_info.file         = getAttributeValue(attr_lst, prFileAttr);
            zone_info.title        = getAttributeValue(attr_lst, prTitleAttr);
            zone_info.template1    = getAttributeValue(attr_lst, prTemplate1Attr);
            zone_info.template2    = getAttributeValue(attr_lst, prTemplate2Attr);
            zone_info.parent       = parent;
            zone_info.attr_lst     = attr_lst;
            zone_info.page_lst     = pageLst(elem, path);
            zone_info.zone_lst     = zone_lst;
            zone_info.resource_lst = resourceLst(elem);
            zone_info.document_lst = documentLst(elem);
	    zone_info.element      = new elementBooster(elem);
        } else {
            zone_info =null;
        }

        return zone_info;
   }

/**
  * PageUnitのリスト
  *
  * @param  Element     elem            PageUnitのElement
  * @return PageInfo    PageUnitの情報
  */
    private Vector pageLst(Element elem, String path) throws Exception {

        //PageUnitのリスト
        Vector page_lst = new Vector();

        //Top Pageの検索
        Element topPage = zoneTopPageUnit(elem);

        //PageUnitの取得
        NodeList page_elem_lst = XPathAPI.selectNodeList(elem, prPageUnit);
        for ( int i = 0; i < page_elem_lst.getLength(); i++ ) {
            Element page_elem = (Element)page_elem_lst.item(i);
            PageInfo page = pageParser(page_elem, path);

            if (page != null) {
                //top PageUnitの場合は先頭に追加する
                if (page_elem == topPage) {
                    page_lst.add(0, page);
                } else {
                    page_lst.add(page);
                }
            }
        }

        return page_lst;
    }
/**
  * PageUnitの解析
  *
  * @param  Element     elem            PageUnitのElement
  * @return PageInfo    PageUnitの情報
  */
    private PageInfo pageParser(Element elem, String path) throws Exception {

        // PageUnitの属性値を取得
        Vector  attr_lst = new Vector(); 
        attr_lst = setAttributes(elem, prPageUnit);

        PageInfo page = new  PageInfo();
        String name  = getAttributeValue(attr_lst, prNameAttr);
        String ptype = getAttributeValue(attr_lst, prPageTypeAttr);

        // Name属性がIgnoreキーでなく、PageTypeが"server"で無いもの
        if ( !(IsIgnore(name)) && !(ptype.equals("server"))) {
            page.name     = name;
            page.attr_lst = attr_lst;
            page.file     = getAttributeValue(attr_lst, prFileAttr);
            page.title    = getAttributeValue(attr_lst, prTitleAttr);
            page.svg      = elem.getAttribute(prSvgAttr);
            if (page.svg == null) page.svg = "";
            page.doc      = elem.getAttribute(prDocAttr);
            if (page.doc == null) page.doc = "";
            page.path     = path;
	    page.element  = new elementBooster(elem);
        } else {
            page = null;
        } 
        return page;
   }

/**
  * ResourceUnitのリスト
  *
  * @param  Element     elem            Element
  * @return ResourceInfo    ResourceInfoのリスト
  */
    private Vector resourceLst(Element elem) throws Exception {

        //Resourceのリスト
        Vector  resource_lst  = new Vector();

        //Resourceの取得
        NodeList resource_elem_lst = XPathAPI.selectNodeList(elem, prResourceUnit);
        for ( int i = 0; i < resource_elem_lst.getLength(); i++ ) {
            Element resource_elem = (Element)resource_elem_lst.item(i);
            ResourceInfo resource = resourceParser(resource_elem);
            resource_lst.add(resource);
        }
        return resource_lst;
    }


/**
  * ResourceUnitの解析
  *
  * @param  Element     elem            ResourceUnitのElement
  * @return ResourceInfo    ResourceInfoの情報
  */
    private ResourceInfo resourceParser(Element elem) throws Exception {

        // ResourceUnitの属性値を取得
        ResourceInfo resource = new  ResourceInfo();
        resource.attr_lst = setAttributes(elem, prResourceUnit);
        return resource;
   }


/**
  * DocumentUnitのリスト
  *
  * @param  Element     elem            PageUnitのElement
  * @return Vector      DocumentUnitのリスト
  */
    private Vector documentLst(Element elem) throws Exception {

        //Documentのリスト
        Vector  document_lst  = new Vector();

        //Documentの取得
        NodeList document_elem_lst = XPathAPI.selectNodeList(elem, prDocumentUnit);
        for ( int i = 0; i < document_elem_lst.getLength(); i++ ) {
            Element document_elem = (Element)document_elem_lst.item(i);
            DocumentInfo document = documentParser(document_elem);
            document_lst.add(document);
        }
        return document_lst;
    }

/**
  * DocumentUnitの解析
  *
  * @param  Element     elem            PageUnitのElement
  * @return DocumentUnit    DocumentUnitの情報
  */
    private DocumentInfo documentParser(Element elem) throws Exception {

        // DocumentUnitの属性値を取得
        DocumentInfo document = new  DocumentInfo();
        document.attr_lst = setAttributes(elem, prDocumentUnit);
        return document;
   }


/**
  * UNITの属性を取得
  *
  * @param  Element     elem            UNITのElement
  * @param  String      unit_name       Unit名
  * @return Vector      属性のリスト
  */
    private Vector setAttributes(Element elem, String unit_name) throws Exception {

        Vector  attr_lst = new Vector(); 

        // UNITの属性一覧を取得
        ZProperties prop  = DocManager.loadProperty( DocManager.ELEMENT );
        String[] attrs = ZString.tokenize(prop.getProperty(unit_name + ".attributes"));

        // 属性名、属性値を設定
        for (int nAt = 0 ; nAt < attrs.length ; nAt++) {

            Attribute Attr = new Attribute();
            Attr.name   = attrs[nAt];
            Attr.value  = elem.getAttribute(attrs[nAt]);

            if (-1 == attr_lst.indexOf(Attr))
                attr_lst.add((Attr));
        }
        return attr_lst;
    }

/**
  * 属性のリストから指定された属性名の値を取得する(大文字小文字の区別なし)
  *
  * @param  Vector      attr_lst        属性のリスト
  * @param  String      attr_name       属性名
  * @return String      指定された属性名の値 / 存在しない場合は""
  */
    private String getAttributeValue(Vector attr_lst, String attr_name) throws Exception {

        String attrValue = "";
        for ( int i = 0; i < attr_lst.size(); i++ ) {
            Attribute attr = (Attribute)attr_lst.elementAt(i);
            if (attr.name.equalsIgnoreCase(attr_name)) {
                attrValue = attr.value;
                break;
            }
        }

        return attrValue;
    }

/**
  * XMLファイルがRID用のXMLファイルか、ルートタグ名でチェツクを行う
  *
  * @param  Element     root_elem       ルートエレメント
  * @param  String      root_tag        ルートタグ名
  *
  * @return boolean true / false
  */
    private boolean checkRootElement(Element root_elem, String root_tag) throws IOException, Exception {

        if ( root_elem.getNodeName().compareTo(root_tag) != 0 ) {
            ZDebug.trace("is not XML file for RID...");
            return false;
        }
        return true;
    }


/**
  * ZoneのTop　PageUnitの検索
  *
  * @param  Element     elem            ZoneUnitのElement
  * @return ZoneInfo    ZoneUnitの情報
  */
    private Element zoneTopPageUnit(Element elem) throws Exception {

        Element  pageElem = null;

        // ZoneUnitのElementの中に 
        String  top = elem.getAttribute("Top");
        
        //Top Attributeが存在しない場合は、
        if ( !isNullString(top) ) {
            //Topが存在した場合
            pageElem = (Element)XPathAPI.selectSingleNode(elem, "PageUnit[@File='" + top + "']");
        } else {
            //FileNameが[index.html]のページを取得
            pageElem = (Element)XPathAPI.selectSingleNode(elem, "PageUnit[@Name='index.html']");

            //null の場合 FileNameが[index.html]のページを取得
            if (pageElem == null){
                //FileNameが[index.html]のページを取得
                pageElem = (Element)XPathAPI.selectSingleNode(elem, "PageUnit[@Name='index.htm']");
            }
        }

        return pageElem;
    }


/**
  * Resourceファイルから[rid.ignore.prefix]取得
  *
  * @return String[]    リスト
  */
    private String[] getIgnore() throws Exception {

        ZResource res = ZApp.getTheApp().getResource();
        String ignore = res.getString("rid.ignore.prefix");
        String[] ignore_lst = ZString.tokenize(ignore);
        return (ignore_lst);
    }


/**
  * [ignore.prefix]の判断
  *
  * @param  String      unitname        UNIT名
  * @return boolean     true(ignore.prefixあり) / false(ignore.prefixなし)
  */
    private boolean IsIgnore(String unitname) throws Exception {
        for (int n = 0 ; n < prIgnoreLst.length ; n++) {
            if (unitname.startsWith(prIgnoreLst[n])) {
                return true;
            }
        }
        return false;
    }

}
