package org.maachang.comet.net.nio ;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;

/**
 * 処理用プーリングスレッド.
 * 
 * @version 2008/05/28
 * @author  masahito suzuki
 * @since   MaachangComet 1.1B
 */
class NioOutputStream extends OutputStream {
    
    private static final int BUFFER_LENGTH = 1024 ;
    private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate( 0 ) ;
    private NioElement element = null ;
    private WriteDataQueue writeBuffer = null ;
    private ByteBuffer buffer = null ;
    private int count = 0 ;
    private final Object sync = new Object() ;
    
    public NioOutputStream() {
        
    }
    
    public NioOutputStream create( NioElement element ) throws Exception {
        if( element == null || element.isUse() == false ) {
            throw new IOException( "コネクションは既に破棄されています" ) ;
        }
        synchronized( sync ) {
            this.resetObject() ;
            this.element = element ;
            this.writeBuffer = element.getWriteDataQueue() ;
            this.buffer = ByteBuffer.allocate( BUFFER_LENGTH ) ;
            this.buffer.clear() ;
            this.element.update() ;
        }
        return this ;
    }
    
    protected void finalize() throws Exception {
        close() ;
    }
    
    protected void resetObject() {
        synchronized( sync ) {
            if( writeBuffer != null && writeBuffer.isUse() ) {
                flushTo() ;
                writeBuffer.append( EMPTY_BUFFER ) ;
            }
            element = null ;
            writeBuffer = null ;
            buffer = null ;
            count = 0 ;
        }
    }
    
    public void close() throws IOException {
        synchronized( sync ) {
            if( writeBuffer != null && writeBuffer.isUse() ) {
                flushTo() ;
                writeBuffer.append( EMPTY_BUFFER ) ;
            }
            element = null ;
            writeBuffer = null ;
            buffer = null ;
            count = 0 ;
        }
    }
    
    public void flush() throws IOException {
        synchronized( sync ) {
            if( writeBuffer == null || writeBuffer.isUse() == false ) {
                throw new IOException( "オブジェクトは既にクローズしています" ) ;
            }
            flushTo() ;
        }
    }
    
    private void flushTo() {
        if( count > 0 ) {
            buffer.flip() ;
            writeBuffer.append( buffer ) ;
            buffer = ByteBuffer.allocate( BUFFER_LENGTH ) ;
            count = 0 ;
            // 送信処理が開始されていない場合は、送信処理を有効にする.
            element.restartWrite() ;
        }
        element.update() ;
    }
    
    public void write(int b) throws IOException {
        synchronized( sync ) {
            if( writeBuffer == null || writeBuffer.isUse() == false ) {
                throw new IOException( "オブジェクトは既にクローズしています" ) ;
            }
            if( count >= BUFFER_LENGTH ) {
                this.flush() ;
            }
            buffer.put( ( byte )b ) ;
            count ++ ;
        }
    }
}
