package org.maachang.rawio ;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * NativeFileRawI/O.
 *  
 * @version 2008/06/12
 * @author  masahito suzuki
 * @since   Rawio 1.00
 */
class NativeRawIO {
    private static boolean initFlag = false ;
    private static final Object sync = new Object() ;
    static {
        synchronized( sync ) {
            String name = RawioDefine.NORMAL_NAME ;
            if( System.getProperty( RawioDefine.LIB_MODE ) != null ) {
                name = System.getProperty( RawioDefine.LIB_MODE ) ;
            }
            String lib = name + "-" + RawioDefine.VERSION ;
            switch( Os.getInstance().getOS() ) {
                case Os.OS_WINNT :
                    lib += RawioDefine.WINDOWS_LIB_PLUS ;
                    System.load( targetDynamincLib( true,lib ) ) ;
                    initFlag = true ;
                    break ;
                case Os.OS_UNIX :
                    lib += RawioDefine.LINUX_LIB_PLUS ;
                    System.load( targetDynamincLib( true,lib ) ) ;
                    initFlag = true ;
                    break ;
                default :
                    initFlag = false ;
                    break ;
            }
        }
    }
    
    private static final String targetDynamincLib( boolean mode,String lib ) {
        String sp = System.getProperty( "file.separator" ) ;
        File targetDir = null ;
        if( System.getProperty( RawioDefine.PROPERTY_NAME ) == null ) {
            targetDir = new File( new StringBuilder().
                append( System.getProperty( "user.home" ) ).
                append( sp ).
                append( RawioDefine.DEFAULT_DIR ).
                toString() );
        }
        else {
            targetDir = new File( System.getProperty( RawioDefine.PROPERTY_NAME ) );
        }
        if( targetDir.exists() == false ) {
            targetDir.mkdirs() ;
        }
        File outFile = new File( targetDir,lib );
        if( mode == true ) {
            String ntvDir = RawioDefine.NATIVE_PACKAGE ;
            ntvDir = ntvDir.trim() ;
            if( ntvDir.endsWith( "/" ) == false ) {
                ntvDir += "/" ;
            }
            if( ntvDir.startsWith( "/" ) ) {
                ntvDir = ntvDir.substring( 1 ) ;
            }
            InputStream is = new BufferedInputStream(
                Thread.currentThread().getContextClassLoader().getResourceAsStream(
                    ntvDir + lib ) ) ;
            if( isLibFile( outFile,is ) ) {
                try{
                    OutputStream os = new BufferedOutputStream( new FileOutputStream( outFile ) ) ;
                    try{
                        try{
                            for(;;) {
                                int n = is.read();
                                if( n <= -1 ) {
                                    break;
                                }
                                os.write( n );
                            }
                            os.flush() ;
                        }
                        finally{
                            is.close();
                            is = null ;
                        }
                    }
                    finally{
                        os.close();
                        os = null ;
                    }
                }
                catch( Exception e ) {
                    outFile = null ;
                }
            }
            if( is != null ) {
                try {
                    is.close() ;
                } catch( Exception e ) {
                }
                is = null ;
            }
        }
        if( outFile != null ) {
            return outFile.getAbsolutePath() ;
        }
        return null ;
    }
    
    private static final boolean isLibFile( File f,InputStream in ) {
        boolean ret = false ;
        try {
            if( f.exists() == false ) {
                ret = true ;
            }
            else {
                int len = ( int )f.length() ;
                ret = ( len <= 0 || len != in.available() ) ;
            }
        } catch( Exception e ) {
            ret = true ;
        }
        return ret ;
    }
    
    protected static final boolean useInit() {
        boolean ret = false ;
        synchronized( sync ) {
            ret = initFlag ;
        }
        return ret ;
    }
    
    protected NativeRawIO() {
        
    }
    
    protected static native int getSector( byte[] drv ) ;
    protected static native int getSectorByHandle( long h ) ;
    protected static native long rawOpen( byte[] path,byte[] drv ) ;
    protected static native void rawClose( long h ) ;
    protected static native int rawWrite( long h,int pos,byte[] data ) ;
    protected static native int rawRead( long h,int pos,byte[] data ) ;
    protected static native long getRawLength( long h ) ;
    protected static native int setRawLength( long h,long len ) ;
}

