package org.maachang.comet.httpd.engine.script.scripts;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.maachang.util.StringUtil;

/**
 * ページキャッシュ機能.
 * 
 * @version 2008/08/06
 * @author masahito suzuki
 * @since MaachangComet 1.22
 */
public class PageCache {
    
    /**
     * LOG.
     */
    private static final Log LOG = LogFactory.getLog( PageCache.class ) ;
    
    /**
     * 出力先文字列バッファ名.
     */
    public static final String OUTPUT_METHOD = "$pageCache" ;
    
    /**
     * デフォルトページキャッシュ時間.
     * 30秒.
     */
    private static final long DEFAULT_CACHE_TIME = 30L ;
    
    /**
     * キャッシュヘッダ情報.
     */
    private static final String CACHE_HEADER = "@cache@" ;
    
    /**
     * シングルトン.
     */
    private static final PageCache SNGL = new PageCache() ;
    
    /**
     * キャッシュ情報格納オブジェクト.
     */
    private Map<String,PageCacheChild> manager = new HashMap<String,PageCacheChild>() ;
    
    /**
     * コンストラクタ.
     */
    private PageCache() {
        //manager = Collections.synchronizedMap( new HashMap<String,PageCacheChild>() ) ;
    }
    
    /**
     * オブジェクトを取得.
     * @return PageCache オブジェクトが返されます.
     */
    public static final PageCache getInstance() {
        return SNGL ;
    }
    
    /**
     * ページキャッシュ情報を登録.
     * @param url 対象のURLを設定します.
     * @param time ページキャッシュ保持時間を設定します.
     * @param cache 対象のキャッシュ情報を設定します.
     * @exception Exception 例外.
     */
    public synchronized void set( String url,long time,String cache ) throws Exception {
        if( url == null || ( url = url.trim() ).length() <= 0 ||
            time <= 0 && cache == null || cache.length() <= 0 ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        if( url.endsWith( "/index.mhtml" ) ) {
            url = url.substring( 0,url.length() - "index.mhtml".length() ) ;
        }
        if( time <= 0L ) {
            time = DEFAULT_CACHE_TIME ;
        }
        if( LOG.isDebugEnabled() ) {
            LOG.debug( "## 指定URL[" + url + "]を" + time + "秒間ページキャッシュしました" ) ;
        }
        PageCacheChild ch = new PageCacheChild( System.currentTimeMillis() + ( time * 1000L ),cache ) ;
        manager.put( url,ch ) ;
    }
    
    /**
     * ページキャッシュ情報を取得.
     * @param url 対象のURLを設定します.
     * @return String キャッシュが存在しない場合は[null]が返されます.
     * @exception Exception 例外.
     */
    public synchronized String get( String url ) throws Exception {
        if( url == null || ( url = url.trim() ).length() <= 0 ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        if( url.endsWith( "/index" ) ) {
            url = url.substring( 0,url.length() - "index".length() ) ;
        }
        PageCacheChild ch = manager.get( url ) ;
        if( ch != null ) {
            if( System.currentTimeMillis() >= ch.getLostTime() ) {
                if( LOG.isDebugEnabled() ) {
                    LOG.debug( "## 指定URL[" + url + "]のページキャッシュを破棄しました" ) ;
                }
                manager.remove( url ) ;
            }
            else {
                return ch.getCache() ;
            }
        }
        return null ;
    }
    
    /**
     * ページキャッシュで処理するか確認.
     */
    protected long analysisCacheMode( String[] data ) throws Exception {
        if( data == null || data.length <= 0 || data[ 0 ].length() <= 0 ) {
            return -1L ;
        }
        int p = data[ 0 ].toLowerCase().indexOf( CACHE_HEADER ) ;
        if( p <= -1 ) {
            return -1L ;
        }
        int end = data[ 0 ].indexOf( "\n" ) ;
        if( end <= -1 ) {
            end = data[ 0 ].indexOf( "\r" ) ;
            if( end <= -1 ) {
                return -1L ;
            }
        }
        if( end < p ) {
            return -1L ;
        }
        String x = data[ 0 ].substring( 0,end ) ;
        data[ 0 ] = data[ 0 ].substring( end ) ;
        int eq = x.indexOf( "=",p ) ;
        if( eq <= -1 ) {
            return DEFAULT_CACHE_TIME ;
        }
        long ret = DEFAULT_CACHE_TIME ;
        try {
            ret = Long.parseLong( StringUtil.trim( x.substring( eq,end ) ) ) ;
        } catch( Exception e ) {
            ret = DEFAULT_CACHE_TIME ;
        }
        if( ret <= -1 ) {
            ret = DEFAULT_CACHE_TIME ;
        }
        return ret ;
    }
}

/**
 * ページキャッシュ子要素.
 */
class PageCacheChild {
    private long lostTime = -1L ;
    private String cache = null ;
    public PageCacheChild() {
        
    }
    public PageCacheChild( long lostTime,String cache ) {
        this.lostTime = lostTime ;
        this.cache = cache ;
    }
    public void setLostTime( long lostTime ) {
        this.lostTime = lostTime ;
    }
    public long getLostTime() {
        return this.lostTime ;
    }
    public void setCache( String cache ) {
        this.cache = cache ;
    }
    public String getCache() {
        return this.cache ;
    }
}
