// // Class: ExcelReader // Current CLR: 4.0.30319.34209 // System: Microsoft Visual Studio 10.0 // Author: dani // Created: 6/15/2015 10:03:40 PM // // Copyright (c) 2015 Informatikbüro Daniel Schick. All rights reserved. using log4net; using Microsoft.Office.Interop.Excel; using System; using System.Collections.Generic; using System.Data; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using ENI2.Locode; using bsmd.database; using System.Text.RegularExpressions; namespace ENI2.Excel { internal class ExcelReader : ExcelBase { internal enum ReadState { NONE, OK, WARN, FAIL }; internal enum SheetTypeEnum { BSMD, DAKOSY }; private readonly SheetTypeEnum _sheetType = SheetTypeEnum.BSMD; internal Dictionary ImportValues { get; } = new Dictionary(); public ExcelReader(string filePath, bool openReadonly = true, bool createNameFields = true) { this._workBook = _excelWorkbooks.Open(filePath, 0, openReadonly, 5, "", "", false, XlPlatform.xlWindows, "", false, false, 0, false, false, false); if(createNameFields) this.InitNameFields(); // Determine if this is a Dakosy or BSMD Sheet if(createNameFields) _sheetType = (_nameDict.Count > 10) ? SheetTypeEnum.BSMD : SheetTypeEnum.DAKOSY; } public SheetTypeEnum SheetType { get { return _sheetType; } } internal static void SaveMessage(Message message) { message.CreatedBy = "EXCEL"; if (message.MessageNotificationClass == Message.NotificationClass.STO) message.InternalStatus = Message.BSMDStatus.PREPARE; else message.InternalStatus = Message.BSMDStatus.EXCEL; message.UnsentMessageWarningShown = false; DBManager.Instance.Save(message); message.SaveElements(); } internal string ReadText(string lookup) { string result = null; if (_nameDict.ContainsKey(lookup)) { try { var val = _nameDict[lookup].RefersToRange.Value; var val2 = _nameDict[lookup].RefersToRange.Value2; if (val != null) result = val.ToString().Trim(); else if (val2 != null) result = val2.ToString().Trim(); } catch (COMException ex) { _log.WarnFormat("COMException reading field {0}: {1}", lookup, ex.ErrorCode); } } if (result != null) { result = result.Trim(); if(result.Length > 0) { result = result.Clean(); } this.ImportValues[lookup] = result; } return result; } internal string ReadTextNoWhitespace(string lookup) { string val = this.ReadText(lookup); if (val == null) return val; return new string(val.Where(c => !Char.IsWhiteSpace(c)).ToArray()); } internal string ReadLoCode(string lookup, bool justPorts = true) { string val = this.ReadText(lookup); if (!val.IsNullOrEmpty()) { val = val.ToUpper(); string portName = LocodeDB.PortNameFromLocode(val); if (!justPorts) portName = LocodeDB.NameFromLocode(val); if (portName.IsNullOrEmpty()) { _log.WarnFormat("unknown Locode {0}", val); val = ""; } } return val; } internal string ReadSSNLocode(string lookup) { string val = this.ReadText(lookup); if (!val.IsNullOrEmpty()) { val = val.ToUpper(); string portName = LocodeDB.SSNPortNameFromLocode(val); if (portName.IsNullOrEmpty()) { _log.WarnFormat("unknown Locode {0}", val); val = ""; } } return val; } internal int? ReadCargoLACode(string lookup) { string val = ReadText(lookup); if (val.IsNullOrEmpty()) return null; if(int.TryParse(val, out int result)) { if ((result < 10) || (result > 99)) _log.WarnFormat("invalid cargo LA code {0}", result); return result; } else { _log.ErrorFormat("Cargo LA code parse error for {0}", lookup); return null; } } internal byte? ReadGender(string lookup) { byte? result = null; string val = this.ReadText(lookup); if (val != null) { if (val.Equals("m", StringComparison.CurrentCultureIgnoreCase) || val.Equals("male", StringComparison.CurrentCultureIgnoreCase)) { result = 1; } else if (val.Equals("f", StringComparison.CurrentCultureIgnoreCase) || val.Equals("female", StringComparison.CurrentCultureIgnoreCase)) { result = 2; } else if (val.Equals("n", StringComparison.CurrentCultureIgnoreCase) || val.Equals("not applicable", StringComparison.CurrentCultureIgnoreCase) || val.Equals("d", StringComparison.CurrentCultureIgnoreCase) || val.Equals("diverse", StringComparison.CurrentCultureIgnoreCase)) { result = 9; } else { result = 0; } } if(result == null) { _log.ErrorFormat("error reading gender on {0}", lookup); } return result; } internal byte? ReadIdentityDocumentType(string lookup) { byte? result = null; string val = this.ReadText(lookup); if (val != null) { if (val.Equals("identity_card", StringComparison.CurrentCultureIgnoreCase) || val.Equals("identity card", StringComparison.CurrentCultureIgnoreCase) || val.Equals("1")) result = 0; if (val.Equals("passport", StringComparison.CurrentCultureIgnoreCase) || val.Equals("2")) result = 1; if (val.Equals("muster_book", StringComparison.CurrentCultureIgnoreCase) || val.Equals("muster book", StringComparison.CurrentCultureIgnoreCase) || val.Equals("3")) result = 2; if (val.Equals("picture_id", StringComparison.CurrentCultureIgnoreCase) || val.Equals("picture id", StringComparison.CurrentCultureIgnoreCase) || val.Equals("4")) result = 3; if (val.Equals("residental_permit", StringComparison.CurrentCultureIgnoreCase) || val.Equals("residental permit", StringComparison.CurrentCultureIgnoreCase) || val.Equals("5")) result = 4; if (val.Equals("other_legal_identity_document", StringComparison.CurrentCultureIgnoreCase) || val.Equals("other legal identity document", StringComparison.CurrentCultureIgnoreCase) || val.Equals("6")) result = 5; if (val.Equals("ic", StringComparison.CurrentCultureIgnoreCase)) result = 0; } if (!result.HasValue) _log.ErrorFormat("cannot read identity document type {0}", lookup); return result; } internal byte? ReadShippingArea(string lookup) { string val = this.ReadText(lookup); byte? result = null; if (val != null) { if ((val.IndexOf("baltic", StringComparison.OrdinalIgnoreCase) >= 0) || (val.Equals("1"))) result = 0; if ((val.IndexOf("europe", StringComparison.OrdinalIgnoreCase) >= 0) || (val.Equals("2"))) result = 1; if ((val.IndexOf("overseas", StringComparison.OrdinalIgnoreCase) >= 0) || (val.Equals("3"))) result = 2; } if (!result.HasValue) _log.ErrorFormat("cannot read shipping area {0}", lookup); return result; } internal byte? ReadGeneralDescriptionOfCargo(string lookup) { string val = this.ReadText(lookup); byte? result = null; if (val != null) { if (val.Contains("container", StringComparison.OrdinalIgnoreCase) || val.Equals("1")) result = 0; if (val.Contains("vehicles", StringComparison.OrdinalIgnoreCase) || val.Equals("2")) result = 1; if (val.Contains("convent", StringComparison.OrdinalIgnoreCase) || val.Equals("3")) result = 2; if (val.Contains("dry", StringComparison.OrdinalIgnoreCase) || val.Equals("4")) result = 3; if (val.Contains("liquid", StringComparison.OrdinalIgnoreCase) || val.Equals("5")) result = 4; if (val.Contains("empty", StringComparison.OrdinalIgnoreCase) || val.Equals("6")) result = 5; } if (!result.HasValue) _log.ErrorFormat("cannot read general description of cargo {0}", lookup); return result; } internal byte? ReadCargoHandlingType(string lookup) { string val = this.ReadText(lookup); byte? result = null; if(val != null) { if ((val.IndexOf("load", StringComparison.OrdinalIgnoreCase) >= 0) || val.Equals("1")) result = 0; if ((val.IndexOf("discharge", StringComparison.OrdinalIgnoreCase) >= 0) || val.Equals("2")) result = 1; if ((val.IndexOf("transit", StringComparison.OrdinalIgnoreCase) >= 0) || val.Equals("3")) result = 2; } if (!result.HasValue) _log.ErrorFormat("cannot read cargo handling type {0}", lookup); return result; } /// /// read nationality field, validation only via log (so none, really..) /// /// uppercase 2 character flag code if valid, empty string otherwise internal string ReadNationality(string lookup) { string val = this.ReadText(lookup)?.Trim().ToUpper(); if (val != null) { if (val.Length > 2) { // maybe it was entered as name and we can get nationality locode from there.. string isoCode = LocodeDB.CountryCodeFromName(val); if (isoCode == null) { _log.ErrorFormat("Wrong ISO code {0}", val); val = ""; } } } return val; } internal byte? ReadHullConfiguration(string lookup) { string val = this.ReadText(lookup); byte? result = null; if (val != null) { if (val.IndexOf("sbt", StringComparison.OrdinalIgnoreCase) >= 0) result = 1; if (val.IndexOf("single", StringComparison.OrdinalIgnoreCase) >= 0) result = 0; if (val.IndexOf("double", StringComparison.OrdinalIgnoreCase) >= 0) result = 2; } if (!result.HasValue) _log.ErrorFormat("cannot read hull configuration {0}", lookup); return result; } internal byte? ReadPackingGroup(string lookup) { string val = this.ReadText(lookup); byte? result = null; if(val!= null) { if (val == "I") result = 0; if (val == "1") result = 0; if (val == "II") result = 1; if (val == "2") result = 1; if (val == "III") result = 2; if (val == "3") result = 2; if (val.Equals("NONE", StringComparison.OrdinalIgnoreCase)) result = 0; } if (!result.HasValue) _log.ErrorFormat("cannot read packing group {0}", lookup); return result; } internal string ReadShip2ShipActivityType(string lookup) { string val = this.ReadText(lookup); bool isValid = false; if(!val.IsNullOrEmpty()) { if (int.TryParse(val, out int typeVal)) { if ((typeVal >= 1) && (typeVal <= 23)) isValid = true; } } if (!isValid) _log.WarnFormat("cannot read ship2ship activity type {0}", lookup); return val; } internal byte? ReadConditionTanks(string lookup) { string val = this.ReadText(lookup); byte? result = null; if (val != null) { if (val.IndexOf("full", StringComparison.OrdinalIgnoreCase) >= 0) result = 0; if (val.IndexOf("empty", StringComparison.OrdinalIgnoreCase) >= 0) result = 1; if (val.IndexOf("inerted", StringComparison.OrdinalIgnoreCase) >= 0) result = 2; } if (!result.HasValue) _log.ErrorFormat("cannot read condition tanks {0}", lookup); return result; } internal byte? ReadDelivery(string lookup) { string val = this.ReadText(lookup); byte? result = null; if (val != null) { if ((val.IndexOf("all", StringComparison.OrdinalIgnoreCase) >= 0) || val.Equals("1")) result = 0; if ((val.IndexOf("some", StringComparison.OrdinalIgnoreCase) >= 0) || val.Equals("2")) result = 1; if ((val.IndexOf("none", StringComparison.OrdinalIgnoreCase) >= 0) || val.Equals("3")) result = 2; } if (!result.HasValue) _log.ErrorFormat("cannot read delivery {0}", lookup); return result; } internal byte? ReadHazards(string lookup) { string val = this.ReadText(lookup); byte? result = null; if(val != null) { if (val.Equals("p", StringComparison.OrdinalIgnoreCase)) return 0; if (val.Equals("s", StringComparison.OrdinalIgnoreCase)) return 1; if (val.Equals("s/p", StringComparison.OrdinalIgnoreCase)) return 2; } return result; } internal byte? ReadHazardClass(string lookup) { string val = this.ReadText(lookup); byte? result = null; if(val != null) { if (val.Equals("a", StringComparison.OrdinalIgnoreCase)) return 0; if (val.Equals("b", StringComparison.OrdinalIgnoreCase)) return 1; if (val.Equals("a and b", StringComparison.OrdinalIgnoreCase)) return 2; // TODO make this more flexible } return result; } internal DateTime? ReadBirthDate(string lookup) { DateTime? result = this.ReadDate(lookup); if(result.HasValue) { if (result.Value > DateTime.Now) _log.WarnFormat("Birth date implausible for {0} : {1}", lookup, result); } return result; } internal DateTime? ReadDate(string lookup) { try { DateTime? date = null; if (_nameDict.ContainsKey(lookup)) { var val = _nameDict[lookup].RefersToRange.Value; if (val is DateTime) { date = val; } else if (val is double) { try { date = DateTime.FromOADate(val); } catch (ArgumentException) { /* .. */ } if(date == null) { CultureInfo provider = CultureInfo.InvariantCulture; string dateString = val.ToString(); const string format = "yyyyMMdd"; if (DateTime.TryParseExact(dateString, format, provider, DateTimeStyles.None, out DateTime tmpDate)) date = tmpDate; } } if (date == null) { if (DateTime.TryParse(val, out DateTime tmpDate)) date = tmpDate; } if (date != null) { if ((date.Value < new DateTime(1899, 1, 1)) || (date.Value > new DateTime(2130, 1, 1))) { date = null; // this can't be right } } } return date; } catch (Exception) { _log.WarnFormat("error parsing datetime for lookup {0}", lookup); return null; } } internal DateTime? ReadDateTime(string dateField, string timeField) { DateTime? result = null; DateTime? etaDate = this.ReadDate(dateField); DateTime? etaTime = this.ReadTime(timeField); if (etaDate != null) { if (etaTime != null) { result = new DateTime(etaDate.Value.Year, etaDate.Value.Month, etaDate.Value.Day, etaTime.Value.Hour, etaTime.Value.Minute, etaTime.Value.Second, DateTimeKind.Local); result = result.Value.ToUniversalTime(); } else { result = new DateTime(etaDate.Value.Year, etaDate.Value.Month, etaDate.Value.Day, 0, 0, 0, DateTimeKind.Local); result = result.Value.ToUniversalTime(); } } return result; } internal DateTime? ReadTime(string lookup) { DateTime? result = null; try { if (_nameDict.ContainsKey(lookup)) { var val = _nameDict[lookup].RefersToRange.Value; if (val is DateTime) { result = val; } if (val is double) { try { result = DateTime.FromOADate(val); } catch(ArgumentException) { } if (result == null) { CultureInfo provider = CultureInfo.InvariantCulture; string dateString = val.ToString(); if (!dateString.Contains(":")) { const string format = "HHmm"; if (DateTime.TryParseExact(dateString, format, provider, DateTimeStyles.None, out DateTime tmpDate)) result = tmpDate; } } } if (val is string) { if (((string)val).EndsWith("lt", StringComparison.OrdinalIgnoreCase)) val = ((string)val).Substring(0, ((string)val).Length - 2).Trim(); else val = ((string)val).Trim(); } if (result == null) { if (DateTime.TryParseExact(val, "HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault, out DateTime date)) result = date; } if (result == null) { if (DateTime.TryParseExact(val, "HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault, out DateTime date)) result = date; } if ((result == null) && (val != null)) { CultureInfo provider = CultureInfo.InvariantCulture; string dateString = val.ToString(); if (!dateString.Contains(":")) { const string format = "HHmm"; if (DateTime.TryParseExact(dateString, format, provider, DateTimeStyles.None, out DateTime tmpDate)) result = tmpDate; } } } } catch (Exception) { _log.WarnFormat("error reading time for lookup {0}", lookup); } return result; } internal double ReadNumberDefaultZero(string lookup) { double? result = this.ReadNumber(lookup); if(!result.HasValue) { result = 0; } return result.Value; } internal bool? ReadBoolean(string lookup) { string val = this.ReadText(lookup); if (val == null) return null; if ((val == "y") || (val == "Y") || val.Equals("yes", StringComparison.OrdinalIgnoreCase) || (val == "1") || (val == "x") || (val == "X")) return true; return false; } #region Dakosy-specific functions internal string ReadCellAsText(string sheetName, string range) { try { Worksheet workSheet = (Worksheet) _workBook.Worksheets[sheetName]; string result = workSheet.Range[range].Text.ToString(); if (!result.IsNullOrEmpty()) result = result.Trim().Clean(); return result; } catch(Exception e) { _log.Warn(e.Message); } return null; } internal string ReadCellAsText(string sheetName, int row, int col) { try { Worksheet workSheet = (Worksheet)_workBook.Worksheets[sheetName]; string result = workSheet.Range[row, col].Text.ToString(); if (!result.IsNullOrEmpty()) result = result.Trim().Clean(); return result; } catch (Exception e) { _log.Warn(e.Message); } return null; } // TODO THIS IS NOT WORKING internal string ReadTextFromDropdown(string sheetName, string range) { try { Worksheet workSheet = (Worksheet)_workBook.Worksheets[sheetName]; Range aRange = workSheet.Range[range]; if (aRange != null) { } } catch (Exception e) { _log.Warn(e.Message); } return null; } internal bool? ReadCellAsBool(string sheetName, string range) { string boolString = ReadCellAsText(sheetName, range); if (!boolString.IsNullOrEmpty()) { if (boolString.Equals("TRUE", StringComparison.OrdinalIgnoreCase)) return true; if (boolString.Equals("FALSE", StringComparison.OrdinalIgnoreCase)) return false; if (boolString.Equals("YES", StringComparison.OrdinalIgnoreCase) || boolString.Equals("Y", StringComparison.OrdinalIgnoreCase)) return true; if (boolString.Equals("NO", StringComparison.OrdinalIgnoreCase) || boolString.Equals("N", StringComparison.OrdinalIgnoreCase)) return false; return null; } else return null; } internal double? ReadCellAsDecimal(string sheetName, string range) { try { double? result = null; Worksheet workSheet = (Worksheet)_workBook.Worksheets[sheetName]; var val = workSheet.Range[range].Value; if (val is double) result = val; if (val is string) { if (double.TryParse(val, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, CultureInfo.InvariantCulture, out double tmpDouble)) result = tmpDouble; if (result == null) { if (double.TryParse(val, out tmpDouble)) // current language style (==GER, mit , statt .) result = tmpDouble; } } if ((result == null) && (val != null)) { double tmpDouble2 = val[1, 1]; result = tmpDouble2; } return result; } catch (Exception e) { _log.Warn(e.Message); } return null; } internal DateTime? ReadCellAsDateTime(string sheetName, string range) { string dateString = ReadCellAsText(sheetName, range); if (dateString != null) { CultureInfo provider = CultureInfo.InvariantCulture; const string dateTimeFormat = "yyyy/MM/dd HH:mm"; if (DateTime.TryParseExact(dateString, dateTimeFormat, provider, DateTimeStyles.None, out DateTime tmpDate)) return tmpDate.ToUniversalTime(); const string dateFormat = "yyyy/MM/dd"; if (DateTime.TryParseExact(dateString, dateFormat, provider, DateTimeStyles.None, out DateTime tmpDate2)) return tmpDate2; const string dateFormat2 = "dd.MM.yyyy"; if (DateTime.TryParseExact(dateString, dateFormat2, provider, DateTimeStyles.None, out DateTime tmpDate3)) return tmpDate3; return null; } else return null; } #endregion } }