/*
 * $Id: TemplateLoader.java,v 1.10 2005/10/23 05:28:56 sugimotokenichi Exp $
 * Copyright (C) 2005 SUGIMOTO Ken-ichi
 * 作成日: 2005/04/03
 */
package feat.v1;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import feat.v1.config.BasicFileLocator;
import feat.v1.config.FileLocator;
import feat.v1.impl.template.HTMLParser15TemplateParser;
import feat.v1.template.HTMLTemplate;
import feat.v1.template.HTMLTemplateParser;

/**
 * Templateをロードするためのクラス。
 * @author SUGIMOTO Ken-ichi
 */
public class TemplateLoader {

    private static HTMLTemplateParser parser = new HTMLParser15TemplateParser();
    private static Map templateCache = new HashMap();
    private static Map templateCache2 = new HashMap();

    /**
     * 現在のロケールのテンプレートをロードする簡易メソッド。
     * @param file
     * @param encoding 文字コード。nullを指定するとHTMLから判断する
     * @return
     * @throws TemplateParsingException テンプレートの解析中にエラーが発生した
     * @throws FileNotFoundException テンプレートファイルが見つからなかった
     * @throws IOException HTMLデータ読み込み中のIO例外
     */
    public static HTMLTemplate load(File file, String encoding)
        throws FileNotFoundException, TemplateParsingException, IOException {

        FileLocator fl = new BasicFileLocator(file);
        return load(fl, Locale.getDefault(), encoding);
    }

    /*public static NekoHTMLTemplate load(File file) throws FileNotFoundException, TemplateParsingException {
        FileLocator fl = new BasicFileLocator(file);
        return load(fl, Locale.getDefault());
    }*/

    /**
     *
     * @param file
     * @param locale
     * @param encoding 文字コード。nullを指定するとHTMLから判断する
     * @return
     * @throws FileNotFoundException テンプレートファイルが見つからなかった
     * @throws TemplateParsingException テンプレートの解析中にエラーが発生した
     * @throws IOException HTMLデータ読み込み中のIO例外
     */
    public static HTMLTemplate load(FileLocator file, Locale locale, String encoding) throws FileNotFoundException, TemplateParsingException, IOException {
        // ロケールにマッチする言語名のリストを作る
        List seq = Util.makeSequence(locale);
        seq.add(Util.NULL_LOCALE);

        HTMLTemplate ret = null;
        synchronized(templateCache) {
            for(int i=0; i<seq.size(); i++) {
                // 言語名を含んだファイル名を作る
                String filename = StringUtil.makeLocaleFilename(file.getFilename(), (Locale)seq.get(i));
                FileLocator f = file.newLocation(filename);
                String uristr = f.getURIString();

                // テンプレートキャッシュの中に有効なテンプレートがあるか？
                TemplateCacheEntry entry = (TemplateCacheEntry)templateCache.get(uristr);
                if ( entry != null ) {

                    // ファイルがまだ有効ならこのファイルを返す
                    if ( entry.isValid() ) {
                        ret = entry.getTamplate();
                        break;
                    }
                    // ファイルが無効ならキャッシュから消す
                    else {
                         templateCache.put(uristr, null);
                    }
                }

                // ファイルがあったらロード
                if ( f.exists() ) {
                    ret = parser.parseTemplate(f, encoding);
                    entry = new TemplateCacheEntry(f, ret);
                    templateCache.put(uristr, entry);
                    break;
                }

            }
        }
        if ( ret == null )
            throw new FileNotFoundException(file.getURIString());
        return ret;
    }

   /*
   *
   * @param file
   * @param locale
   * @return
   * @throws TemplateParsingException テンプレートの解析中にエラーが発生した
   * @throws FileNotFoundException テンプレートファイルが見つからなかった
   */
   /*public static NekoHTMLTemplate load(FileLocator file, Locale locale) throws TemplateParsingException, FileNotFoundException {
       // ロケールにマッチする言語名のリストを作る
       List seq = Util.makeSequence(locale);
       seq.add(Util.NULL_LOCALE);

       NekoHTMLTemplate ret = null;
       synchronized(templateCache) {
           for(int i=0; i<seq.size(); i++) {
               // 言語名を含んだファイル名を作る
               String filename = StringUtil.makeLocaleFilename(file.getFilename(), (Locale)seq.get(i));
               FileLocator f = file.newLocation(filename);
               String uristr = f.getURIString();

               // テンプレートキャッシュの中に有効なテンプレートがあるか？
               ret = (NekoHTMLTemplate)templateCache2.get(uristr);
               if ( ret != null ) {

                   // ファイルがまだ有効ならこのファイルを返す
                   if ( ret.isValid() ) {
                       break;
                   }
                   // ファイルが無効ならキャッシュから消す
                   else {
                          templateCache.put(uristr, null);
                   }
               }

               // ファイルがあったらロード
               if ( f.exists() ) {
                   ret = new NekoHTMLTemplate(f);
                   templateCache.put(uristr, ret);
                   break;
               }

           }
       }
       if ( ret == null )
           throw new FileNotFoundException(file.getURIString());
       return ret;
   }*/

}

class TemplateCacheEntry {

    FileLocator file;
    HTMLTemplate template;
    long lastModified;

    TemplateCacheEntry(FileLocator file, HTMLTemplate template) {
        this.file = file;
        this.template = template;
        try {
            lastModified = file.getLastModified();
        }
        catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * ファイルが存在していて、更新されていなかったらtrue。
     * @return boolean
     */
    public boolean isValid() {
        try {
            return exists() && !checkFile();
        }
        catch (IOException ex) {
            return false;
        }
    }

    public boolean exists() {
        return file != null && file.exists();
    }

    /**
     * ファイルが更新されていたらtrueを返す。
     * @param locator FileLocator
     * @return boolean
     */
    private boolean checkFile() throws IOException {
        long lastModified = file.getLastModified();
        if ( this.lastModified != lastModified ) {
            return true;
        }
        return false;
    }

    public HTMLTemplate getTamplate() {
        return template;
    }
}
