package org.maachang.jni.io;

import java.io.IOException;
import java.io.OutputStream;

/**
 * NativeOutputStream.
 * 
 * @version 2010/06/04
 * @author  masahito suzuki
 * @since   SeabassNativeIO-1.0.0
 */
public class NativeOutputStream extends OutputStream {
    private static final int ACCESS_MODE = NativeIODefine.MODE_SEQ ;
    private static final int IO_OPT = NativeIODefine.OPT_WRITE ;
    private static final int TEMP_LEN = 512 ;
    private final FastMemoryBuffer temp = new FastMemoryBuffer( TEMP_LEN ) ;
    private int position = 0 ;
    private long handle = -1L ;
    
    private NativeOutputStream() {
        
    }
    
    /**
     * ファイルオープン.
     * @param name 対象のファイル名を設定します.
     * @exception Exception 例外.
     */
    public NativeOutputStream( String name ) throws Exception {
        this( false,name ) ;
    }
    
    /**
     * ファイルオープン.
     * @param mode [true]の場合、既存ファイルが存在した場合、削除します.
     * @param name 対象のファイル名を設定します.
     * @exception Exception 例外.
     */
    public NativeOutputStream( boolean mode,String name ) throws Exception {
        if( name == null || ( name = name.trim() ).length() <= 0 ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        name = NativeIODefine.fullPath( name ) ;
        boolean useFileFlag = NativeIODefine.useFile( name ) ;
        this.handle = NativeIO.open( ACCESS_MODE,IO_OPT,NativeIODefine.nativeString( name ) ) ;
        if( this.handle == -1L ) {
            throw new IOException( "指定ファイル[" + name + "]のオープンに失敗しました" ) ;
        }
        if( useFileFlag && mode ) {
            NativeIO.setLength( this.handle,0L ) ;
        }
    }
    
    protected void finalize() throws Exception {
        close() ;
    }
    
    /**
     * ファイルクローズ.
     * @exception IOException I/O例外.
     */
    public void close() throws IOException {
        this.temp.clear() ;
        if( this.handle > -1L ) {
            flush() ;
            NativeIO.close( this.handle ) ;
            this.handle = -1L ;
            this.position = 0 ;
        }
    }
    
    /**
     * ファイル更新.
     * @exception IOException I/O例外.
     */
    public void flush() throws IOException {
        if( handle <= -1L ) {
            throw new IOException( "ファイルは既にクローズしています" ) ;
        }
        if( position > 0 ) {
            NativeIO.write( handle,-1L,temp.address,0,position ) ;
            position = 0 ;
        }
    }
    
    /**
     * 書き込み処理.
     * @param b 書き込み情報を設定します.
     * @exception IOException I/O例外.
     */
    public void write(int b) throws IOException {
        if( position >= TEMP_LEN ) {
            flush() ;
        }
        temp.putByte( position,(byte)b ) ;
        position ++ ;
    }
}
