package org.maachang.session.client.net ;

import java.io.IOException;

import org.maachang.connector.ClientConnector;
import org.maachang.session.client.PSession;
import org.maachang.session.client.PSessionManager;
import org.maachang.session.client.net.protocol.ClCreateSessionIdProtocol;
import org.maachang.session.client.net.protocol.ClDeleteSessionIdProtocol;
import org.maachang.session.client.net.protocol.ClDeleteSessionTimeProtocol;
import org.maachang.session.client.net.protocol.ClUseSessionIdProtocol;
import org.maachang.session.client.net.protocol.ClUseToSessionIdProtocol;
import org.maachang.session.client.net.protocol.IOClientProtocol;
import org.maachang.session.engine.PersistenceDefine;

/**
 * クライアント永続化セッション管理ネットアクセス用.
 * 
 * @version 2008/05/25
 * @author masahito suzuki
 * @since PersistenceSession 1.00
 */
class PSessionNetManagerImpl implements PSessionManager {
    
    /**
     * クライアントコネクタ.
     */
    private ClientConnector conn = null ;
    
    /**
     * セッションキャッシュオブジェクト.
     */
    private ClientSessionCache cache = null ;
    
    /**
     * 削除時間タイム.
     */
    private long deleteTime = -1L ;
    
    /**
     * 各プロトコルオブジェクト.
     */
    private final ClCreateSessionIdProtocol createSession = new ClCreateSessionIdProtocol() ;
    private final ClDeleteSessionIdProtocol removeSession = new ClDeleteSessionIdProtocol() ;
    private final ClUseSessionIdProtocol isSession = new ClUseSessionIdProtocol() ;
    private final ClDeleteSessionTimeProtocol deleteSessionTime = new ClDeleteSessionTimeProtocol() ;
    private final ClUseToSessionIdProtocol useToSession = new ClUseToSessionIdProtocol() ;
    
    /**
     * コンストラクタ.
     * @param conn クライアントコネクターを設定します.
     * @exception Exception 例外.
     */
    public PSessionNetManagerImpl( ClientConnector conn ) throws Exception {
        if( conn == null ) {
            throw new IllegalArgumentException( "コネクタが設定されていません" ) ;
        }
        ClientSessionCache cache = new ClientSessionCache() ;
        this.conn = conn ;
        this.cache = cache ;
    }
    
    /**
     * デストラクタ.
     */
    protected void finalize() throws Exception {
        conn = null ;
    }
    
    /**
     * 新しいセッションIDを取得.
     * @return String 新しいセッションIDが返されます.
     * @exception Exception 例外.
     */
    public String createSession() throws Exception {
        createSession.clear() ;
        String ret = null ;
        try {
            IOClientProtocol.execution( conn,createSession,PersistenceDefine.PROTOCOL_OFFSET ) ;
            ret = ( String )createSession.getResult() ;
            if( ret != null && ret.length() == PersistenceDefine.SESSION_KEY_LENGTH ) {
                cache.put( ret ) ;
            }
        } finally {
            createSession.clear() ;
        }
        return ret ;
    }
    
    /**
     * 指定セッションIDのセッションオブジェクトを取得.
     * @return PSession セッションオブジェクトが返されます.
     * @exception Exception 例外.
     */
    public PSession getSession() throws Exception {
        return getSession( null ) ;
    }
    
    /**
     * 指定セッションIDのセッションオブジェクトを取得.
     * @param sessionId 対象のセッションIDを設定します.
     * @return PSession セッションオブジェクトが返されます.
     * @exception Exception 例外.
     */
    public PSession getSession( String sessionId ) throws Exception {
        if( sessionId == null ||
            ( sessionId = sessionId.trim() ).length() != PersistenceDefine.SESSION_KEY_LENGTH ) {
            sessionId = null ;
        }
        if( cache.containsKey( sessionId ) ) {
            return new PSessionNetImpl( sessionId,conn ) ;
        }
        sessionId = useToSessionId( sessionId ) ;
        if( sessionId != null && sessionId.length() == PersistenceDefine.SESSION_KEY_LENGTH ) {
            cache.put( sessionId ) ;
            return new PSessionNetImpl( sessionId,conn ) ;
        }
        throw new IOException( "セッション情報の取得に失敗しました" ) ;
    }
    
    /**
     * 指定セッションIDを削除.
     * @param sessionId 対象のセッションIDを設定します.
     * @exception Exception 例外.
     */
    public void reomveSession( String sessionId ) throws Exception {
        if( sessionId == null ||
            ( sessionId = sessionId.trim() ).length() != PersistenceDefine.SESSION_KEY_LENGTH ) {
            return ;
        }
        cache.remove( sessionId ) ;
        removeSession.clear() ;
        removeSession.create( sessionId ) ;
        try {
            IOClientProtocol.execution( conn,removeSession,PersistenceDefine.PROTOCOL_OFFSET ) ;
        } finally {
            removeSession.clear() ;
        }
    }
    
    /**
     * 指定セッションIDが存在するかチェック.
     * @param sessionId 対象のセッションIDを設定します.
     * @return boolean [true]の場合、セッション情報は存在します.
     * @exception Exception 例外.
     */
    public boolean isSession( String sessionId ) throws Exception {
        if( sessionId == null ||
            ( sessionId = sessionId.trim() ).length() != PersistenceDefine.SESSION_KEY_LENGTH ) {
            return false ;
        }
        if( cache.containsKey( sessionId ) ) {
            return true ;
        }
        isSession.clear() ;
        isSession.create( sessionId ) ;
        boolean ret = false ;
        try {
            IOClientProtocol.execution( conn,isSession,PersistenceDefine.PROTOCOL_OFFSET ) ;
            Object v = isSession.getResult() ;
            if( v != null ) {
                ret = ( ( Boolean )v ).booleanValue() ;
                if( ret == true ) {
                    cache.put( sessionId ) ;
                }
            }
        } finally {
            isSession.clear() ;
        }
        return ret ;
    }
    
    /**
     * セッション削除時間を取得.
     * @return long セッション削除時間が返されます.
     * @exception Exception 例外.
     */
    public long getDeleteSessionTime() throws Exception {
        if( deleteTime > 0L ) {
            return deleteTime ;
        }
        deleteSessionTime.clear() ;
        long ret = -1L ;
        try {
            IOClientProtocol.execution( conn,deleteSessionTime,PersistenceDefine.PROTOCOL_OFFSET ) ;
            Object v = deleteSessionTime.getResult() ;
            if( v != null ) {
                ret = ( ( Long )v ).longValue() ;
                deleteTime = ret ;
            }
        } finally {
            deleteSessionTime.clear() ;
        }
        return ret ;
    }
    
    /**
     * 指定セッションIDが存在しない場合は、新規で生成.
     */
    private String useToSessionId( String sessionId )
        throws Exception {
        if( sessionId == null ) {
            return createSession() ;
        }
        useToSession.clear() ;
        useToSession.create( sessionId ) ;
        String ret = null ;
        try {
            IOClientProtocol.execution( conn,useToSession,PersistenceDefine.PROTOCOL_OFFSET ) ;
            Object v = useToSession.getResult() ;
            if( v != null ) {
                ret = ( String )v ;
            }
        } finally {
            useToSession.clear() ;
        }
        return ret ;
    }
    
}

