package org.maachang.proxy.engine.net.http;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

import org.maachang.util.StringUtil;

/**
 * HTTPDタイムスタンプ生成/解析.
 * <BR><BR>
 * HTTPDタイムスタンプを生成/解析します.
 *
 * @version 2007/08/19
 * @author  masahito suzuki
 * @since MaachangProxy 1.00
 */
public class HttpdTimestamp {
    
    /**
     * 曜日情報.
     * 日 - 土.
     */
    private static final String WKDAY_SUNDAY = "Sun" ;
    private static final String WKDAY_MONDAY = "Mon" ;
    private static final String WKDAY_TUESDAY = "Tue" ;
    private static final String WKDAY_WEDNESDAY = "Wed" ;
    private static final String WKDAY_THURSDAY = "Thu" ;
    private static final String WKDAY_FRIDAY = "Fri" ;
    private static final String WKDAY_SATURDAY = "Sat" ;
    
    /**
     * 月情報.
     */
    private static final String[] MONTH = {
        "Jan" , "Feb" , "Mar" , "Apr" ,
        "May" , "Jun" , "Jul" , "Aug" ,
        "Sep" , "Oct" , "Nov" , "Dec"
    } ;
    
    /**
     * 月情報チェック用.
     */
    private static final String[] CK_MONTH = {
        "jan" , "feb" , "mar" , "apr" ,
        "may" , "jun" , "jul" , "aug" ,
        "sep" , "oct" , "nov" , "dec"
    } ;
    
    /**
     * グリニッジ標準時.
     */
    private static final String GREENWICH = "GMT" ;
    
    /**
     * グリニッジ標準時タイムゾーン.
     */
    private static final TimeZone GMT_TIMEZONE = TimeZone.getTimeZone(
        "Europe/London"
    ) ;
    
    /**
     * HTTPタイムスタンプを取得.
     * <BR><BR>
     * 現在の時間をHTTPタイムスタンプで取得します.
     * <BR>
     * @return String 変換されたタイムスタンプが返されます.
     */
    public static final String getNowTimestamp() {
        return HttpdTimestamp.getTimestamp( System.currentTimeMillis() ) ;
    }
    
    /**
     * HTTPタイムスタンプを取得.
     * <BR><BR>
     * 現在の時間をHTTPタイムスタンプで取得します.
     * <BR>
     * @param mode [true]の場合は[Wdy, DD-Mon-YYYY HH:MM:SS GMT]となります.
     * @return String 変換されたタイムスタンプが返されます.
     */
    public static final String getNowTimestamp( boolean mode ) {
        return HttpdTimestamp.getTimestamp( mode,System.currentTimeMillis() ) ;
    }
    
    /**
     * HTTPタイムスタンプを取得.
     * <BR><BR>
     * HTTPタイムスタンプを取得します.
     * <BR>
     * @param time 取得対象のタイム値(long)を設定します.
     * @return String 変換されたタイムスタンプが返されます.
     */
    public static final String getTimestamp( long time ) {
        return getTimestamp( false,time ) ;
    }
    
    /**
     * HTTPタイムスタンプを取得.
     * <BR><BR>
     * HTTPタイムスタンプを取得します.
     * <BR>
     * @param mode [true]の場合は[Wdy, DD-Mon-YYYY HH:MM:SS GMT]となります.
     * @param time 取得対象のタイム値(long)を設定します.
     * @return String 変換されたタイムスタンプが返されます.
     */
    public static final String getTimestamp( boolean mode,long time ) {
        StringBuffer buf = null ;
        Calendar cal = null ;
        String tmp = null ;
        String ret = null ;
        
        try{
            
            cal = new GregorianCalendar( GMT_TIMEZONE ) ;
            cal.setTime( new Date( time ) ) ;
            
            buf = new StringBuffer() ;
            
            buf.append( HttpdTimestamp.getWeekCode( cal ) ) ;
            buf.append( ", " ) ;
            
            if( mode == true ) {
                tmp = String.valueOf( cal.get( Calendar.DAY_OF_MONTH ) ) ;
                buf.append( "00".substring( tmp.length() ) ) ;
                buf.append( tmp ) ;
                buf.append( "-" ) ;
                
                buf.append( MONTH[ cal.get( Calendar.MONTH ) ] ) ;
                buf.append( "-" ) ;
                
            }
            else {
                tmp = String.valueOf( cal.get( Calendar.DAY_OF_MONTH ) ) ;
                buf.append( "00".substring( tmp.length() ) ) ;
                buf.append( tmp ) ;
                buf.append( " " ) ;
                
                buf.append( MONTH[ cal.get( Calendar.MONTH ) ] ) ;
                buf.append( " " ) ;
                
            }
            
            tmp = String.valueOf( cal.get( Calendar.YEAR ) ) ;
            buf.append( "0000".substring( tmp.length() ) ) ;
            buf.append( tmp ) ;
            buf.append( " " ) ;
            tmp = String.valueOf( cal.get( Calendar.HOUR_OF_DAY ) ) ;
            buf.append( "00".substring( tmp.length() ) ) ;
            buf.append( tmp ) ;
            buf.append( ":" ) ;
            
            tmp = String.valueOf( cal.get( Calendar.MINUTE ) ) ;
            buf.append( "00".substring( tmp.length() ) ) ;
            buf.append( tmp ) ;
            buf.append( ":" ) ;
            
            tmp = String.valueOf( cal.get( Calendar.SECOND ) ) ;
            buf.append( "00".substring( tmp.length() ) ) ;
            buf.append( tmp ) ;
            buf.append( " " ) ;
            
            buf.append( GREENWICH ) ;
            
            ret = buf.toString() ;
            
        }catch( Exception e ){
            ret = null ;
        }finally{
            buf = null ;
            cal = null ;
            tmp = null ;
        }
        
        return ret ;
    }
    
    /**
     * HTMLタイムスタンプを時間変換.
     * <BR><BR>
     * HTMLタイムスタンプを時間変換します.
     * <BR>
     * @param timestamp 変換対象のHTMLタイムスタンプを設定します.
     * @return long 変換された時間が返されます.<BR>
     *              [Long.MIN_VALUE]が返された場合変換に失敗しました.
     */
    public static final long convertTimestamp( String timestamp ) {
        int len ;
        long ret ;
        
        ArrayList lst = null ;
        Calendar cal = null ;
        
        try{
            
            cal = new GregorianCalendar( GMT_TIMEZONE ) ;
            cal.clear() ;
            
            lst = StringUtil.cutString( timestamp," \t,:-" ) ;
            len = lst.size() ;
            
            if( len == 8 ){
                
                cal.set( Calendar.DAY_OF_MONTH,Integer.parseInt( ( String )lst.get( 1 ) ) ) ;
                HttpdTimestamp.setMonth( cal,( String )lst.get( 2 ) ) ;
                cal.set( Calendar.YEAR,Integer.parseInt( ( String )lst.get( 3 ) ) ) ;
                cal.set( Calendar.HOUR_OF_DAY,Integer.parseInt( ( String )lst.get( 4 ) ) ) ;
                cal.set( Calendar.MINUTE,Integer.parseInt( ( String )lst.get( 5 ) ) ) ;
                cal.set( Calendar.SECOND,Integer.parseInt( ( String )lst.get( 6 ) ) ) ;
                
                ret = cal.getTime().getTime() ;
                
            }
            else{
                ret = Long.MIN_VALUE ;
            }
            
        }catch( Exception e ){
            ret = Long.MIN_VALUE ;
        }finally{
            if( lst != null ){
                lst.clear() ;
            }
            lst = null ;
            cal = null ;
        }
        
        return ret ;
        
    }
    
    /**
     * 比較対照タイムスタンプを生成.
     * <BR><BR>
     * [HttpdTimestamp#convertTimestamp()]でコンバートした値と比較する
     * 時間を生成します.<BR>
     * この処理は単にミリ秒部分を０にするための処理です.
     * <BR>
     * @param time 設定対象の時間を設定します.
     * @return long 生成結果の時間が返されます.
     */
    public static final long createTime( long time ) {
        return ( long )( ( ( long )( time / 1000L ) ) * 1000L ) ;
    }
    
    /**
     * コンストラクタ.
     */
    private HttpdTimestamp(){}
    
    /**
     * 週情報取得.
     */
    private static final String getWeekCode( Calendar date ) {
        String ret = null ;
        switch(date.get(Calendar.DAY_OF_WEEK)){
            case Calendar.SUNDAY :
                ret = WKDAY_SUNDAY ;
                break ;
            case Calendar.MONDAY :
                ret = WKDAY_MONDAY ;
                break ;
            case Calendar.TUESDAY :
                ret = WKDAY_TUESDAY ;
                break ;
            case Calendar.WEDNESDAY :
                ret = WKDAY_WEDNESDAY ;
                break ;
            case Calendar.THURSDAY :
                ret = WKDAY_THURSDAY ;
                break ;
            case Calendar.FRIDAY :
                ret = WKDAY_FRIDAY ;
                break ;
            case Calendar.SATURDAY :
                ret = WKDAY_SATURDAY ;
                break ;
            default :
                ret = "?" ;
                break ;
        }
        return ret ;
    }
    
    /**
     * 月情報を解析.
     */
    private static final void setMonth( Calendar out,String code ) {
        int i ;
        int len ;
        
        len = CK_MONTH.length ;
        code = code.toLowerCase() ;
        
        for( i = 0 ; i < len ; i ++ ){
            
            if( code.equals( CK_MONTH[ i ] ) == true ){
                out.set( Calendar.MONTH,i ) ;
                break ;
            }
            
        }
    }
}

