using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Xml.Linq; using InABox.Core; using NPOI.SS.Formula.Functions; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using NCell = NPOI.SS.UserModel.ICell; using NRow = NPOI.SS.UserModel.IRow; using NSheet = NPOI.SS.UserModel.ISheet; using NDataFormat = NPOI.SS.UserModel.IDataFormat; using NCellStyle = NPOI.SS.UserModel.ICellStyle; using NPOI.SS.Util; namespace InABox.Scripting { public class RowEnumerator : IEnumerator { private IEnumerator _enumerator { get; set; } public Row Current => new Row(_enumerator.Current as NRow); object IEnumerator.Current => new Row(_enumerator.Current as NRow); internal RowEnumerator(IEnumerator enumerator) { _enumerator = enumerator; } public bool MoveNext() { return _enumerator.MoveNext(); } public void Reset() { _enumerator.Reset(); } public void Dispose() { } } public class Sheet : ISheet { private NSheet _sheet; public string Name => _sheet.SheetName; internal Sheet(NSheet sheet) { _sheet = sheet; } public IEnumerable Rows() { var enumerator = _sheet.GetRowEnumerator(); var row = 0; while (enumerator.MoveNext() && row <= int.MaxValue) { yield return new Row((NRow)enumerator.Current); row++; } } public IEnumerator RowEnumerator() { return new RowEnumerator(_sheet.GetRowEnumerator()); } public IRow NewRow() { var row = _sheet.CreateRow(_sheet.LastRowNum + 1); return new Row(row); } public ISheet SetColumnWidth(int column, float charWidth) { _sheet.SetColumnWidth(column, (int)Math.Round(charWidth * 256)); return this; } public ISheet MergeCells(int firstRow, int lastRow, int firstColumn, int lastColumn) { var range = new CellRangeAddress(firstRow, lastRow, firstColumn, lastColumn); _sheet.AddMergedRegion(range); return this; } } public class Row : IRow { private NRow _row; public int RowNumber => _row.RowNum; internal Row(NRow row) { _row = row; } public string ExtractString(int column, bool uppercase = false) { try { var result = ""; var cell = _row.GetCell(column, MissingCellPolicy.CREATE_NULL_AS_BLANK); if (cell.CellType == CellType.Numeric) result = cell.NumericCellValue.ToString(); else result = cell.StringCellValue; if (string.IsNullOrWhiteSpace(result)) result = ""; return uppercase ? result.ToUpper() : result; } catch (Exception e) { throw new Exception(string.Format("Row {0}:[{1}:{2}]: {3}", _row.Sheet.SheetName, _row.RowNum + 1, column, e.Message)); } } public DateTime ExtractDateTime(int column) { try { var cell = _row.GetCell(column, MissingCellPolicy.CREATE_NULL_AS_BLANK); try { return cell.DateCellValue; } catch { var sDate = cell.StringCellValue; DateTime.TryParse(sDate, out var result); return result; } } catch (Exception e) { throw new Exception(string.Format("Row {0}:[{1}:{2}]: {3}", _row.Sheet.SheetName, _row.RowNum + 1, column, e.Message)); } } public double? ExtractDouble(int column) { try { double result = 0.0F; var cell = _row.GetCell(column, MissingCellPolicy.CREATE_NULL_AS_BLANK); if (cell.CellType == CellType.Numeric || cell.CellType == CellType.Formula) result = cell.NumericCellValue; else if (cell.CellType == CellType.String) result = double.Parse(cell.StringCellValue); return result; } catch (FormatException) { return null; } catch (Exception e) { throw new Exception(string.Format("Row {0}:[{1}:{2}]: {3}", _row.Sheet.SheetName, _row.RowNum + 1, column, e.Message)); } } public int GetColumn(string name, bool throwException = true) { var cells = _row.GetEnumerator(); while (cells.MoveNext()) { var cell = cells.Current; if (!string.IsNullOrWhiteSpace(cell.StringCellValue) && cell.StringCellValue.ToUpper().Trim().Equals(name.ToUpper().Trim())) { return cell.ColumnIndex; } } if (!throwException) { return -1; } throw new Exception("Unable to find Column: " + name); } public ICell GetCell(int column) => new Cell(_row.GetCell(column)); public ICell NewCell(int column) { var cell = _row.CreateCell(column); return new Cell(cell); } } public class Cell : ICell { private NCell _cell; internal Cell(NCell cell) { _cell = cell; } public string GetValue() { if (_cell.CellType == CellType.Formula) { if (_cell.CachedFormulaResultType == CellType.Numeric) return string.Format("{0:F}", _cell.NumericCellValue.ToString()); return _cell.StringCellValue; } return _cell.ToString(); } public bool? GetBoolValue() { try { if (_cell.CellType == CellType.Boolean) return _cell.BooleanCellValue; return null; } catch (Exception) { return null; } } public double? GetDoubleValue() { try { double result = 0.0F; if (_cell.CellType == CellType.Numeric || _cell.CellType == CellType.Formula) result = _cell.NumericCellValue; else if (_cell.CellType == CellType.String) result = double.Parse(_cell.StringCellValue); return result; } catch (Exception) { return null; } } public DateTime GetDateTimeValue() { try { return _cell.DateCellValue; } catch { var sDate = _cell.StringCellValue; if(!DateTime.TryParse(sDate, out var result)){ return DateTime.MinValue; } return result; } } public byte? GetByteValue() { try { byte result = 0; if (_cell.CellType == CellType.Numeric || _cell.CellType == CellType.Formula) result = (byte)_cell.NumericCellValue; else if (_cell.CellType == CellType.String) result = byte.Parse(_cell.StringCellValue); return result; } catch (Exception) { return null; } } public ICell SetValue(bool value) { _cell.SetCellValue(value); return this; } public ICell SetValue(double value) { _cell.SetCellValue(value); return this; } public ICell SetValue(string value) { _cell.SetCellValue(value); return this; } public ICell SetValue(byte value) { _cell.SetCellValue(value); return this; } public ICell SetValue(DateTime value) { _cell.SetCellValue(value); return this; } public ICell SetBlank() { _cell.SetBlank(); return this; } public ICell SetStyle(ICellStyle style) { _cell.CellStyle = (style as CellStyle)._style; return this; } } public class SheetEnumerator : IEnumerator { public Sheet Current => new(_enumerator.Current); private IEnumerator _enumerator { get; } object IEnumerator.Current => new Sheet(_enumerator.Current); internal SheetEnumerator(IEnumerator enumerator) { _enumerator = enumerator; } public void Dispose() { _enumerator.Dispose(); } public bool MoveNext() { return _enumerator.MoveNext(); } public void Reset() { _enumerator.Reset(); } } public class DataFormat : IDataFormat { public short FormatIndex { get; } public DataFormat(short format) { FormatIndex = format; } } public class CellStyle : ICellStyle { internal NCellStyle _style { get; } public IDataFormat DataFormat { get => new DataFormat(_style.DataFormat); set => _style.DataFormat = value.FormatIndex; } public CellStyle(NCellStyle style) { _style = style; } } public class Spreadsheet : ISpreadsheet { public IWorkbook Workbook; private NCellStyle DateStyle; private NDataFormat DataFormat; private Spreadsheet(IWorkbook workbook) { Workbook = workbook; DataFormat = Workbook.CreateDataFormat(); } public Spreadsheet(string fileName) : this(WorkbookFactory.Create(fileName)) { } public Spreadsheet(FileStream file) : this(WorkbookFactory.Create(file)) { } public Spreadsheet() : this(new XSSFWorkbook()) { } public ISheet GetSheet(int index) { return new Sheet(Workbook.GetSheetAt(index)); } public ISheet GetSheet(string name) { return new Sheet(Workbook.GetSheet(name)); } public IEnumerator SheetEnumerator() { var enumerator = Workbook.GetEnumerator(); return new SheetEnumerator(enumerator); } public IEnumerable Sheets() { for (var i = 0; i < Workbook.NumberOfSheets; i++) yield return GetSheet(i); } public void Write(FileStream file) { Workbook.Write(file); } public void Write(string filename, FileMode mode = FileMode.Create) { using(var stream = new FileStream(filename, FileMode.Create)) { Workbook.Write(stream); } } public ISheet NewSheet(string name) { var sheet = Workbook.CreateSheet(name); return new Sheet(sheet); } public ISheet NewSheet() { var sheet = Workbook.CreateSheet(); return new Sheet(sheet); } public ICellStyle NewStyle() { var style = Workbook.CreateCellStyle(); var x = style.GetDataFormatString(); return new CellStyle(style); } public IDataFormat GetDataFormat(string format) { var dataFormat = DataFormat.GetFormat(format); return new DataFormat(dataFormat); } } }