package org.maachang.report ;

import java.io.IOException;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;

/**
 * 範囲選択されたセルスタイル情報.
 * 
 * @version 2008/09/29
 * @author masahito suzuki
 * @since MaachangReport 1.00
 */
class CellStyle {
    
    /**
     * セルスタイル名.
     */
    private String name = null ;
    
    /**
     * コピー元の開始軸X.
     */
    private int startX = -1 ;
    
    /**
     * コピー元の開始軸Y.
     */
    private int startY = -1 ;
    
    /**
     * コピーWidth値.
     */
    private int width = -1 ;
    
    /**
     * コピーHeight値.
     */
    private int height = -1 ;
    
    /**
     * 現在追加位置.
     */
    private int nowPos = 0 ;
    
    /**
     * コピーされたセルスタイル格納内容.
     */
    private HSSFCellStyle[] styles = null ;
    
    /**
     * 書込み時にInsertするかチェックするフラグ.
     */
    private boolean writeByInsertFlag = false ;
    
    /**
     * コンストラクタ.
     */
    private CellStyle() {
        
    }
    
    /**
     * コンストラクタ.
     * @param name セルスタイル名を設定します.
     * @param sheet 対象のExcelシートオブジェクトを設定します.
     * @param startXPos コピー開始位置Xを設定します.
     * @param startYPos コピー開始位置Yを設定します.
     * @param width Width値を設定します.
     * @param height Height値を設定します.
     * @exception Exception 例外.
     */
    public CellStyle( String name,HSSFSheet sheet,int startXPos,int startYPos,int width,int height )
        throws Exception {
        if( name == null || ( name = name.trim() ).length() <= 0 ) {
            throw new IllegalArgumentException( "セルスタイル名は不正です" ) ;
        }
        if( sheet == null ) {
            throw new IllegalArgumentException( "(" +  name + ")Excelシートは、存在しません" ) ;
        }
        startYPos -- ;// ExcelのRow位置にあわせる.
        if( startXPos <= -1 || startXPos > 65535 || startYPos <= -1 || startYPos > 65535 ) {
            throw new IllegalArgumentException( "(" +  name + ")開始ポジションが不正です(startX:" +
                startXPos + " startY:" + startYPos + ")" ) ;
        }
        if( width <= -1 || width > 65535 || height <= -1 || height > 65535 ) {
            throw new IllegalArgumentException( "(" +  name + ")コピー範囲が不正です(width:" +
                width + " height:" + height + ")" ) ;
        }
        
        HSSFCellStyle[] st = new HSSFCellStyle[ width * height ] ;
        for( int i = 0,k = 0 ; i < height ; i ++ ) {
            for( int j = 0 ; j < width ; j ++ ) {
                HSSFRow row = sheet.getRow( startYPos+i ) ;
                if( row == null ) {
                    st[ k ] = null ;
                    k ++ ;
                    continue ;
                }
                HSSFCell cell = row.getCell( (short)(startXPos+j) );
                if( cell == null ) {
                    st[ k ] = null ;
                    k ++ ;
                    continue ;
                }
                st[ k ] = cell.getCellStyle() ;
                k ++ ;
            }
        }
        this.name = name ;
        this.styles = st ;
        this.width = width ;
        this.height = height ;
        this.startX = startXPos ;
        this.startY = startYPos ;
        this.nowPos = 0 ;
        this.writeByInsertFlag = false ;
    }
    
    /**
     * コンストラクタ.
     * @param name セルスタイル名を設定します.
     * @param sheet 対象のExcelシートオブジェクトを設定します.
     * @param startXPos コピー開始位置X(ExcelA-Z座標)を設定します.
     * @param startYPos コピー開始位置Yを設定します.
     * @param width Width値を設定します.
     * @param height Height値を設定します.
     * @exception Exception 例外.
     */
    public CellStyle( String name,HSSFSheet sheet,String startXPos,int startYPos,int width,int height )
        throws Exception {
        this( name,sheet,ExcelUtil.getPosAz( startXPos ),startYPos,width,height ) ;
    }
    
    /**
     * コンストラクタ.
     * @param bean CellStyleBeanを設定します.
     * @param sheet 対象のExcelシートオブジェクトを設定します.
     * @exception Exception 例外.
     */
    public CellStyle( CellStyleBean bean,HSSFSheet sheet )
        throws Exception {
        this( bean.getName(),sheet,bean.getStartX(),bean.getStartY(),bean.getWidth(),bean.getHeight() ) ;
    }
    
    protected void finalize() throws Exception {
        destroy() ;
    }
    
    /**
     * オブジェクト破棄.
     */
    public void destroy() {
        name = null ;
        width = -1 ;
        height = -1 ;
        styles = null ;
        startX = -1 ;
        startY = -1 ;
        nowPos = 0 ;
        writeByInsertFlag = false ;
    }
    
    /**
     * セルスタイルコピー.
     * @param sheet 対象のExcelシートオブジェクトを設定します.
     * @param startXPos コピー開始位置X(ExcelA-Z座標)を設定します.
     * @param startYPos コピー開始位置Yを設定します.
     * @exception Exception 例外.
     */
    public void copy( HSSFSheet sheet,String startXPos,int startYPos )
        throws Exception {
        copy( sheet,ExcelUtil.getPosAz( startXPos ),startYPos ) ;
    }
    
    /**
     * セルスタイルコピー.
     * @param sheet 対象のExcelシートオブジェクトを設定します.
     * @param startXPos コピー開始位置Xを設定します.
     * @param startYPos コピー開始位置Yを設定します.
     * @exception Exception 例外.
     */
    public void copy( HSSFSheet sheet,int startXPos,int startYPos )
        throws Exception {
        if( isUse() == false ) {
            throw new IOException( "オブジェクトは既に破棄されています" ) ;
        }
        if( sheet == null ) {
            throw new IllegalArgumentException( "Excelシートは、存在しません" ) ;
        }
        if( startXPos <= -1 || startXPos > 65535 || startYPos <= -1 || startYPos > 65535 ) {
            throw new IllegalArgumentException( "開始ポジションが不正です(startX:" +
                startXPos + " startY:" + startYPos + ")" ) ;
        }
        for( int i = 0,k = 0 ; i < height ; i ++ ) {
            for( int j = 0 ; j < width ; j ++ ) {
                if( styles[ k ] == null ) {
                    k ++ ;
                    continue ;
                }
                HSSFRow row = sheet.getRow( startYPos+i ) ;
                if( row == null ) {
                    row = sheet.createRow( startYPos+i ) ;
                }
                HSSFCell cell = row.getCell( (short)(startXPos+j) ) ;
                if( cell == null ) {
                    cell = row.createCell( (short)(startXPos+j) ) ;
                }
                cell.setCellStyle( styles[ k ] ) ;
                k ++ ;
            }
        }
    }
    
    /**
     * Width値を取得.
     * @return int Width値が返されます.
     */
    public int getWidth() {
        return width ;
    }
    
    /**
     * Height値を取得.
     * @return int Height値が返されます.
     */
    public int getHeight() {
        return height ;
    }
    
    /**
     * startX値を取得.
     * @return int startX値が返されます.
     */
    public int getStartX() {
        return startX ;
    }
    
    /**
     * startY値を取得.
     * @return int startY値が返されます.
     */
    public int getStartY() {
        return startY ;
    }
    
    /**
     * startY値に対して、情報を増やす.
     * @param addNumber 追加数値を設定します.
     */
    public void addStartY( int addNumber ) {
        startY += addNumber ;
    }
    
    /**
     * セルスタイル名を取得.
     * @return String セルスタイル名が返されます.
     */
    public String getName() {
        return name ;
    }
    
    /**
     * オブジェクトが有効かチェック.
     * @return boolean [true]の場合、有効です.
     */
    public boolean isUse() {
        return ( styles != null ) ;
    }
    
    /**
     * 指定セルポジションが範囲内かチェック.
     * @param x セルポジションX値(ExcelA-Z座標)を設定します.
     * @param y セルポジションY値を設定します.
     * @return boolean [true]の場合、範囲内です.
     */
    public boolean isGroup( String x,int y ) {
        return isGroup( ExcelUtil.getPosAz( x ),y ) ;
    }
    
    /**
     * 指定セルポジションが範囲内かチェック.
     * @param x セルポジションX値を設定します.
     * @param y セルポジションY値を設定します.
     * @return boolean [true]の場合、範囲内です.
     */
    public boolean isGroup( int x,int y ) {
        return ( x >= startX && x <= startX+width &&
            y >= startY && y <= startY+height ) ;
    }
    
    /**
     * nowPos を取得.
     * <BR><BR>
     * @return int nowPos が返されます.
     */
    public int getNowPos() {
        return nowPos ;
    }
    
    /**
     * nowPos を設定.
     * <BR><BR>
     * @param nowPos nowPos を設定します.
     */
    public void setNowPos( int nowPos ) {
        this.nowPos = nowPos ;
    }
    
    /**
     * 現在のRow位置を取得.
     * @return int 現在のRow位置が返されます.
     */
    public int getNowRow() {
        return startY + ( height * (nowPos+1) ) ;
    }
    
    /**
     * 現在のRow位置を１インクリメント.
     */
    public void addNowRow() {
        this.nowPos ++ ;
    }
    
    /**
     * 指定位置が、セルポジションより、下に存在するかチェック.
     * @param y 対象のYを設定します.
     * @return boolean [true]の場合、下に存在します.
     */
    public boolean isUnderRow( int y ) {
        return ( startY + ( height * (nowPos+1) ) <= y ) ;
    }
    
    /**
     * Insert可能か否かのフラグをONに設定.
     */
    public void insert() {
        writeByInsertFlag = true ;
    }
    
    /**
     * Insert可能か否かのフラグを取得.
     * @return boolean [true]の場合、Insert可能です.
     */
    public boolean isInsert() {
        boolean ret = writeByInsertFlag ;
        writeByInsertFlag = false ;
        return ret ;
    }
    
    /**
     * 文字列に出力.
     * @return String 文字列に出力します.
     */
    public String toString() {
        return new StringBuilder().
            append( " CellStyle = {" ).
            append( " name:" ).append( name ).
            append( " startX:" ).append( startX ).
            append( " startY:" ).append( startY ).
            append( " width:" ).append( width ).
            append( " height:" ).append( height ).
            append( " nowPos:" ).append( nowPos ).
            append( "}" ).
            toString() ;
    }
}

