package org.maachang.rawio.mapping ;

import java.io.IOException;

/**
 * Mapping管理オブジェクト.
 *  
 * @version 2008/06/15
 * @author  masahito suzuki
 * @since   Rawio 1.00
 */
class MappingManager {
    
    /**
     * １つのMapping要素.
     */
    private MappingChild[] mappings = null ;
    
    /**
     * 全Mapping長.
     */
    private int allLength = -1 ;
    
    /**
     * コンストラクタ.
     */
    public MappingManager() {
        
    }
    
    /**
     * デストラクタ.
     */
    protected void finalize() throws Exception {
        destroy() ;
    }
    
    /**
     * オブジェクト破棄.
     */
    protected synchronized void destroy() {
        if( mappings != null ) {
            int len = mappings.length ;
            for( int i = 0 ; i < len ; i ++ ) {
                mappings[ i ].destroy() ;
                mappings[ i ] = null ;
            }
        }
        mappings = null ;
    }
    
    /**
     * Mapping情報を追加.
     * @param sector セクタ長を設定します.
     * @param startPos 開始位置を設定します.
     * @param length 長さを設定します.
     * @return MappingChild 追加されたMappingChildが返されます.
     * @exception Exception 例外.
     */
    public synchronized MappingChild add( int sector,int startPos,int length )
        throws Exception {
        MappingChild ret = null ;
        if( mappings != null ) {
            int len = mappings.length ;
            int endPos = startPos + length ;
            for( int i = 0 ; i < len ; i ++ ) {
                MappingChild ch = mappings[ i ] ;
                if( ch.isPosition( startPos ) || ch.isPosition( endPos ) ) {
                    throw new IOException( "指定ポジション(start:" + startPos +
                        " length:" + length + ")は他のMappingと競合します" ) ;
                }
            }
            ret = new MappingChild( sector,startPos,length ) ;
            MappingChild[] m = new MappingChild[ len+1 ] ;
            System.arraycopy( mappings,0,m,0,len ) ;
            m[ len ] = ret ;
            mappings = m ;
            allLength += length ;
        }
        else {
            ret = new MappingChild( sector,startPos,length ) ;
            MappingChild[] m = new MappingChild[ 1 ] ;
            m[ 0 ] = ret ;
            mappings = m ;
            allLength = length ;
        }
        return ret ;
    }
    
    /**
     * 指定位置のMappingChildを取得.
     * @param no 対象の項番を設定します.
     * @return MappingChild 対象のMappingChildが返されます
     */
    public synchronized MappingChild get( int no ) {
        if( mappings != null ) {
            int len = mappings.length ;
            for( int i = 0 ; i < len ; i ++ ) {
                if( mappings[ i ].isPosition( no ) ) {
                    return mappings[ i ] ;
                }
            }
        }
        return null ;
    }
    
    /**
     * 指定配列項番からMappingChildを取得.
     * @param no 対象の配列項番を設定します.
     * @return MappingChild 対象のMappingChildが返されます.
     */
    public synchronized MappingChild getArray( int no ) {
        if( mappings != null ) {
            if( no < 0 || no >= mappings.length ) {
                return null ;
            }
            return mappings[ no ] ;
        }
        return null ;
    }
    
    /**
     * 指定位置がMaapingされているかチェック.
     * @param no ポジションを設定します.
     * @return boolean [true]の場合、Mappingされています.
     */
    public synchronized boolean isMapping( int no ) {
        if( mappings != null ) {
            int len = mappings.length ;
            for( int i = 0 ; i < len ; i ++ ) {
                if( mappings[ i ].isPosition( no ) ) {
                    return true ;
                }
            }
        }
        return false ;
    }
    
    /**
     * 更新セクタサイズを取得.
     * @return int 更新セクタサイズが返されます.
     */
    public synchronized int getUpdateSize() {
        int ret = 0 ;
        if( mappings != null ) {
            int len = mappings.length ;
            for( int i = 0 ; i < len ; i ++ ) {
                ret += mappings[ i ].updateLength() ;
            }
        }
        return ret ;
    }
    
    /**
     * Mapping数を取得.
     * @return int Mapping数が返されます.
     */
    public synchronized int length() {
        return ( mappings != null ) ? mappings.length : 0 ;
    }
    
    /**
     * 全Mappingサイズを取得.
     * @return int 全Mappingサイズが返されます.
     */
    public synchronized int mappingSize() {
        return allLength ;
    }
}
