package org.itscool.commons.document;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.LinkedList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.itscool.commons.collection.KeyLinkedList;

import org.itscool.commons.logging.AbstractLog;
import org.itscool.commons.logging.SimpleLog;
import org.itscool.commons.util.URLDecodeUtil;
import org.itscool.commons.util.UrlUtil;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

/**
 * コンフィグファイルを読み込むクラス<BR>
 * XMLドキュメントを読み出す基本抽象クラスです
 * @author KANO
 * @since jdk1.4.1
 * @version 1.00A 2004/11/1
 */
public abstract class XmlConfigReader {
    protected AbstractLog log = SimpleLog.getInstance();
    protected File xmlFile;
    protected DocumentBuilderFactory factory;
    protected DocumentBuilder builder;
    protected Document document;
    protected String configName;
    
    public String getConfigName(){
        return configName;
    }
    
    public void setConfigName(String configName ){
        this.configName = configName;
    }
    
    public void create(HashMap nodeList ) throws IOException{
        configName = URLDecodeUtil.decode(configName, "utf8");
        ClassLoader parent = Thread.currentThread().getContextClassLoader();
        URL url = parent.getResource(configName);
        //URL url = ConfigReader.class.getResource(fileName);
        if( url == null ){
            throw new IOException(configName + " is not found.");
        }
        log.info("load config is " + url.getFile());
        create(url.getFile(), nodeList);
    }
    
    public void create(LinkedList nodeList ) throws IOException{
        configName = URLDecodeUtil.decode(configName, "utf8");
        ClassLoader parent = Thread.currentThread().getContextClassLoader();
        URL url = parent.getResource(configName);
        //URL url = ConfigReader.class.getResource(fileName);
        if( url == null ){
            throw new IOException(configName + " is not found.");
        }
        String fileStr = url.getFile();
        String pathStr = url.getPath();
        fileStr = URLDecodeUtil.decode(fileStr, "utf8");
        pathStr = URLDecodeUtil.decode(pathStr, "utf8");
        log.info("load config is " + fileStr);
        create(pathStr, nodeList);
    }
    
    public void create(KeyLinkedList nodeList ) throws IOException{
        configName = URLDecodeUtil.decode(configName, "utf8");
        ClassLoader parent = Thread.currentThread().getContextClassLoader();
        URL url = parent.getResource(configName);
        //URL url = ConfigReader.class.getResource(fileName);
        if( url == null ){
            throw new IOException(configName + " is not found.");
        }
        String fileStr = url.getFile();
        String pathStr = url.getPath();
        fileStr = URLDecodeUtil.decode(fileStr, "utf8");
        pathStr = URLDecodeUtil.decode(pathStr, "utf8");
        log.info("load config is " + fileStr);
        create(pathStr, nodeList);
    }
    
    /**
     * DocumentBuilderを使ってXMLファイルを読み込みます
     * @param path コンフィグファイルのパスを指定します
     * @param nodeList 読み込んだDOMを格納するインスタンスを指定します
     * @throws Exception ファイルの読み込みに失敗した場合は例外Exceptionをスローします
     */
    public void create(String path, HashMap nodeList ) throws IOException{
        path = UrlUtil.replacePath(path);
        path = URLDecodeUtil.decode(path, "utf8");
        File xmlFile = new File( path );
        if( !xmlFile.isFile()) {
            String err = "Can not found file at config file(" + path +")";
            throw new IOException(err);
        }
        try{
            factory = DocumentBuilderFactory.newInstance();
            builder = factory.newDocumentBuilder();
            //エラー・ハンドラの登録
            XmlConfigExceptionHandler handler = new XmlConfigExceptionHandler();
            handler.setFileName(path);
            builder.setErrorHandler(handler);
            document = builder.parse( xmlFile);    //ドキュメント解析
        }catch( Exception e){
            throw new IOException(e.getMessage());
        }
        doCreate(nodeList);
    }
    
    /**
     * DocumentBuilderを使ってXMLファイルを読み込みます
     * @param path コンフィグファイルのパスを指定します
     * @param nodeList 読み込んだDOMを格納するインスタンスを指定します
     * @throws Exception ファイルの読み込みに失敗した場合は例外Exceptionをスローします
     */
    public void create(String path, LinkedList nodeList ) throws IOException{
        path = UrlUtil.replacePath(path);
        path = URLDecodeUtil.decode(path, "utf8");
        File xmlFile = new File( path );
        if( !xmlFile.isFile()) {
            String err = "[" + path + "]" +
                "Can not found file  at config file(" +
                XmlConfigReader.class.getName()+")";
            throw new IOException(err);
        }
        try{
            factory = DocumentBuilderFactory.newInstance();
            factory.setValidating(false);
            builder = factory.newDocumentBuilder();
            //エラー・ハンドラの登録
            XmlConfigExceptionHandler handler = new XmlConfigExceptionHandler();
            handler.setFileName(path);
            builder.setErrorHandler(handler);
            document = builder.parse( xmlFile);    //ドキュメント解析
        }catch( SAXException e){
            throw new IOException(e.getMessage());
            
        }catch( Exception e){
            e.printStackTrace();
            throw new IOException(e.getMessage());
        }
        doCreate(nodeList);
    }
    
    /**
     * DocumentBuilderを使ってXMLファイルを読み込みます
     * @param path コンフィグファイルのパスを指定します
     * @param nodeList 読み込んだDOMを格納するインスタンスを指定します
     * @throws Exception ファイルの読み込みに失敗した場合は例外Exceptionをスローします
     */
    public void create(String path, KeyLinkedList nodeList ) throws IOException{
        path = UrlUtil.replacePath(path);
        path = URLDecodeUtil.decode(path, "utf8");
        File xmlFile = new File( path );
        if( !xmlFile.isFile()) {
            String err = "[" + path + "]" +
                "Can not found file  at config file(" +
                XmlConfigReader.class.getName()+")";
            throw new IOException(err);
        }
        try{
            factory = DocumentBuilderFactory.newInstance();
            factory.setValidating(false);
            builder = factory.newDocumentBuilder();
            //エラー・ハンドラの登録
            XmlConfigExceptionHandler handler = new XmlConfigExceptionHandler();
            handler.setFileName(path);
            builder.setErrorHandler(handler);
            document = builder.parse( xmlFile);    //ドキュメント解析
        }catch( SAXException e){
            throw new IOException(e.getMessage());
            
        }catch( Exception e){
            e.printStackTrace();
            throw new IOException(e.getMessage());
        }
        doCreate(nodeList);
    }
    
    /**
     * 指定されたHTML情報を解析します
     * @param uri リクエストURI
     * @param buf HTML情報
     */
    public void create(String uri, byte[] buf, HashMap nodeList ) throws IOException{
        
        try{
            uri = URLDecodeUtil.decode(uri, "utf8");
            ByteArrayInputStream bIn = new ByteArrayInputStream(buf);
            
            factory = DocumentBuilderFactory.newInstance();
            builder = factory.newDocumentBuilder();
            //エラー・ハンドラの登録
            XmlConfigExceptionHandler handler = new XmlConfigExceptionHandler();
            handler.setFileName(uri);
            builder.setErrorHandler(handler);
            document = builder.parse(bIn);    //ドキュメント解析
        }catch( SAXException e){
            throw new IOException(e.getMessage());
            
        }catch( Exception e){
            throw new IOException(e.getMessage());
        }
        doCreate(nodeList);
    }
    
    /**
     * 指定されたHTML情報を解析します
     * @param uri リクエストURI
     * @param buf HTML情報
     */
    public void create(String uri, byte[] buf, LinkedList nodeList ) throws IOException{
        
        try{
            uri = URLDecodeUtil.decode(uri, "utf8");
            ByteArrayInputStream bIn = new ByteArrayInputStream(buf);
            
            factory = DocumentBuilderFactory.newInstance();
            builder = factory.newDocumentBuilder();
            //エラー・ハンドラの登録
            XmlConfigExceptionHandler handler = new XmlConfigExceptionHandler();
            handler.setFileName(uri);
            builder.setErrorHandler(handler);
            document = builder.parse(bIn);    //ドキュメント解析
        }catch( SAXException e){
            String msg = e.getMessage() + System.getProperty("line.separator") + new String(buf);
            throw new IOException(msg);
            
        }catch( Exception e){
            String msg = e.getMessage() + System.getProperty("line.separator") + new String(buf);
            throw new IOException(msg);
        }
        doCreate(nodeList);
    }
    
    /**
     * XMLファイルから要素を解析します<br>
     * 解析結果はnodeListにセットします<br>
     * @param nodeList XMLの解析結果
     */
    protected void doCreate(HashMap nodeList) throws IOException{}
    
    /**
     * XMLファイルから要素を解析します<br>
     * 解析結果はnodeListにセットします<br>
     * @param nodeList XMLの解析結果
     */
    protected void doCreate(LinkedList nodeList) throws IOException{}
    
    /**
     * XMLファイルから要素を解析します<br>
     * 解析結果はnodeListにセットします<br>
     * @param nodeList XMLの解析結果
     */
    protected void doCreate(KeyLinkedList nodeList) throws IOException{}

}


