using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Text;

namespace NFine.Code.Excel
{
    public class NPOIExcel
    {
        private string _title;
        private string _sheetName;
        private string _filePath;

        /// <summary>
        /// 导出到Excel
        /// </summary>
        /// <param name="table"></param>
        /// <returns></returns>
        public bool ToExcel(DataTable table)
        {
            FileStream fs = new FileStream(this._filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
            IWorkbook workBook = new HSSFWorkbook();
            this._sheetName = this._sheetName.IsEmpty() ? "sheet1" : this._sheetName;
            ISheet sheet = workBook.CreateSheet(this._sheetName);

            //处理表格标题
            IRow row = sheet.CreateRow(0);
            row.CreateCell(0).SetCellValue(this._title);
            sheet.AddMergedRegion(new CellRangeAddress(0, 0, 0, table.Columns.Count - 1));
            row.Height = 500;

            ICellStyle cellStyle = workBook.CreateCellStyle();
            IFont font = workBook.CreateFont();
            font.FontName = "微软雅黑";
            font.FontHeightInPoints = 17;
            cellStyle.SetFont(font);
            cellStyle.VerticalAlignment = VerticalAlignment.Center;
            cellStyle.Alignment = HorizontalAlignment.Center;
            row.Cells[0].CellStyle = cellStyle;

            //处理表格列头
            row = sheet.CreateRow(1);
            for (int i = 0; i < table.Columns.Count; i++)
            {
                row.CreateCell(i).SetCellValue(table.Columns[i].ColumnName);
                row.Height = 350;
                sheet.AutoSizeColumn(i);
            }

            //处理数据内容
            for (int i = 0; i < table.Rows.Count; i++)
            {
                row = sheet.CreateRow(2 + i);
                row.Height = 250;
                for (int j = 0; j < table.Columns.Count; j++)
                {
                    row.CreateCell(j).SetCellValue(table.Rows[i][j].ToString());
                    sheet.SetColumnWidth(j, 256 * 15);
                }
            }

            //写入数据流
            workBook.Write(fs);
            fs.Flush();
            fs.Close();

            return true;
        }

        /// <summary>
        /// 导出到Excel
        /// </summary>
        /// <param name="table"></param>
        /// <param name="title"></param>
        /// <param name="sheetName"></param>
        /// <returns></returns>
        public bool ToExcel(DataTable table, string title, string sheetName, string filePath)
        {
            this._title = title;
            this._sheetName = sheetName;
            this._filePath = filePath;
            return ToExcel(table);
        }

        /// <summary>
        ///  组装workbook.
        /// </summary>
        /// <param name="dictionary">列头</param>
        /// <param name="dt">dataTable数据</param>
        /// <param name="columnHeader">表头</param>
        /// <returns></returns>
        public HSSFWorkbook BuildWorkbook(Dictionary<string, string> dictionary, DataTable dt, string columnHeader = "")
        {
            var workbook = new HSSFWorkbook();
            ISheet sheet = workbook.CreateSheet(string.IsNullOrWhiteSpace(dt.TableName) ? "Sheet1" : dt.TableName);

            var dateStyle = workbook.CreateCellStyle();
            var format = workbook.CreateDataFormat();
            dateStyle.DataFormat = format.GetFormat("yyyy-mm-dd");

            //取得列宽
            // var arrColWidth = new int[dt.Columns.Count];
            var arrColWidth = new int[dictionary.Count + 1];
            int itemCoutn = 0;//需要导出的列的数量.
            foreach (DataColumn item in dt.Columns)
            {
                //判断需要导出的 “列”

                if (dictionary.ContainsKey(item.ColumnName))
                {
                    arrColWidth[itemCoutn] = Encoding.GetEncoding(936).GetBytes(item.ColumnName.ToString()).Length;
                    itemCoutn++;
                }
            }
            itemCoutn = 0;
            for (var i = 0; i < dt.Rows.Count; i++)
            {
                for (var j = 0; j < dt.Columns.Count; j++)
                {
                    //判断需要导出的 “列”
                    if (dictionary.ContainsKey(dt.Rows[i][j].ToString()))
                    {
                        int intTemp = Encoding.GetEncoding(936).GetBytes(dt.Rows[i][j].ToString()).Length;
                        if (intTemp > arrColWidth[j])
                        {
                            arrColWidth[j] = intTemp;
                        }
                    }
                }
            }
            int rowIndex = 0;//行索引,第一行为:表头(列头)

            foreach (DataRow row in dt.Rows)
            {
                #region 表头 列头
                if (rowIndex == 65535 || rowIndex == 0)
                {
                    if (rowIndex != 0)
                    {
                        sheet = workbook.CreateSheet();
                    }

                    #region 表头及样式
                    {
                        IRow headerRow = sheet.CreateRow(0);
                        headerRow.HeightInPoints = 19.5F;
                        headerRow.Height = 40 * 20;
                        headerRow.CreateCell(0).SetCellValue(columnHeader);

                        //CellStyle
                        ICellStyle headStyle = workbook.CreateCellStyle();
                        headStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;// 左右居中    
                        headStyle.VerticalAlignment = VerticalAlignment.Center;// 上下居中 
                        // 设置单元格的背景颜色(单元格的样式会覆盖列或行的样式)    
                        headStyle.FillForegroundColor = (short)11;
                        //定义font
                        IFont font = workbook.CreateFont();
                        font.FontHeightInPoints = 20;
                        font.Boldweight = 700;
                        headStyle.SetFont(font);
                        headerRow.GetCell(0).CellStyle = headStyle;
                        //根据表的列数计算
                        //sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(0, 0, 0, dt.Columns.Count - 1));
                        sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(0, 0, 0, dictionary.Count));
                        #endregion

                    }
                    {
                        #region 列头及样式

                        var headerRow = sheet.CreateRow(1);
                        //CellStyle
                        ICellStyle headStyle = workbook.CreateCellStyle();
                        headStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;// 左右居中    
                        headStyle.VerticalAlignment = VerticalAlignment.Center;// 上下居中 
                        //定义font
                        IFont font = workbook.CreateFont();
                        font.FontHeightInPoints = 10;
                        font.Boldweight = 700;
                        headStyle.SetFont(font);

                        int columnCount = 0;
                        foreach (var dic in dictionary)
                        {
                            foreach (DataColumn column in dt.Columns)
                            {
                                //判断需要导出的 “列”
                                if (dic.Key.ToLower() == column.ColumnName.ToLower())
                                {
                                    //headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
                                    //headerRow.GetCell(column.Ordinal).CellStyle = headStyle;
                                    //sheet.SetColumnWidth(column.Ordinal, (arrColWidth[column.Ordinal] + 1) * 256);
                                    headerRow.CreateCell(columnCount).SetCellValue(dic.Value);//column.ColumnName
                                    headerRow.GetCell(columnCount).CellStyle = headStyle;
                                    sheet.SetColumnWidth(columnCount, (arrColWidth[columnCount]) * 256);
                                    columnCount++;
                                    continue;
                                }
                            }
                        }
                        #endregion
                    }

                    rowIndex = 2;
                }
                #endregion


                #region 内容
                var dataRow = sheet.CreateRow(rowIndex);

                int columnContentCount = 0; //column.Ordinal
                foreach (var dicKey in dictionary)
                {
                    foreach (DataColumn column in dt.Columns)
                    {
                        //判断需要导出的 “列”
                        if (dicKey.Key.ToLower() == column.ColumnName.ToLower())
                        {
                            var newCell = dataRow.CreateCell(columnContentCount);

                            string drValue = row[column].ToString();

                            switch (column.DataType.ToString())
                            {
                                case "System.String"://字符串类型
                                    newCell.SetCellValue(drValue);
                                    break;
                                case "System.DateTime"://日期类型
                                    DateTime dateV;
                                    DateTime.TryParse(drValue, out dateV);
                                    newCell.SetCellValue(dateV);

                                    newCell.CellStyle = dateStyle;//格式化显示
                                    break;
                                case "System.Boolean"://布尔型
                                    bool boolV = false;
                                    bool.TryParse(drValue, out boolV);
                                    newCell.SetCellValue(boolV);
                                    break;
                                case "System.Int16"://整型
                                case "System.Int32":
                                case "System.Int64":
                                case "System.Byte":
                                    int intV = 0;
                                    int.TryParse(drValue, out intV);
                                    newCell.SetCellValue(intV);
                                    break;
                                case "System.Decimal"://浮点型
                                case "System.Double":
                                    double doubV = 0;
                                    double.TryParse(drValue, out doubV);
                                    newCell.SetCellValue(doubV);
                                    break;
                                case "System.DBNull"://空值处理
                                    newCell.SetCellValue("");
                                    break;
                                default:
                                    newCell.SetCellValue("");
                                    break;
                            }
                            columnContentCount++;//列索引
                            continue;
                        }
                    }
                }

                #endregion

                rowIndex++;
            }
            //自动列宽
            for (int i = 0; i <= dictionary.Count; i++)
                sheet.AutoSizeColumn(i, true);


            return workbook;
        }
    }
}