using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

using DocumentFormat.OpenXml.Packaging;
using Ap = DocumentFormat.OpenXml.ExtendedProperties;
using Vt = DocumentFormat.OpenXml.VariantTypes;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Spreadsheet;
using A = DocumentFormat.OpenXml.Drawing;
using System.Security.Cryptography;

namespace IronIntel.Contractor
{
    internal class ExcelXlsx
    {
        public ExcelXlsx() { }

        private Dictionary<string, UInt32Value> _fontIndexCache = new Dictionary<string, UInt32Value>();
        private Dictionary<string, UInt32Value> _fillIndexCache = new Dictionary<string, UInt32Value>();
        private Dictionary<string, UInt32Value> _borderIndexCache = new Dictionary<string, UInt32Value>();
        private Dictionary<string, UInt32Value> _formatIndexCache = new Dictionary<string, UInt32Value>();

        // Creates a SpreadsheetDocument.
        public void CreatePackage(MemoryStream ms, COpenXmlExcelSheet edata)
        {
            using (SpreadsheetDocument package = SpreadsheetDocument.Create(ms, SpreadsheetDocumentType.Workbook))
            {
                CExcelSheet excelSheetData = ConvertData(edata);
                CreateParts(package, excelSheetData);
            }
        }

        private CExcelSheet ConvertData(COpenXmlExcelSheet openXmlData)
        {
            CExcelSheet excelSheetData = new CExcelSheet();

            //保存每列宽度。
            foreach (double width in openXmlData.WidthList)
            {
                excelSheetData.WidthList.Add(width);
            }

            //保存每行高度。
            foreach (KeyValuePair<int, double> kvp in openXmlData.RowHeightList)
            {
                excelSheetData.RowHeightList.Add(kvp.Key, kvp.Value);
            }

            CExcelCellData excellData = null;

            //生成特定样式数据，并生成shared strings列表，合并单元格列表。
            int orderIndex = 0;
            foreach (List<IOpenXmlExcelStyleAndData> rowData in openXmlData.DataMatrix)
            {
                List<CExcelCellData> excelRowData = new List<CExcelCellData>();
                foreach (IOpenXmlExcelStyleAndData cellData in rowData)
                {
                    excellData = new CExcelCellData();
                    excelRowData.Add(excellData);

                    excellData.ApplyNumberFormat = DocumentFormat.OpenXml.BooleanValue.FromBoolean(true);
                    excellData.CAlignment = cellData.CAlignment;
                    excellData.CBorder = cellData.CBorder;
                    excellData.CFill = cellData.CFill;
                    excellData.CFont = cellData.CFont;

                    if (cellData.FormatType == CellFormatType.CSharp)
                    {
                        bool b = false;
                        if (cellData.FormatCode != null && cellData.FormatCode.Contains("{0:MMM-yyyy}"))
                        {
                            b = true;
                        }
                        excellData.FormatCode = ConvertFormat.ConvertFormatFromCSharpToExcel(cellData.FormatCode, cellData.DataType);
                        if (cellData.DataType == CellDataType.String || cellData.DataType == CellDataType.Integer)
                        {
                            if (b)
                            {
                                if (cellData.Value != null && cellData.Value.ToString().Length != 6)
                                {
                                    excellData.FormatCode = "";
                                }
                            }
                        }
                    }
                    if (string.IsNullOrEmpty(excellData.FormatCode))
                    {
                        excellData.Value = orderIndex;
                        orderIndex++;
                        excelSheetData.SharedStrings.Add(cellData.Value == null ? "" : cellData.Value.ToString());
                        excellData.DataType = CellValues.SharedString;
                        excellData.FormatCode = "";
                        excellData.NumberFormatId = 49U;
                    }
                    else
                    {
                        switch (cellData.DataType)
                        {
                            case CellDataType.Bool:
                                try
                                {

                                    int v = 0;// Convert.ToInt16(cellData.Value);
                                    if (cellData.Value == null || cellData.Value.ToString() == "0" ||
                                        string.Equals(cellData.Value.ToString(), "false", StringComparison.OrdinalIgnoreCase))
                                    {
                                        v = 0;
                                    }
                                    else
                                    {
                                        v = 1;
                                    }

                                    excellData.Value = v;
                                    excellData.DataType = CellValues.Number;
                                }
                                catch { }
                                break;
                            case CellDataType.Date:
                                try
                                {
                                    excellData.Value = Convert.ToDateTime(cellData.Value).ToOADate();
                                    excellData.DataType = CellValues.Number;
                                }
                                catch { }
                                break;
                            case CellDataType.Float:
                            case CellDataType.Integer:
                                excellData.Value = cellData.Value;
                                excellData.DataType = CellValues.Number;
                                break;
                            default:
                                //excellData.Value = orderIndex;
                                //orderIndex++;
                                //excelSheetData.SharedStrings.Add(cellData.Value == null ? "" : cellData.Value.ToString());
                                //excellData.DataType = CellValues.SharedString;
                                excellData.Value = (cellData.Value == null ? "" : cellData.Value.ToString());
                                excellData.DataType = CellValues.String;
                                excellData.FormatCode = "";
                                excellData.NumberFormatId = 49U;
                                break;
                        }
                    }

                    #region 合并单元格还没处理好。
                    if (!string.IsNullOrEmpty(cellData.MergedCellsPosition))
                    {
                        excelSheetData.MergeCellReferenceList.Add(cellData.MergedCellsPosition);
                    }
                    #endregion
                }
                excelSheetData.DataMatrix.Add(excelRowData);
            }

            return excelSheetData;
        }

        // Adds child parts and generates content of the specified part.
        private void CreateParts(SpreadsheetDocument document, CExcelSheet excelSheetData)
        {
            WorkbookPart workbookPart = document.AddWorkbookPart();
            GenerateWorkbookPart1Content(workbookPart);

            WorkbookStylesPart workbookStylesPart = workbookPart.AddNewPart<WorkbookStylesPart>("rId3");
            GenerateWorkbookStylesPart1Content(workbookStylesPart);

            WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>("rId1");
            GenerateWorksheetPart1Content(worksheetPart);

            #region columns
            Columns columns = GenerateColumns(excelSheetData.WidthList);
            worksheetPart.Worksheet.Append(columns);
            #endregion

            #region sheet data
            SheetData sheetData = GenerateSheetData(workbookStylesPart.Stylesheet, excelSheetData);
            worksheetPart.Worksheet.Append(sheetData);
            #endregion

            #region sheet merge cells
            if (excelSheetData.MergeCellReferenceList.Count > 0)
            {
                MergeCells mergeCells = GenerateMergeCell(excelSheetData.MergeCellReferenceList);
                worksheetPart.Worksheet.Append(mergeCells);
            }
            #endregion

            #region sheet shared strings
            if (excelSheetData.SharedStrings.Count > 0)
            {
                SharedStringTablePart sharedStringTablePart = workbookPart.AddNewPart<SharedStringTablePart>("rId4");
                GenerateSharedStringTablePart1Content(sharedStringTablePart, excelSheetData.SharedStrings);
            }
            #endregion
        }

        // Generates content of workbookPart1.
        private void GenerateWorkbookPart1Content(WorkbookPart workbookPart1)
        {
            Workbook workbook1 = new Workbook();
            workbook1.AddNamespaceDeclaration("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
            FileVersion fileVersion1 = new FileVersion() { ApplicationName = "xl", LastEdited = "4", LowestEdited = "4", BuildVersion = "4505" };
            WorkbookProperties workbookProperties1 = new WorkbookProperties() { DefaultThemeVersion = (UInt32Value)124226U };

            BookViews bookViews1 = new BookViews();
            WorkbookView workbookView1 = new WorkbookView() { XWindow = 120, YWindow = 120, WindowWidth = (UInt32Value)21495U, WindowHeight = (UInt32Value)9570U };

            bookViews1.Append(workbookView1);

            Sheets sheets1 = new Sheets();
            Sheet sheet1 = new Sheet() { Name = "Sheet1", SheetId = (UInt32Value)1U, Id = "rId1" };

            sheets1.Append(sheet1);
            CalculationProperties calculationProperties1 = new CalculationProperties() { CalculationId = (UInt32Value)125725U };
            FileRecoveryProperties fileRecoveryProperties1 = new FileRecoveryProperties() { RepairLoad = true };

            workbook1.Append(fileVersion1);
            workbook1.Append(workbookProperties1);
            workbook1.Append(bookViews1);
            workbook1.Append(sheets1);
            workbook1.Append(calculationProperties1);
            workbook1.Append(fileRecoveryProperties1);

            workbookPart1.Workbook = workbook1;
        }

        // Generates content of worksheetPart1.
        private void GenerateWorksheetPart1Content(WorksheetPart worksheetPart1)
        {
            Worksheet worksheet1 = new Worksheet();
            worksheet1.AddNamespaceDeclaration("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");

            #region sheet dimension
            //SheetDimension sheetDimension1 = new SheetDimension();// { Reference = "A1:H3" };
            //worksheet1.Append(sheetDimension1);
            #endregion

            #region sheet views
            SheetViews sheetViews1 = new SheetViews();

            SheetView sheetView1 = new SheetView() { TabSelected = true, WorkbookViewId = (UInt32Value)0U };
            Selection selection1 = new Selection() { ActiveCell = "A1", SequenceOfReferences = new ListValue<StringValue>() { InnerText = "A1" } };

            sheetView1.Append(selection1);
            sheetViews1.Append(sheetView1);
            worksheet1.Append(sheetViews1);
            #endregion

            #region sheet format properties
            SheetFormatProperties sheetFormatProperties1 = new SheetFormatProperties() { DefaultRowHeight = 18D, CustomHeight = true };
            worksheet1.Append(sheetFormatProperties1);
            #endregion

            #region columns 外部加入。
            //Columns columns = GenerateColumns(widthList);
            //worksheet1.Append(columns);
            #endregion

            #region sheet data  外部加入。
            //SheetData sheetData = GenerateSheetData();
            //worksheet1.Append(sheetData);
            #endregion

            #region merge cells
            #endregion

            //PhoneticProperties phoneticProperties1 = new PhoneticProperties() { FontId = (UInt32Value)1U, Type = PhoneticValues.NoConversion };
            //PageMargins pageMargins1 = new PageMargins() { Left = 0.7D, Right = 0.7D, Top = 0.75D, Bottom = 0.75D, Header = 0.3D, Footer = 0.3D };
            //PageSetup pageSetup1 = new PageSetup() { PaperSize = (UInt32Value)9U, Orientation = OrientationValues.Portrait, HorizontalDpi = (UInt32Value)200U, VerticalDpi = (UInt32Value)200U };

            //worksheet1.Append(phoneticProperties1);
            //worksheet1.Append(pageMargins1);
            //worksheet1.Append(pageSetup1);

            worksheetPart1.Worksheet = worksheet1;
        }

        private Columns GenerateColumns(List<DoubleValue> columnProperties)
        {
            Columns columns = new Columns();
            Column column = null;
            UInt32Value col = 0;
            double gain = 127.0 / 750.0;
            foreach (DoubleValue dv in columnProperties)
            {
                col++;
                column = new Column() { Min = col, Max = col, Width = dv * gain, CustomWidth = true, BestFit = true };
                columns.Append(column);
            }

            return columns;
        }

        private Row GenerateRow(int rowIndex, List<Cell> cellsInRow, int styleIndex)
        {
            if (rowIndex < 0) return null;

            Row row = new Row() { RowIndex = (UInt32)rowIndex };

            if (styleIndex >= 0)
            {
                row.StyleIndex = (UInt32)styleIndex;
            }

            if (cellsInRow.Count > 0)
            {
                row.Spans = new ListValue<StringValue>() { InnerText = "1:" + cellsInRow.Count };
            }

            foreach (Cell cell in cellsInRow)
            {
                row.Append(cell);
            }

            return row;
        }

        private Cell GenerateCell(Stylesheet styleSheet, CExcelCellData cellData)
        {
            Cell cell = new Cell();
            CellValue cellValue = new CellValue();
            if (styleSheet == null)
            {
                cell.DataType = CellValues.String;
                cellValue.Text = cellData.Value == null ? "" : cellData.Value.ToString();
                cell.Append(cellValue);
                return cell;
            }

            UInt32Value fontId = CreateFonts(styleSheet, cellData.CFont);
            UInt32Value fillId = CreateFills(styleSheet, cellData.CFill);
            UInt32Value borderId = CreateBorders(styleSheet, cellData.CBorder);

            cell.StyleIndex = CreateCellFormat(styleSheet, fontId, fillId, borderId, cellData);

            if (cellData.DataType != null && cellData.DataType.HasValue)
            {
                cell.DataType = cellData.DataType;
            }

            cellValue.Text = cellData.Value == null ? "" : cellData.Value.ToString();
            cell.Append(cellValue);

            return cell;
        }

        private string GetFontsHashString(CellFont cellFont)
        {
            StringBuilder sb = new StringBuilder();
            if (cellFont != null)
            {
                sb.AppendLine(string.IsNullOrEmpty(cellFont.FontName) ? "" : cellFont.FontName);
                if (cellFont.FontSize != null && cellFont.FontSize.HasValue)
                {
                    sb.AppendLine(cellFont.FontSize.Value.ToString());
                }
                if (cellFont.ForeColor != null)
                {
                    sb.AppendLine(cellFont.ForeColor.ToArgb().ToString());
                }
                if (cellFont.IsBold != null && cellFont.IsBold.HasValue)
                {
                    sb.AppendLine(cellFont.IsBold.Value.ToString());
                }
            }

            string result = GetHashString(sb.ToString());
            return result;
        }

        private string GetFillHashString(CellFill fill)
        {
            StringBuilder sb = new StringBuilder();
            if (fill != null)
            {
                if (fill.FillColor != null)
                {
                    sb.AppendLine(fill.FillColor.ToArgb().ToString());
                }
            }

            string result = GetHashString(sb.ToString());
            return result;
        }

        private string GetBorderHashString(CellBorder border)
        {
            StringBuilder sb = new StringBuilder();
            if (border != null)
            {
                if (border.LeftBorder != null)
                    sb.AppendLine("left");
                if (border.RightBorder != null)
                    sb.AppendLine("right");
                if (border.TopBorder != null)
                    sb.AppendLine("top");
                if (border.BottomBorder != null)
                    sb.AppendLine("bottom");
                if (border.DialogalBorder != null)
                    sb.AppendLine("dialogal");
            }

            string result = GetHashString(sb.ToString());
            return result;
        }

        private string GetFormatHashString(CellFormat cellFormat, string formateCode)
        {
            StringBuilder sb = new StringBuilder();
            if (cellFormat != null)
            {
                if (cellFormat.FontId != null && cellFormat.FontId.HasValue)
                    sb.AppendLine(cellFormat.FontId.Value.ToString());
                if (cellFormat.ApplyFont != null && cellFormat.ApplyFont.HasValue)
                    sb.AppendLine(cellFormat.ApplyFont.Value.ToString());

                if (cellFormat.FillId != null && cellFormat.FillId.HasValue)
                    sb.AppendLine(cellFormat.FillId.Value.ToString());
                if (cellFormat.ApplyFill != null && cellFormat.ApplyFill.HasValue)
                    sb.AppendLine(cellFormat.ApplyFill.Value.ToString());

                if (cellFormat.BorderId != null && cellFormat.BorderId.HasValue)
                    sb.AppendLine(cellFormat.BorderId.Value.ToString());
                if (cellFormat.ApplyBorder != null && cellFormat.ApplyBorder.HasValue)
                    sb.AppendLine(cellFormat.ApplyBorder.Value.ToString());

                if (cellFormat.ApplyNumberFormat != null && cellFormat.ApplyNumberFormat.HasValue)
                    sb.AppendLine(cellFormat.ApplyNumberFormat.Value.ToString());
                if (cellFormat.NumberFormatId != null && cellFormat.NumberFormatId.HasValue)
                    sb.AppendLine(cellFormat.NumberFormatId.Value.ToString());

                if (cellFormat.Alignment != null)
                {
                    if (cellFormat.Alignment.Horizontal != null && cellFormat.Alignment.Horizontal.HasValue)
                        sb.AppendLine(cellFormat.Alignment.Horizontal.Value.ToString());
                    if (cellFormat.Alignment.Vertical != null && cellFormat.Alignment.Vertical.HasValue)
                        sb.AppendLine(cellFormat.Alignment.Vertical.Value.ToString());
                    if (cellFormat.ApplyAlignment != null && cellFormat.ApplyAlignment.HasValue)
                        sb.AppendLine(cellFormat.ApplyAlignment.Value.ToString());
                }
            }

            sb.AppendLine(formateCode);

            string result = GetHashString(sb.ToString());
            return result;
        }

        private string GetHashString(string str)
        {
            return str;
            byte[] b1 = Encoding.UTF8.GetBytes(str);
            //Cryptography.HashCode hc = new LHBIS.Security.Cryptography.HashCode(LHBIS.Security.Cryptography.HashType.htSHA256);
            //byte[] b2 = hc.ComputeHash(b1);
            //string result = LHBIS.Security.Cryptography.CommonConvert.ToHex(b2);
            //return result;

            HashAlgorithm ha = new SHA256Managed();
            byte[] b2 = ha.ComputeHash(b1);
            string result = ToHex(b2);
            return result;
        }

        private static string ToHex(byte[] buffer)
        {
            if (buffer == null)
                return "";
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < buffer.Length; i++)
            {
                sb.Append(string.Format("{0:X2}", buffer[i]));
            }
            return sb.ToString();
        }

        private SheetData GenerateSheetData(Stylesheet styleSheet, CExcelSheet data)
        {
            SheetData sheetData = new SheetData();
            Row row = null;
            Cell cell = null;
            List<Cell> cellList = null;
            int rowIndex = 0;

            foreach (List<CExcelCellData> rowData in data.DataMatrix)
            {
                rowIndex += 1;
                cellList = new List<Cell>();
                foreach (CExcelCellData cellData in rowData)
                {
                    //no style while stylesheet is null
                    cell = GenerateCell(styleSheet, cellData);
                    cellList.Add(cell);
                }
                //初始化行的样式为-1，表示使用缺省样式。
                row = GenerateRow(rowIndex, cellList, -1);
                if (data.RowHeightList.ContainsKey(rowIndex))
                {
                    row.CustomHeight = new BooleanValue(true);
                    row.Height = new DoubleValue(data.RowHeightList[rowIndex]);
                }

                sheetData.Append(row);
            }
            return sheetData;
        }

        private UInt32Value CreateFonts(Stylesheet styleSheet, CellFont cellFont)
        {
            if (styleSheet == null || cellFont == null) return 0U;

            string key = GetFontsHashString(cellFont);
            UInt32Value ui32 = 0;
            if (_fontIndexCache.TryGetValue(key, out ui32))
            {
                return ui32;
            }

            Font font = new Font();
            if (!string.IsNullOrEmpty(cellFont.FontName))
            {
                FontName name = new FontName() { Val = cellFont.FontName };
                font.Append(name);
            }
            if (cellFont.FontSize != null && cellFont.FontSize.HasValue)
            {
                FontSize size = new FontSize() { Val = cellFont.FontSize.Value };
                font.Append(size);
            }
            if (cellFont.IsBold != null && cellFont.IsBold.Value)
            {
                Bold bold = new Bold();
                font.Append(bold);
            }
            if (cellFont.ForeColor != null)
            {
                Color color = new Color();
                color.Rgb = new HexBinaryValue();
                color.Rgb.Value = System.Drawing.ColorTranslator.ToHtml(
                    System.Drawing.Color.FromArgb(cellFont.ForeColor.A, cellFont.ForeColor.R, cellFont.ForeColor.G, cellFont.ForeColor.B)).Replace("#", "");
                font.Append(color);
            }

            FontFamilyNumbering fontFamilyNumbering = new FontFamilyNumbering() { Val = 2 };
            font.Append(fontFamilyNumbering);
            FontCharSet fontCharSet = new FontCharSet() { Val = 134 };
            font.Append(fontCharSet);
            FontScheme fontScheme = new FontScheme() { Val = FontSchemeValues.Minor };
            font.Append(fontScheme);

            if (styleSheet.Fonts == null)
            {
                styleSheet.Fonts = new Fonts();
            }
            styleSheet.Fonts.Append(font);
            UInt32Value fontID = styleSheet.Fonts.Count;
            _fontIndexCache.Add(key, fontID);

            styleSheet.Fonts.Count++;
            return fontID;
        }

        private UInt32Value CreateFills(Stylesheet styleSheet, CellFill cellFill)
        {
            if (styleSheet == null || cellFill == null) return 0U;

            string key = GetFillHashString(cellFill);
            UInt32Value ui32 = 0;
            if (_fillIndexCache.TryGetValue(key, out ui32))
            {
                return ui32;
            }

            PatternFill patternFill = new PatternFill();
            if (cellFill != null)
            {
                patternFill.Append(new ForegroundColor()
                {
                    Rgb = new HexBinaryValue()
                    {
                        Value = System.Drawing.ColorTranslator.ToHtml(
                            System.Drawing.Color.FromArgb(cellFill.FillColor.A, cellFill.FillColor.R, cellFill.FillColor.G, cellFill.FillColor.B)).Replace("#", "")
                    }
                });
                patternFill.PatternType = PatternValues.Solid;
            }
            else
            {
                patternFill.PatternType = PatternValues.None;
            }
            if (styleSheet.Fills == null)
            {
                styleSheet.Fills = new Fills();
            }

            styleSheet.Fills.Append(new Fill(patternFill));
            UInt32Value fillId = styleSheet.Fills.Count;
            _fillIndexCache.Add(key, fillId);
            styleSheet.Fills.Count++;
            return fillId;
        }

        private UInt32Value CreateBorders(Stylesheet styleSheet, CellBorder cellBorder)
        {
            if (styleSheet == null || cellBorder == null) return 0U;

            string key = GetBorderHashString(cellBorder);
            UInt32Value ui32 = 0;
            if (_borderIndexCache.TryGetValue(key, out ui32))
            {
                return ui32;
            }

            Border border = new Border();
            if (cellBorder == null) return 0;
            if (cellBorder.LeftBorder != null)
                border.Append(cellBorder.LeftBorder);
            if (cellBorder.RightBorder != null)
                border.Append(cellBorder.RightBorder);
            if (cellBorder.TopBorder != null)
                border.Append(cellBorder.TopBorder);
            if (cellBorder.BottomBorder != null)
                border.Append(cellBorder.BottomBorder);
            if (cellBorder.DialogalBorder != null)
                border.Append(cellBorder.DialogalBorder);

            if (styleSheet.Borders == null)
            {
                styleSheet.Borders = new Borders();
            }
            styleSheet.Borders.Append(border);
            UInt32Value borderId = styleSheet.Borders.Count;
            _borderIndexCache.Add(key, borderId);
            styleSheet.Borders.Count++;
            return borderId;
        }

        private UInt32Value CreateCellFormat(Stylesheet styleSheet, UInt32Value fontIndex, UInt32Value fillIndex,
            UInt32Value borderIndex, CExcelCellData cellData)
        {
            if (styleSheet == null) return 0U;

            CellFormat cellFormat = new CellFormat();
            if (fontIndex == null) fontIndex = 0;
            cellFormat.FontId = fontIndex;
            cellFormat.ApplyFont = BooleanValue.FromBoolean(true);

            if (fillIndex == null) fillIndex = 0;
            cellFormat.FillId = fillIndex;
            cellFormat.ApplyFill = BooleanValue.FromBoolean(true);

            if (borderIndex == null) borderIndex = 0;
            cellFormat.BorderId = borderIndex;
            cellFormat.ApplyBorder = BooleanValue.FromBoolean(true);

            cellFormat.ApplyNumberFormat = cellData.ApplyNumberFormat;
            cellFormat.NumberFormatId = cellData.NumberFormatId;

            if (cellData.CAlignment != null)
            {
                cellFormat.Append(cellData.CAlignment.Align);
                cellFormat.ApplyAlignment = BooleanValue.FromBoolean(true);
            }

            string key = GetFormatHashString(cellFormat, cellData.FormatCode);
            UInt32Value ui32 = 0;
            if (_formatIndexCache.TryGetValue(key, out ui32))
            {
                return ui32;
            }

            if (!string.IsNullOrEmpty(cellData.FormatCode) && cellData.FormatCode.HasValue)
            {
                cellFormat.NumberFormatId = CreateFormatId(cellData.FormatCode, styleSheet.NumberingFormats);
            }

            styleSheet.CellFormats.Append(cellFormat);
            UInt32Value cellFormatId = styleSheet.CellFormats.Count;
            _formatIndexCache.Add(key, cellFormatId);
            styleSheet.CellFormats.Count++;
            return cellFormatId;
        }

        private UInt32Value CreateFormatId(string formatCode, NumberingFormats numberingFormats)
        {
            NumberingFormat nf = numberingFormats.AppendChild(new NumberingFormat());
            numberingFormats.Count++;
            nf.FormatCode = formatCode;
            nf.NumberFormatId = GetMaxFormatId(numberingFormats);
            if (nf.NumberFormatId == 0)
            {
                nf.NumberFormatId = 176U;
            }
            else
            {
                nf.NumberFormatId += 1;
            }
            return nf.NumberFormatId;
        }

        private UInt32Value GetMaxFormatId(NumberingFormats numberingFormats)
        {
            UInt32Value maxFormatId = 0U;
            foreach (NumberingFormat nf in numberingFormats.ChildElements)
            {
                if (nf.NumberFormatId != null && nf.NumberFormatId.HasValue && nf.NumberFormatId > maxFormatId)
                    maxFormatId = nf.NumberFormatId;
            }
            return maxFormatId;
        }

        // Generates content of workbookStylesPart1.
        private void GenerateWorkbookStylesPart1Content(WorkbookStylesPart workbookStylesPart1)
        {
            Stylesheet stylesheet = new Stylesheet();

            #region default fonts
            Font font = new Font();
            FontSize fontSize = new FontSize() { Val = 11D };
            Color color = new Color() { Theme = (UInt32Value)1U };
            FontName fontName = new FontName() { Val = "宋体" };
            FontFamilyNumbering fontFamilyNumbering = new FontFamilyNumbering() { Val = 2 };
            FontCharSet fontCharSet = new FontCharSet() { Val = 134 };
            FontScheme fontScheme = new FontScheme() { Val = FontSchemeValues.Minor };

            font.Append(fontSize);
            font.Append(color);
            font.Append(fontName);
            font.Append(fontFamilyNumbering);
            font.Append(fontCharSet);
            font.Append(fontScheme);

            if (stylesheet.Fonts == null) stylesheet.Fonts = new Fonts() { Count = 2 };
            stylesheet.Fonts.Append(font);

            Font font2 = new Font();
            FontSize fontSize2 = new FontSize() { Val = 9D };
            FontName fontName2 = new FontName() { Val = "宋体" };
            FontFamilyNumbering fontFamilyNumbering2 = new FontFamilyNumbering() { Val = 2 };
            FontCharSet fontCharSet2 = new FontCharSet() { Val = 134 };
            FontScheme fontScheme2 = new FontScheme() { Val = FontSchemeValues.Minor };

            font2.Append(fontSize2);
            font2.Append(fontName2);
            font2.Append(fontFamilyNumbering2);
            font2.Append(fontCharSet2);
            font2.Append(fontScheme2);
            stylesheet.Fonts.Append(font2);
            #endregion

            #region default fills
            Fill fill = new Fill();
            PatternFill patternFill = new PatternFill() { PatternType = PatternValues.None };

            fill.Append(patternFill);

            if (stylesheet.Fills == null) stylesheet.Fills = new Fills() { Count = 2 };
            stylesheet.Fills.Append(fill);

            Fill fill2 = new Fill();
            PatternFill patternFill2 = new PatternFill() { PatternType = PatternValues.Gray125 };

            fill2.Append(patternFill2);
            stylesheet.Fills.Append(fill2);
            #endregion

            #region default border
            Border border = new Border();
            LeftBorder leftBorder = new LeftBorder();
            RightBorder rightBorder = new RightBorder();
            TopBorder topBorder = new TopBorder();
            BottomBorder bottomBorder = new BottomBorder();
            DiagonalBorder diagonalBorder = new DiagonalBorder();

            border.Append(leftBorder);
            border.Append(rightBorder);
            border.Append(topBorder);
            border.Append(bottomBorder);
            border.Append(diagonalBorder);

            if (stylesheet.Borders == null) stylesheet.Borders = new Borders() { Count = 1 };
            stylesheet.Borders.Append(border);
            #endregion

            #region cell style format
            #endregion

            #region cell numberingformats
            stylesheet.NumberingFormats = new NumberingFormats() { Count = (UInt32Value)0U };
            #endregion

            #region cell format 初始化一个cell format，因为cellXfs的索引须从1开始。
            stylesheet.CellFormats = new CellFormats() { Count = 1U };
            CellFormat cf0 = stylesheet.CellFormats.AppendChild(new CellFormat());
            cf0.NumberFormatId = 0;
            cf0.FontId = 0;
            cf0.BorderId = 0;
            cf0.FillId = 0;
            #endregion

            #region cell style
            #endregion
            workbookStylesPart1.Stylesheet = stylesheet;
        }

        // Generates content of sharedStringTablePart1.
        private void GenerateSharedStringTablePart1Content(SharedStringTablePart sharedStringTablePart1, List<string> cellValues)
        {
            SharedStringTable sharedStringTable = new SharedStringTable() { Count = UInt32Value.FromUInt32((uint)cellValues.Count), UniqueCount = UInt32Value.FromUInt32((uint)cellValues.Count) };

            SharedStringItem sharedStringItem = null;// new SharedStringItem();
            Text text = null;// new Text();
            foreach (string str in cellValues)
            {
                sharedStringItem = new SharedStringItem();
                text = new Text();

                text.Text = str;
                sharedStringItem.Append(text);
                sharedStringTable.Append(sharedStringItem);
            }

            sharedStringTablePart1.SharedStringTable = sharedStringTable;
        }

        private MergeCells GenerateMergeCell(List<string> mergeCellReferenceList)
        {
            MergeCells mcells = new MergeCells() { Count = UInt32Value.FromUInt32((uint)mergeCellReferenceList.Count) };
            if (mcells == null || mergeCellReferenceList == null || mergeCellReferenceList.Count <= 0) return mcells;
            var mergeCells = mergeCellReferenceList.Select((s) =>
            {
                return new MergeCell() { Reference = s };
            });

            foreach (var o in mergeCells)
            {
                mcells.Append(o);
            }
            return mcells;
        }
    }
}
