package org.hy.common.report.bean;

import java.util.Hashtable;
import java.util.Map;

import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.hy.common.Help;
import org.hy.common.report.ExcelHelp;





/**
 * 工作薄 
 *
 * @author      ZhengWei(HY)
 * @createDate  2017-03-18
 * @version     v1.0
 *              v2.0  2017-09-11  1. 添加外界(第三方)创建样式、字体,并通过标记ID保存,方便二次引用的功能。
 *                                   建议人:李浩
 *              v2.1  2017-09-20  1. 修复:getCellStyleByCopy() 在动态改变单元格颜色时,可能出现颜色ID相同后,相互覆盖的问题。
 *                                2. 修复:getFontByCopy()      在动态改变单元格字体时,可能出现字体ID相同后,相互覆盖的问题。
 *              v3.0  2020-05-29  1. 添加:字体ID、样式ID生成,即唯一性的维护按新规则,不再按字体索引、样式索引管理。
 */
public class RWorkbook
{
    
    /** 工作薄 */
    private Workbook workbook;
    
    /** 
     * 工作薄所用到的模板中的字体信息。
     * 
     * 此字体为已在工作薄中创建过的字体,是本工作薄的字体对象,不是模板的。
     * 
     * Map.key 为字体ID
     */
    private Map<String ,Font> fonts;
    
    /** 
     * 工作薄所用到的模板中的单元格样式信息。
     * 
     * 此单元格样式为已在工作薄中创建过的单元格样式,是本工作薄的单元格样式对象,不是模板的。
     * 
     * Map.key 为样式ID
     */
    private Map<String ,CellStyle> cellStyles;
    
    /**
     * 第三方用户动态通过克隆创建出来的样式。
     * 
     * Map.key    为第三方自行定义的标识
     */
    private Map<String ,CellStyle> cellStylesByCopy;
    
    /**
     * 第三方用户动态通过克隆创建出来的字体。
     * 
     * Map.key    为第三方自行定义的标识
     */
    private Map<String ,Font> fontsByCopy;

    
    
    public RWorkbook()
    {
        this(null);
    }
    
    
    
    public RWorkbook(Workbook i_Workbook)
    {
        this.workbook         = i_Workbook;
        this.fonts            = new Hashtable<String ,Font>();
        this.cellStyles       = new Hashtable<String ,CellStyle>();
        this.cellStylesByCopy = new Hashtable<String ,CellStyle>();
    }
    
    
    
    /**
     * 保存工作薄
     * 
     * @author      ZhengWei(HY)
     * @createDate  2017-07-27
     * @version     v1.0
     *
     * @param i_SaveFile  保存的全路径+文件名称。当没有写扩展名称或类型不匹配时,自动识别添加
     * @return            保存成功返回:文件全路径+文件名称;异常返回:null
     */
    public final String save(String i_SaveFile)
    {
        return ExcelHelp.save(this ,i_SaveFile);
    }
    
    
    
    /**
     * 生成字体ID
     * 
     * @author      ZhengWei(HY)
     * @createDate  2020-05-29
     * @version     v1.0
     *
     * @param i_Font
     * @return
     */
    public static String makeFontID(Font i_Font)
    {
        StringBuilder v_Buffer = new StringBuilder();
        
        if ( i_Font instanceof HSSFFont )
        {
            HSSFFont v_Font = (HSSFFont)i_Font;
            
            v_Buffer.append(Help.NVL(v_Font.getFontName() ,"FN"));
            v_Buffer.append("_");
            v_Buffer.append(v_Font.getFontHeight());
            v_Buffer.append("_");
            v_Buffer.append(v_Font.getFontHeightInPoints());
            v_Buffer.append("_B");
            v_Buffer.append(v_Font.getBold() ? "1" : "0");
            v_Buffer.append("_I");
            v_Buffer.append(v_Font.getItalic() ? "1" : "0");
            v_Buffer.append("_S");
            v_Buffer.append(v_Font.getStrikeout() ? "1" : "0");
            v_Buffer.append("_U");
            v_Buffer.append(v_Font.getUnderline());
            v_Buffer.append("_T");
            v_Buffer.append(v_Font.getTypeOffset());
            v_Buffer.append("_C");
            v_Buffer.append(v_Font.getColor());
            v_Buffer.append("_");
            v_Buffer.append(v_Font.getCharSet());
        }
        else if ( i_Font instanceof XSSFFont )
        {
            XSSFFont v_Font = (XSSFFont)i_Font;
            
            v_Buffer.append(Help.NVL(v_Font.getFontName() ,"FN"));
            v_Buffer.append("_");
            v_Buffer.append(v_Font.getFontHeight());
            v_Buffer.append("_");
            v_Buffer.append(v_Font.getFontHeightInPoints());
            v_Buffer.append("_B");
            v_Buffer.append(v_Font.getBold() ? "1" : "0");
            v_Buffer.append("_I");
            v_Buffer.append(v_Font.getItalic() ? "1" : "0");
            v_Buffer.append("_S");
            v_Buffer.append(v_Font.getStrikeout() ? "1" : "0");
            v_Buffer.append("_U");
            v_Buffer.append(v_Font.getUnderline());
            v_Buffer.append("_T");
            v_Buffer.append(v_Font.getTypeOffset());
            v_Buffer.append("_TC");
            v_Buffer.append(v_Font.getThemeColor());
            v_Buffer.append("_");
            v_Buffer.append(v_Font.getCharSet());
            v_Buffer.append("_S");
            v_Buffer.append(v_Font.getScheme());
            
            v_Buffer.append("_C");
            if ( v_Font.getXSSFColor() != null )
            {
                v_Buffer.append(Help.NVL(v_Font.getXSSFColor().getARGBHex() ,v_Font.getColor()));
            }
            else
            {
                v_Buffer.append(v_Font.getColor());
            }
        }
        
        return v_Buffer.toString();
    }
    
    
    
    /**
     * 生成样式ID
     * 
     * @author      ZhengWei(HY)
     * @createDate  2020-05-29
     * @version     v1.0
     *
     * @param i_CellStyle
     * @param i_Font
     * @return
     */
    public static String makeCellStyleID(CellStyle i_CellStyle ,Font i_Font)
    {
        StringBuilder v_Buffer = new StringBuilder();
        
        if ( i_CellStyle instanceof HSSFCellStyle )
        {
            HSSFCellStyle v_CellStyle = (HSSFCellStyle)i_CellStyle;
            
            v_Buffer.append(v_CellStyle.getAlignmentEnum());
            v_Buffer.append("_DF");
            v_Buffer.append(v_CellStyle.getDataFormat());
            
            // 边框和边框颜色
            v_Buffer.append("_BB");
            v_Buffer.append(v_CellStyle.getBorderBottomEnum());
            v_Buffer.append("_BL");
            v_Buffer.append(v_CellStyle.getBorderLeftEnum());
            v_Buffer.append("_BR");
            v_Buffer.append(v_CellStyle.getBorderRightEnum());
            v_Buffer.append("_BT");
            v_Buffer.append(v_CellStyle.getBorderTopEnum());
            v_Buffer.append("_CBL");
            v_Buffer.append(v_CellStyle.getLeftBorderColor());
            v_Buffer.append("_CBR");
            v_Buffer.append(v_CellStyle.getRightBorderColor());
            v_Buffer.append("_CBT");
            v_Buffer.append(v_CellStyle.getTopBorderColor());
            v_Buffer.append("_CBB");
            v_Buffer.append(v_CellStyle.getBottomBorderColor());
            
            // 背景和前景
            v_Buffer.append("_CFB");
            v_Buffer.append(v_CellStyle.getFillBackgroundColor());
            v_Buffer.append("_CFF");
            v_Buffer.append(v_CellStyle.getFillForegroundColor());
            v_Buffer.append("_CFP");
            v_Buffer.append(v_CellStyle.getFillPatternEnum());
            v_Buffer.append("_H");
            v_Buffer.append(v_CellStyle.getHidden());
            
            // 首行缩进
            v_Buffer.append("_I");
            v_Buffer.append(v_CellStyle.getIndention());
            v_Buffer.append("_L");
            v_Buffer.append(v_CellStyle.getLocked());

            // 旋转
            v_Buffer.append("_SF");
            v_Buffer.append(v_CellStyle.getShrinkToFit());
            v_Buffer.append("_R");
            v_Buffer.append(v_CellStyle.getRotation());
            v_Buffer.append("_VA");
            v_Buffer.append(v_CellStyle.getVerticalAlignmentEnum());
            v_Buffer.append("_WT");
            v_Buffer.append(v_CellStyle.getWrapText());
            
            v_Buffer.append("_QP");
            v_Buffer.append(v_CellStyle.getQuotePrefixed());
            v_Buffer.append("_RO");
            v_Buffer.append(v_CellStyle.getReadingOrder());
            v_Buffer.append("_USN");
            v_Buffer.append(v_CellStyle.getUserStyleName());
        }
        else if ( i_CellStyle instanceof XSSFCellStyle )
        {
            XSSFCellStyle v_CellStyle = (XSSFCellStyle)i_CellStyle;
            
            v_Buffer.append(v_CellStyle.getAlignmentEnum());
            v_Buffer.append("_DF");
            v_Buffer.append(v_CellStyle.getDataFormat());
            
            // 边框和边框颜色
            v_Buffer.append("_BB");
            v_Buffer.append(v_CellStyle.getBorderBottomEnum());
            v_Buffer.append("_BL");
            v_Buffer.append(v_CellStyle.getBorderLeftEnum());
            v_Buffer.append("_BR");
            v_Buffer.append(v_CellStyle.getBorderRightEnum());
            v_Buffer.append("_BT");
            v_Buffer.append(v_CellStyle.getBorderTopEnum());
            
            v_Buffer.append("_CBL");
            if ( v_CellStyle.getLeftBorderXSSFColor() != null )
            {
                v_Buffer.append(Help.NVL(v_CellStyle.getLeftBorderXSSFColor().getARGBHex() ,v_CellStyle.getLeftBorderColor()));
            }
            else
            {
                v_Buffer.append(v_CellStyle.getLeftBorderColor());
            }
            
            v_Buffer.append("_CBR");
            if ( v_CellStyle.getRightBorderXSSFColor() != null )
            {
                v_Buffer.append(Help.NVL(v_CellStyle.getRightBorderXSSFColor().getARGBHex() ,v_CellStyle.getRightBorderColor()));
            }
            else
            {
                v_Buffer.append(v_CellStyle.getRightBorderColor());
            }
            
            v_Buffer.append("_CBT");
            if ( v_CellStyle.getTopBorderXSSFColor() != null )
            {
                v_Buffer.append(Help.NVL(v_CellStyle.getTopBorderXSSFColor().getARGBHex() ,v_CellStyle.getTopBorderColor()));
            }
            else
            {
                v_Buffer.append(v_CellStyle.getTopBorderColor());
            }
            
            v_Buffer.append("_CBB");
            if ( v_CellStyle.getBottomBorderXSSFColor() != null )
            {
                v_Buffer.append(Help.NVL(v_CellStyle.getBottomBorderXSSFColor().getARGBHex() ,v_CellStyle.getBottomBorderColor()));
            }
            else
            {
                v_Buffer.append(v_CellStyle.getBottomBorderColor());
            }
            
            // 背景和前景
            v_Buffer.append("_CFB");
            if ( v_CellStyle.getFillBackgroundXSSFColor() != null )
            {
                v_Buffer.append(Help.NVL(v_CellStyle.getFillBackgroundXSSFColor().getARGBHex() ,v_CellStyle.getFillBackgroundColor()));
            }
            else if ( v_CellStyle.getFillBackgroundColorColor() != null )
            {
                v_Buffer.append(Help.NVL(v_CellStyle.getFillBackgroundColorColor().getARGBHex() ,v_CellStyle.getFillBackgroundColor()));
            }
            else
            {
                v_Buffer.append(v_CellStyle.getFillBackgroundColor());
            }
            
            v_Buffer.append("_CFF");
            if ( v_CellStyle.getFillForegroundXSSFColor() != null )
            {
                v_Buffer.append(Help.NVL(v_CellStyle.getFillForegroundXSSFColor().getARGBHex() ,v_CellStyle.getFillForegroundColor()));
            }
            else if ( v_CellStyle.getFillForegroundColorColor() != null )
            {
                v_Buffer.append(Help.NVL(v_CellStyle.getFillForegroundColorColor().getARGBHex() ,v_CellStyle.getFillForegroundColor()));
            }
            else
            {
                v_Buffer.append(v_CellStyle.getFillForegroundColor());
            }
            
            v_Buffer.append("_CFP");
            v_Buffer.append(v_CellStyle.getFillPatternEnum());
            v_Buffer.append("_H");
            v_Buffer.append(v_CellStyle.getHidden());
            
            // 首行缩进
            v_Buffer.append("_I");
            v_Buffer.append(v_CellStyle.getIndention());
            v_Buffer.append("_L");
            v_Buffer.append(v_CellStyle.getLocked());

            // 旋转
            v_Buffer.append("_SF");
            v_Buffer.append(v_CellStyle.getShrinkToFit());
            v_Buffer.append("_R");
            v_Buffer.append(v_CellStyle.getRotation());
            v_Buffer.append("_VA");
            v_Buffer.append(v_CellStyle.getVerticalAlignmentEnum());
            v_Buffer.append("_WT");
            v_Buffer.append(v_CellStyle.getWrapText());
            
            v_Buffer.append("_QP");
            v_Buffer.append(v_CellStyle.getQuotePrefixed());
        }
        
        v_Buffer.append("_CSF_");
        v_Buffer.append(makeFontID(i_Font));
        
        return v_Buffer.toString();
    }
    
    
    
    /**
     * 获取模板指定位置上的已转为本工作薄的字体
     * 
     * 目前看,只用于2003的版本(*.xls),2007的版本是可以直接 setFont() 方法设置字体的。
     * 
     * @author      ZhengWei(HY)
     * @createDate  2017-03-18
     * @version     v1.0
     *
     * @param i_RTemplate  模板对象
     * @param i_IDX        字体在模板中的索引位置
     * @return
     */
    public synchronized Font getFont(RTemplate i_RTemplate ,int i_IDX)
    {
        Font   v_FromFont = i_RTemplate.getTemplateSheet().getWorkbook().getFontAt((short)i_IDX);
        String v_FontID   = makeFontID(v_FromFont);
        Font   v_ToFont   = this.fonts.get(v_FontID);
        
        if ( v_ToFont == null )
        {
            v_ToFont = this.workbook.createFont();
            ExcelHelp.copyFont(v_FromFont ,v_ToFont);
            
            this.fonts.put(v_FontID ,v_ToFont);
        }
        
        return v_ToFont;
    }
    
    
    
    /**
     * 获取模板指定位置上的已转为本工作薄的单元格样式
     * 
     * 目前看,只用于2003的版本(*.xls),2007的版本是可以直接 setCellStyle() 方法设置字体的。
     * 
     * @author      ZhengWei(HY)
     * @createDate  2017-03-18
     * @version     v1.0
     *
     * @param i_RTemplate  模板对象
     * @param i_IDX        单元格样式在模板中的索引位置
     * @return
     */
    public synchronized CellStyle getCellStyle(RTemplate i_RTemplate ,int i_IDX)
    {
        CellStyle v_FromCellStyle = i_RTemplate.getTemplateSheet().getWorkbook().getCellStyleAt(i_IDX);
        Font      v_FromFont      = i_RTemplate.getTemplateSheet().getWorkbook().getFontAt(v_FromCellStyle.getFontIndex());
        String    v_CellStyleID   = makeCellStyleID(v_FromCellStyle ,v_FromFont);
        CellStyle v_ToCellStyle   = this.cellStyles.get(v_CellStyleID);
        
        if ( v_ToCellStyle == null )
        {
            v_ToCellStyle = this.workbook.createCellStyle();
            
            ExcelHelp.copyCellStyle(v_FromCellStyle ,v_ToCellStyle);
            Font v_ToFont = this.getFont(i_RTemplate ,v_FromFont.getIndex());
            
            v_ToCellStyle.setFont(v_ToFont);
            
            this.cellStyles.put(v_CellStyleID ,v_ToCellStyle);
        }
        
        return v_ToCellStyle;
    }
    
    
    
    /**
     * 创建一个新的样式,样式从i_DataCell中克隆出来。
     * 
     * @author      ZhengWei(HY)
     * @createDate  2017-09-11
     * @version     v1.0
     *
     * @param i_ID         标记ID。由调用者设定
     * @param i_DataCell   被克隆的单元格样式
     * @return
     */
    public synchronized CellStyle getCellStyleByCopy(String i_ID ,Cell i_DataCell ,RTemplate i_RTemplate)
    {
        CellStyle v_NewCellStyle = this.cellStylesByCopy.get(i_ID);
        
        if ( v_NewCellStyle == null )
        {
            v_NewCellStyle = this.workbook.createCellStyle();
            
            ExcelHelp.copyCellStyle(i_DataCell.getCellStyle(), v_NewCellStyle);
            
            Font v_FromFont = this.workbook.getFontAt(i_DataCell.getCellStyle().getFontIndex());
            Font v_NewFont  = this.workbook.createFont();
            ExcelHelp.copyFont(v_FromFont ,v_NewFont);
            
            v_NewCellStyle.setFont(v_NewFont);
            
            this.cellStylesByCopy.put(i_ID ,v_NewCellStyle);
        }
        
        return v_NewCellStyle;
    }
    
    
    
    /**
     * 创建一个新的字体,字体从i_DataCell中克隆出来。
     * 
     * @author      ZhengWei(HY)
     * @createDate  2017-09-11
     * @version     v1.0
     *
     * @param i_ID         标记ID。由调用者设定
     * @param i_DataCell   被克隆的单元格样式
     * @return
     */
    public synchronized Font getFontByCopy(String i_ID ,Cell i_DataCell ,RTemplate i_RTemplate)
    {
        Font v_NewFont = this.fontsByCopy.get(i_ID);
        
        if ( v_NewFont == null )
        {
            v_NewFont = this.workbook.createFont();
            
            ExcelHelp.copyFont(this.workbook.getFontAt(i_DataCell.getCellStyle().getFontIndex()) ,v_NewFont);
            
            this.fontsByCopy.put(i_ID ,v_NewFont);
        }
        
        return v_NewFont;
    }
    
    
    
    /**
     * 获取:工作薄
     */
    public Workbook getWorkbook()
    {
        return workbook;
    }

    
    
    /**
     * 设置:工作薄
     * 
     * @param workbook 
     */
    public void setWorkbook(Workbook workbook)
    {
        this.workbook = workbook;
    }

    
    
    /**
     * 工作薄所用到的模板中的字体信息。
     * 
     * 此字体为已在工作薄中创建过的字体,是本工作薄的字体对象,不是模板的。
     * 
     * Map.key 为字体ID
     */
    public Map<String ,Font> getFonts()
    {
        return fonts;
    }

    
    
    /**
     * 工作薄所用到的模板中的字体信息。
     * 
     * 此字体为已在工作薄中创建过的字体,是本工作薄的字体对象,不是模板的。
     * 
     * Map.key 为字体ID
     * 
     * @param fonts 
     */
    public void setFonts(Map<String ,Font> fonts)
    {
        this.fonts = fonts;
    }


    
    /**
     * 工作薄所用到的模板中的单元格样式信息。
     * 
     * 此单元格样式为已在工作薄中创建过的单元格样式,是本工作薄的单元格样式对象,不是模板的。
     * 
     * Map.key 为样式ID
     */
    public Map<String ,CellStyle> getCellStyles()
    {
        return cellStyles;
    }

    

    /**
     * 工作薄所用到的模板中的单元格样式信息。
     * 
     * 此单元格样式为已在工作薄中创建过的单元格样式,是本工作薄的单元格样式对象,不是模板的。
     * 
     * Map.key 为样式ID
     * 
     * @param cellStyles 
     */
    public void setCellStyles(Map<String ,CellStyle> cellStyles)
    {
        this.cellStyles = cellStyles;
    }
    
}