package org.maachang.dbm.engine ;

import java.io.IOException;

import org.maachang.util.ConvertParam;

/**
 * M2KeyChild.
 * 
 * @version 2008/06/05
 * @author masahito suzuki
 * @since MaachangDBM 1.12
 */
class M2KeyChild {
    private static final int MAX_KEY_LENGTH = 16 * 0x00100000 ;
    private static final int HEADER = 36 ;
    private int startPos = -1 ;
    private int startFileNo = -1 ;
    private int sectorNextPos = -1 ;
    private int sectorNextFileNo = -1 ;
    private int befPos = -1 ;
    private int befFileNo = -1 ;
    private int nextPos = -1 ;
    private int nextFileNo = -1 ;
    private int hashCode = -1 ;
    private int hashCode2 = -1 ;
    private int elementPos = -1 ;
    private int elementFileNo = -1 ;
    private int length = -1 ;
    private byte[] data = null ;
    
    private int position = 0 ;
    
    public M2KeyChild() {
        
    }
    public M2KeyChild( M2SectorData data,int pos,int fno ) throws Exception {
        this.create( data,pos,fno ) ;
    }
    
    public M2KeyChild( byte[] b,int pos,int fno,int sectorNextNo,int sectorNextFno ) throws Exception {
        this.create( b,pos,fno,sectorNextNo,sectorNextFno ) ;
    }
    
    public void create( M2SectorData data,int pos,int fno ) throws Exception {
        clear() ;
        this.startPos = pos ;
        this.startFileNo = fno ;
        this.sectorNextPos = data.getNextNo() ;
        this.sectorNextFileNo = data.getNextFileNo() ;
        byte[] b = data.getData() ;
        this.befPos = ConvertParam.convertInt( 0,b ) ;
        this.befFileNo = ConvertParam.convertInt( 4,b ) ;
        this.nextPos = ConvertParam.convertInt( 8,b ) ;
        this.nextFileNo = ConvertParam.convertInt( 12,b ) ;
        this.hashCode = ConvertParam.convertInt( 16,b ) ;
        this.hashCode2 = ConvertParam.convertInt( 20,b ) ;
        this.elementPos = ConvertParam.convertInt( 24,b ) ;
        this.elementFileNo = ConvertParam.convertInt( 28,b ) ;
        this.length = ConvertParam.convertInt( 32,b ) ;
        if( this.length > MAX_KEY_LENGTH ) {
            throw new IOException( "不正なデータ長[" + this.length + "]を検知しました" ) ;
        }
        this.data= new byte[ this.length ] ;
        this.position = data.getLength()-HEADER ;
        System.arraycopy( b,HEADER,this.data,0,this.position ) ;
    }
    
    public void create( byte[] b,int pos,int fno,int sectorNextNo,int sectorNextFno ) throws Exception {
        clear() ;
        this.startPos = pos ;
        this.startFileNo = fno ;
        this.sectorNextPos = sectorNextNo ;
        this.sectorNextFileNo = sectorNextFno ;
        this.befPos = ConvertParam.convertInt( 0,b ) ;
        this.befFileNo = ConvertParam.convertInt( 4,b ) ;
        this.nextPos = ConvertParam.convertInt( 8,b ) ;
        this.nextFileNo = ConvertParam.convertInt( 12,b ) ;
        this.hashCode = ConvertParam.convertInt( 16,b ) ;
        this.hashCode2 = ConvertParam.convertInt( 20,b ) ;
        this.elementPos = ConvertParam.convertInt( 24,b ) ;
        this.elementFileNo = ConvertParam.convertInt( 28,b ) ;
        this.length = ConvertParam.convertInt( 32,b ) ;
        if( this.length > MAX_KEY_LENGTH ) {
            throw new IOException( "不正なデータ長[" + this.length + "]を検知しました" ) ;
        }
        
        this.data = new byte[ this.length ] ;
        System.arraycopy( b,HEADER,this.data,0,this.length ) ;
        this.position = this.length ;
    }
    
    public void clear() {
        startPos = -1 ;
        startFileNo = -1 ;
        sectorNextPos = -1 ;
        sectorNextFileNo = -1 ;
        befPos = -1 ;
        befFileNo = -1 ;
        nextPos = -1 ;
        nextFileNo = -1 ;
        hashCode = -1 ;
        hashCode2 = -1 ;
        elementPos = -1 ;
        elementFileNo = -1 ;
        length = -1 ;
        data = null ;
        position = 0 ;
    }
    
    public void addData( M2SectorData data ) {
        int len = data.getLength() ;
        System.arraycopy( data.getData(),0,this.data,position,len ) ;
        position += len ;
    }
    
    public void setStartPos( int startPos ) {
        this.startPos = startPos ;
    }
    
    public int getStartPos() {
        return startPos ;
    }
    
    public void setStartFileNo( int startFileNo ) {
        this.startFileNo = startFileNo ;
    }
    
    public int getStartFileNo() {
        return startFileNo ;
    }
    
    public void setSectorNextPos( int sectorNextPos ) {
        this.sectorNextPos = sectorNextPos ;
    }
    
    public int getSectorNextPos() {
        return sectorNextPos ;
    }
    
    public void setSectorNextFileNo( int sectorNextFileNo ) {
        this.sectorNextFileNo = sectorNextFileNo ;
    }
    
    public int getSectorNextFileNo() {
        return sectorNextFileNo ;
    }
    
    public void setBefPos( int befPos ) {
        this.befPos = befPos ;
    }
    
    public int getBefPos() {
        return befPos ;
    }
    
    public void setBefFileNo( int befFileNo ) {
        this.befFileNo = befFileNo ;
    }
    
    public int getBefFileNo() {
        return befFileNo ;
    }
    
    public void setNextPos( int nextPos ) {
        this.nextPos = nextPos ;
    }
    
    public int getNextPos() {
        return nextPos ;
    }
    
    public void setNextFileNo( int nextFileNo ) {
        this.nextFileNo = nextFileNo ;
    }
    
    public int getNextFileNo() {
        return nextFileNo ;
    }
    
    public void setHashCode( int hashCode ) {
        this.hashCode = hashCode ;
    }
    
    public int getHashCode() {
        return hashCode ;
    }
    
    public void setHashCode2( int hashCode2 ) {
        this.hashCode2 = hashCode2 ;
    }
    
    public int getHashCode2() {
        return hashCode2 ;
    }
    
    public void setElementPos( int elementPos ) {
        this.elementPos = elementPos ;
    }
    
    public int getElementPos() {
        return elementPos ;
    }
    
    public void setElementFileNo( int elementFileNo ) {
        this.elementFileNo = elementFileNo ;
    }
    
    public int getElementFileNo() {
        return elementFileNo ;
    }
    
    public int getLength() {
        return length ;
    }
    
    public void setData( byte[] data ) {
        this.data = data ;
        this.length = data.length ;
    }
    
    public byte[] getData() {
        return data ;
    }
    
    public byte[] save() {
        byte[] ret = new byte[ HEADER + length ] ;
        int p = 0 ;
        ConvertParam.convertInt( ret,p,befPos ) ;
        p += 4 ;
        ConvertParam.convertInt( ret,p,befFileNo ) ;
        p += 4 ;
        ConvertParam.convertInt( ret,p,nextPos ) ;
        p += 4 ;
        ConvertParam.convertInt( ret,p,nextFileNo ) ;
        p += 4 ;
        ConvertParam.convertInt( ret,p,hashCode ) ;
        p += 4 ;
        ConvertParam.convertInt( ret,p,hashCode2 ) ;
        p += 4 ;
        ConvertParam.convertInt( ret,p,elementPos ) ;
        p += 4 ;
        ConvertParam.convertInt( ret,p,elementFileNo ) ;
        p += 4 ;
        ConvertParam.convertInt( ret,p,length ) ;
        p += 4 ;
        System.arraycopy( data,0,ret,p,length ) ;
        return ret ;
    }
    
    public M2SectorData header( int blockSize ) {
        M2SectorData ret = new M2SectorData() ;
        header( blockSize,ret ) ;
        return ret ;
    }
    
    public void header( int blockSize,M2SectorData data ) {
        data.setSectorType( MDbmDefine.SECTOR_TYPE_KEY ) ;
        int len = ( this.length >= blockSize ) ?
            blockSize : this.length ;
        byte[] b = new byte[ len + HEADER ] ;
        int p = 0 ;
        ConvertParam.convertInt( b,p,this.befPos ) ;
        p += 4 ;
        ConvertParam.convertInt( b,p,this.befFileNo ) ;
        p += 4 ;
        ConvertParam.convertInt( b,p,this.nextPos ) ;
        p += 4 ;
        ConvertParam.convertInt( b,p,this.nextFileNo ) ;
        p += 4 ;
        ConvertParam.convertInt( b,p,this.hashCode ) ;
        p += 4 ;
        ConvertParam.convertInt( b,p,this.hashCode2 ) ;
        p += 4 ;
        ConvertParam.convertInt( b,p,this.elementPos ) ;
        p += 4 ;
        ConvertParam.convertInt( b,p,this.elementFileNo ) ;
        p += 4 ;
        ConvertParam.convertInt( b,p,this.length ) ;
        p += 4 ;
        System.arraycopy( this.data,0,b,HEADER,len ) ;
        data.setData( b ) ;
        data.setLength( b.length ) ;
        data.setNextNo( this.sectorNextPos ) ;
        data.setNextFileNo( this.sectorNextFileNo ) ;
    }
    
    public String toString() {
        return new StringBuilder().
            append( " startPos:" ).append( startPos ).
            append( " startFileNo:" ).append( startFileNo ).
            append( " sectorNextPos:" ).append( sectorNextPos ).
            append( " sectorNextFileNo:" ).append( sectorNextFileNo ).
            append( " befPos:" ).append( befPos ).
            append( " befFileNo:" ).append( befFileNo ).
            append( " nextPos:" ).append( nextPos ).
            append( " nextFileNo:" ).append( nextFileNo ).
            append( " hashCode:" ).append( hashCode ).
            append( " hashCode2:" ).append( hashCode2 ).
            append( " elementPos:" ).append( elementPos ).
            append( " elementFileNo:" ).append( elementFileNo ).
            append( " length:" ).append( length ).toString() ;
    }
}
