package org.maachang.rawio.async ;

import java.io.IOException;

/**
 * 書込み同期フラグ.
 * 
 * @version 2008/06/12
 * @author  masahito suzuki
 * @since   Rawio 1.00
 */
class ASyncWriteLock {
    private static final int ETC_MASK = 0x0000003f ;
    private static final long LETC_MASK = ( ( long )ETC_MASK & 0x00000000ffffffffL ) ;
    private static final int FSS_MASK = ~ETC_MASK ;
    private static final int RIGHT_SHIFT = 6 ;
    private long[] sync = null ;
    private int waitSize = 0 ;
    
    private ASyncWriteLock() {
        
    }
    
    public ASyncWriteLock( int size ) {
        if( size <= 0 ) {
            this.sync = null ;
        }
        this.sync = new long[ convert( size ) ] ;
    }
    
    protected void finalize() throws Exception {
        destroy() ;
    }
    
    public synchronized void destroy() {
        sync = null ;
    }
    
    public synchronized void expansion( int size ) {
        if( sync == null ) {
            this.sync = new long[ convert( size ) ] ;
        }
        else {
            int len = convert( size ) ;
            if( this.sync.length < len ) {
                long[] nw = new long[ len ] ;
                System.arraycopy( this.sync,0,nw,0,this.sync.length ) ;
                this.sync = nw ;
            }
        }
    }
    
    private static final int convert( int size ) {
        return ( ( ( size & FSS_MASK ) >> RIGHT_SHIFT ) + ( ( ( size & ETC_MASK ) != 0 ) ? 1 : 0 ) ) ;
    }
    
    public synchronized void on( int no ) throws Exception {
        if( sync != null ) {
            long pos = ( long )no & 0x00000000ffffffffL ;
            int thisPos = ( ( no & FSS_MASK ) >> RIGHT_SHIFT ) ;
            long innerPos = ( pos & LETC_MASK ) ;
            long target = sync[ thisPos ] ;
            if( ( ( ( 1L << innerPos ) ) & target ) != 0L ) {
                throw new IOException( "指定項番["+pos+"]は既にONです" ) ;
            }
            sync[ thisPos ] = ( 1L << innerPos ) | target ;
            waitSize ++ ;
        }
    }
    
    public synchronized void off( int no ) {
        if( sync != null ) {
            long pos = ( long )no & 0x00000000ffffffffL ;
            int thisPos = ( ( no & FSS_MASK ) >> RIGHT_SHIFT ) ;
            long innerPos = ( pos & LETC_MASK ) ;
            long target = sync[ thisPos ] ;
            if( ( ( ( 1L << innerPos ) ) & target ) == 0L ) {
                return ;
            }
            sync[ thisPos ] = ( ~( 1L << innerPos ) ) & target ;
            waitSize -- ;
            if( waitSize <= 0 ) {
                waitSize = 0 ;
            }
        }
    }
    
    public synchronized boolean flag( int no ) {
        if( sync != null ) {
            long pos = ( long )no & 0x00000000ffffffffL ;
            int thisPos = ( ( no & FSS_MASK ) >> RIGHT_SHIFT ) ;
            long innerPos = ( pos & LETC_MASK ) ;
            long target = sync[ thisPos ] ;
            return ( ( ( ( 1L << innerPos ) ) & target ) != 0L ) ;
        }
        return false ;
    }
    
    public synchronized int size() {
        if( sync != null ) {
            return waitSize ;
        }
        return 0 ;
    }

}
