package org.maachang.jni.io ;

import java.io.IOException;
import java.util.Iterator;

/**
 * NativeRandomI/O(FAST).
 * <p>このバッファは、速度重視を考慮した、チェック処理なしで、
 *    Nativeファイルにアクセスするオブジェクトです.
 *    欠点として、ダイレクトにNativeファイルにアクセスするので、
 *    このオブジェクトによって操作した結果によって、処理異常が
 *    発生した場合、最悪JavaVMが異常停止してしまいます.</p>
 * 
 * @version 2010/06/04
 * @author  masahito suzuki
 * @since   SeabassNativeIO-1.0.0
 */
public class FastNativeRandomIO extends NativeRandomIO {
    
    /**
     * コンストラクタ.
     * @param opt ファイルアクセスオプションを設定します.
     * @param name 対象のファイル名を設定します.
     * @exception Exception 例外.
     */
    public FastNativeRandomIO( int opt,String name ) throws Exception {
        if( name == null || ( name = name.trim() ).length() <= 0 ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        if( opt != OPT_READ ) {
            opt = OPT_WRITE ;
        }
        name = NativeIODefine.fullPath( name ) ;
        long handle = NativeIO.open( ACCESS_MODE,NativeIODefine.OPEN_ALWAYS,opt,NativeIODefine.nativeString( name ) ) ;
        if( handle <= -1L ) {
            throw new IOException( "ファイルオープンに失敗しました" ) ;
        }
        this.handle = handle ;
        this.name = name ;
        this.opt = opt ;
    }
    
    /**
     * デストラクタ.
     */
    protected void finalize() throws Exception {
        close() ;
    }
    
    /**
     * クローズ処理.
     */
    public void close() {
        if( handle != -1L ) {
            Long key ;
            Iterator it = _mmapManager.keySet().iterator() ;
            while( it.hasNext() ) {
                key = (Long)it.next() ;
                _mmapManager.get( key ).clear() ;
            }
            NativeIO.fsync( handle ) ;
            NativeIO.close( handle ) ;
        }
        handle = -1L ;
        name = null ;
    }
    
    /**
     * ファイルキャッシュ強制出力.
     * @exception Exception 例外.
     */
    public void fsync() throws Exception {
        if( handle != -1L ) {
            // mmapデータを更新.
            Long key ;
            Iterator it = _mmapManager.keySet().iterator() ;
            while( it.hasNext() ) {
                key = (Long)it.next() ;
                _mmapManager.get( key ).flush() ;
            }
            // fsync更新.
            if( NativeIO.fsync( handle ) != 0 ) {
                throw new IOException( "fsync処理に失敗" ) ;
            }
        }
    }
    
    /**
     * 読み込み処理.
     * @param buffer 読み込み先NativeBufferを設定します.
     * @param offset 読み込みオフセット値を設定します.
     * @param length 読み込みデータ長を設定します.
     * @return int 読み込みデータ長が返されます.
     * @exception Exception 例外.
     */
    public int read( NativeBuffer buffer,int offset,int length )
        throws Exception {
        return read( buffer,-1L,offset,length ) ;
    }
    
    /**
     * 読み込み処理.
     * @param buffer 読み込み先NativeBufferを設定します.
     * @param seek シーク位置を設定します.
     * @param offset 読み込みオフセット値を設定します.
     * @param length 読み込みデータ長を設定します.
     * @return int 読み込みデータ長が返されます.
     * @exception Exception 例外.
     */
    public int read( NativeBuffer buffer,long seek,int offset,int length )
        throws Exception {
        return NativeIO.read( handle,seek,buffer.getAddress(),offset,length ) ;
    }
    
    /**
     * 書込み処理.
     * @param buffer 書き込み先NativeBufferを設定します.
     * @param offset 書込みオフセット値を設定します.
     * @param length 書込みデータ長を設定します.
     * @exception Exception 例外.
     */
    public void write( NativeBuffer buffer,int offset,int length )
        throws Exception {
        write( buffer,-1L,offset,length ) ;
    }
    
    /**
     * 書込み処理.
     * @param buffer 書き込み先NativeBufferを設定します.
     * @param seek シーク位置を設定します.
     * @param offset 書込みオフセット値を設定します.
     * @param length 書込みデータ長を設定します.
     * @exception Exception 例外.
     */
    public void write( NativeBuffer buffer,long seek,int offset,int length )
        throws Exception {
        if( NativeIO.write( handle,seek,buffer.getAddress(),offset,length ) <= -1 ) {
            throw new IOException( "書込み処理に失敗しました" ) ;
        }
    }
    
    /**
     * 現在のシーク位置を取得.
     * @return long 現在のシーク位置が返されます.
     * @exception Exception 例外.
     */
    public long getSeek() throws Exception {
        return NativeIO.getSeek( handle ) ;
    }
    
    /**
     * 現在のファイルサイズを取得.
     * @return long ファイルサイズが返されます.
     * @exception Exception 例外.
     */
    public long length() throws Exception {
        return NativeIO.getLength( handle ) ;
    }
    
    /**
     * ファイルサイズを設定.
     * @param length ファイルサイズを設定します.
     * @exception Exception 例外.
     */
    public void length( long length ) throws Exception {
        NativeIO.setLength( handle,length ) ;
    }
    
    /**
     * オープンファイル名を取得.
     * @return String オープンファイル名が返されます.
     */
    public String getName() {
        return name ;
    }
    
    /**
     * ファイルオプションを取得.
     * @return int ファイルオプションが返されます.
     */
    public int getOption() {
        return opt ;
    }
    
    /**
     * ファイルがオープン中かチェック.
     * @return boolean [true]の場合、オープンしています.
     */
    public boolean isOpen() {
        return ( handle != -1L ) ;
    }
}

