// // Class: Util // Current CLR: 4.0.30319.34209 // System: Microsoft Visual Studio 10.0 // Author: dani // Created: 6/17/2015 7:12:38 AM // // Copyright (c) 2015 Informatikbüro Daniel Schick. All rights reserved. using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using log4net; using bsmd.database; namespace bsmd.ExcelReadService { public class Util { private static ILog _log = LogManager.GetLogger(typeof(Util)); public static bool ProcessSheet(ExcelReader reader, out string readMessage, out MessageCore messageCore) { readMessage = "ok"; messageCore = Util.LookupMessageCore(reader, out readMessage); if (messageCore == null) return false; // cannot work with this sheet or create one // load messages if already present List messages = DBManager.Instance.GetMessagesForCore(messageCore); // start parsing fields if (messageCore.IsTransit) { // scan for transit messages // AGNT // NOA_NOD // SEC // POBA // POBD ScanTIEFA(messages, messageCore, reader); ScanBKRA(messages, messageCore, reader); ScanSTAT(messages, messageCore, reader); // MDH // CREW // PAS // BPOL // TOWA // HAZA // HAZD } else { // scan for visit messages // AGNT // NOA_NOD ScanATA(messages, messageCore, reader); ScanATD(messages, messageCore, reader); // SEC // POBA // POBD ScanNAME(messages, messageCore, reader); ScanTIEFA(messages, messageCore, reader); ScanTIEFD(messages, messageCore, reader); ScanBKRA(messages, messageCore, reader); ScanBKRD(messages, messageCore, reader); ScanSTAT(messages, messageCore, reader); // LADG // INFO // SERV // PRE72H // MDH // WAS // CREW // PAS // BPOL // TOWA // TOWD // HAZA // HAZD } //string sheetVersion = reader.GetCell("Portcall", 2, 1) as string; //messageCore.SietasSheetVersion = sheetVersion; // save all messages now foreach(Message message in messages) { DBManager.Instance.Save(message); // TODO: Die abhängigen Listen müssen auch gespeichert werden } DBManager.Instance.Save(messageCore); return true; } #region ATA static void ScanATA(List messages, MessageCore messageCore, ExcelReader reader) { Message ataMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.ATA); if (ataMessage.Elements.Count == 0) { ATA newATA = new ATA(); newATA.MessageHeader = ataMessage; ataMessage.Elements.Add(newATA); } ATA ata = ataMessage.Elements[0] as ATA; Util.ScanMessage(ata, reader); if (!ata.ATAPortOfCall.HasValue && ataMessage.IsNew) messages.Remove(ataMessage); } #endregion #region ATD static void ScanATD(List messages, MessageCore messageCore, ExcelReader reader) { Message atdMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.ATD); if (atdMessage.Elements.Count == 0) { ATD newATD = new ATD(); newATD.MessageHeader = atdMessage; atdMessage.Elements.Add(newATD); } ATD atd = atdMessage.Elements[0] as ATD; Util.ScanMessage(atd, reader); if (!atd.ATDPortOfCall.HasValue && atdMessage.IsNew) messages.Remove(atdMessage); } #endregion #region TIEFA static void ScanTIEFA(List messages, MessageCore messageCore, ExcelReader reader) { Message tiefaMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.TIEFA); if (tiefaMessage.Elements.Count == 0) { TIEFA newTIEFA = new TIEFA(); newTIEFA.MessageHeader = tiefaMessage; tiefaMessage.Elements.Add(newTIEFA); } TIEFA tiefa = tiefaMessage.Elements[0] as TIEFA; Util.ScanMessage(tiefa, reader); if (!tiefa.DraughtUponArrival_DMT.HasValue && tiefaMessage.IsNew) messages.Remove(tiefaMessage); } #endregion #region TIEFD static void ScanTIEFD(List messages, MessageCore messageCore, ExcelReader reader) { Message tiefdMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.TIEFD); if(tiefdMessage.Elements.Count == 0) { TIEFD newTIEFD = new TIEFD(); newTIEFD.MessageHeader = tiefdMessage; tiefdMessage.Elements.Add(newTIEFD); } TIEFD tiefd = tiefdMessage.Elements[0] as TIEFD; Util.ScanMessage(tiefd, reader); if (!tiefd.DraughtUponDeparture_DMT.HasValue && tiefdMessage.IsNew) messages.Remove(tiefdMessage); } #endregion #region NAME static void ScanNAME(List messages, MessageCore messageCore, ExcelReader reader) { Message nameMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.NAME); if (nameMessage.Elements.Count == 0) { NAME newNAME = new NAME(); newNAME.MessageHeader = nameMessage; nameMessage.Elements.Add(newNAME); } NAME name = nameMessage.Elements[0] as NAME; Util.ScanMessage(name, reader); if (name.NameOfMaster.IsNullOrEmpty() && name.IsNew) messages.Remove(nameMessage); } #endregion #region STAT static void ScanSTAT(List messages, MessageCore messageCore, ExcelReader reader) { Message statMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.STAT); if(statMessage.Elements.Count == 0) { STAT newSTAT = new STAT(); newSTAT.MessageHeader = statMessage; statMessage.Elements.Add(newSTAT); } STAT stat = statMessage.Elements[0] as STAT; Util.ScanMessage(stat, reader); if (!stat.Flag.IsNullOrEmpty() && stat.Flag.Length > 2) stat.Flag = LocodeDB.CountryCodeFromName(stat.Flag); if (!stat.Flag.IsNullOrEmpty() && stat.Flag.Length == 2) { if (!stat.PortOfRegistry.IsNullOrEmpty() && stat.PortOfRegistry.Length != 5) stat.PortOfRegistry = LocodeDB.LocodeFromCity(stat.PortOfRegistry, stat.Flag); } // wird nicht wieder entfernt (core ist auch da!) } #endregion #region BKRA static void ScanBKRA(List messages, MessageCore messageCore, ExcelReader reader) { Message bkraMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.BKRA); for (int i = 0; i < bkraMessage.NumberOfExcelRows; i++) { string lnQuantity = string.Format("BKRA.BunkerFuelQuantity_TNE_{0}", i + 1); string lnType = string.Format("BKRA.BunkerFuelType_{0}", i + 1); BRKA bkra = bkraMessage.GetSublistElementWithIdentifier((i + 1).ToString()) as BRKA; if (bkra == null) { bkra = new BRKA(); bkra.Identifier = (i + 1).ToString(); bkra.MessageHeader = bkraMessage; bkraMessage.Elements.Add(bkra); } bkra.BunkerFuelQuantity_TNE = reader.ReadNumber(lnQuantity); bkra.BunkerFuelType = reader.ReadText(lnType); // dont save empty element if(bkra.IsNew && !bkra.BunkerFuelQuantity_TNE.HasValue && bkra.BunkerFuelType.IsNullOrEmpty()) bkraMessage.Elements.Remove(bkra); } } #endregion #region BKRD static void ScanBKRD(List messages, MessageCore messageCore, ExcelReader reader) { Message bkrdMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.BKRD); for (int i = 0; i < bkrdMessage.NumberOfExcelRows; i++) { string lnQuantity = string.Format("BKRD.BunkerFuelQuantity_TNE_{0}", i + 1); string lnType = string.Format("BKRD.BunkerFuelType_{0}", i + 1); BRKD bkrd = bkrdMessage.GetSublistElementWithIdentifier((i + 1).ToString()) as BRKD; if (bkrd == null) { bkrd = new BRKD(); bkrd.Identifier = (i + 1).ToString(); bkrd.MessageHeader = bkrdMessage; bkrdMessage.Elements.Add(bkrd); } bkrd.BunkerFuelQuantity_TNE = reader.ReadNumber(lnQuantity); bkrd.BunkerFuelType = reader.ReadText(lnType); // dont save empty element if(bkrd.IsNew && !bkrd.BunkerFuelQuantity_TNE.HasValue && bkrd.BunkerFuelType.IsNullOrEmpty()) bkrdMessage.Elements.Remove(bkrd); } } #endregion #region LADG static void ScanLADG(List messages, MessageCore messageCore, ExcelReader reader) { Message ladgMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.LADG); for (int i = 0; i < ladgMessage.NumberOfExcelRows; i++) { string lnCHT = string.Format("LADG.CargoHandlingType_{0}", i + 1); string lnType = string.Format("LADG.CargoType_{0}", i + 1); string lnCNOI = string.Format("LADG.CargoNumberOfItems_{0}", i + 1); string lnCGQ = string.Format("LADG.CargoGrossQuantity_TNE_{0}", i + 1); LADG ladg = ladgMessage.GetSublistElementWithIdentifier((i + 1).ToString()) as LADG; if (ladg == null) { ladg = new LADG(); ladg.Identifier = (i + 1).ToString(); ladg.MessageHeader = ladgMessage; ladgMessage.Elements.Add(ladg); } string handlingTypeString = reader.ReadText(lnCHT); if (!handlingTypeString.IsNullOrEmpty()) { // irgendwas mit "*load*" drin wird load, alles andere discharge ladg.CargoHandlingType = handlingTypeString.Contains("load", StringComparison.InvariantCultureIgnoreCase) ? (byte) 0 : (byte) 1; } ladg.CargoCodeNST = reader.ReadText(lnType); if (ladg.CargoCodeNST.Length != 2) ladg.CargoCodeNST = null; // stupid validation ladg.CargoNumberOfItems = (int?) reader.ReadNumber(lnCNOI); ladg.CargoGrossQuantity_TNE = reader.ReadNumber(lnCGQ); // dont save empty element if (ladg.IsNew && !ladg.CargoHandlingType.HasValue) ladgMessage.Elements.Remove(ladg); } } #endregion private static void ScanMessage(DatabaseEntity dbEntity, ExcelReader reader) { Type objType = dbEntity.GetType(); List props = new List(); // add lookup properties to scan list props.AddRange(objType.GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(LookupNameAttribute)))); foreach (PropertyInfo property in props) { object propValue = property.GetValue(dbEntity, null); string value = (propValue == null) ? string.Empty : propValue.ToString(); LookupNameAttribute lookupNameAttribute = Attribute.GetCustomAttribute(property, typeof(LookupNameAttribute)) as LookupNameAttribute; if (property.PropertyType == typeof(DateTime?)) { DateTime? sheetValue = reader.ReadDate(lookupNameAttribute.LookupName); if (sheetValue != null) property.SetValue(dbEntity, sheetValue); } else if (property.PropertyType == typeof(double?)) { double? sheetValue = reader.ReadNumber(lookupNameAttribute.LookupName); if (sheetValue != null) property.SetValue(dbEntity, sheetValue); } else if (property.PropertyType == typeof(string)) { string sheetValue = reader.ReadText(lookupNameAttribute.LookupName); if (sheetValue != null) property.SetValue(dbEntity, sheetValue); } else { } } } /// /// Check with cell values if this message core is already in our DB /// private static MessageCore LookupMessageCore(ExcelReader reader, out string message) { // lookup using field values MessageCore result = null; DateTime? eta = null; string poc = null; string imo = null; message = string.Empty; bool isTransit = false; // first check with visit/transit ID string visitTransitId = reader.ReadText("ID"); if (visitTransitId != null) { if (bsmd.database.Util.IsVisitId(visitTransitId)) { result = DBManager.Instance.GetMessageCoreByVisitId(visitTransitId); } else if (bsmd.database.Util.IsTransitId(visitTransitId)) { result = DBManager.Instance.GetMessageCoreByTransitId(visitTransitId); } } else { // lookup poc, imo, eta poc = reader.ReadText("Visit.PortOfCall"); // Prüfen auf Transit if (poc.ToUpper().Contains("CANAL")) { poc = "ZZNOK"; isTransit = true; } else { // Im Sheet könnte der Name statt des LOCODES stehen! if (!RuleEngine.IsGermanLocode(poc)) { // somehow lookup LOCODE from the port's name! poc = LocodeDB.LocodeGERFromCity(poc); } } imo = reader.ReadText("Visit.IMONumber"); // ETA DateTime? etaDate = reader.ReadDate("NOA_NOD.ETADateToPortOfCall"); DateTime? etaTime = reader.ReadTime("NOA_NOD.ETATimeToPortOfCall"); if (etaDate != null) { eta = new DateTime(etaDate.Value.Year, etaDate.Value.Month, etaDate.Value.Day); if (etaTime != null) { eta = new DateTime(etaDate.Value.Year, etaDate.Value.Month, etaDate.Value.Day, etaTime.Value.Hour, etaTime.Value.Minute, etaTime.Value.Second); } } result = DBManager.Instance.GetMessageCoreByShipInfos(imo, eta.Value, poc); if (result.IsNew) result.IsTransit = isTransit; } if (result == null) { if (imo == null) { message = "IMO number missing or not found"; return null; } if(poc == null) { message = string.Format("Port of call missing or not found for IMO {0}", imo); return null; } if(eta == null) { message = string.Format("ETA missing or not found for IMO {0}", imo); return null; } result = new MessageCore(); result.IMO = imo; result.ReportStatus = MessageCore.ReportStatusEnum.COMPLETE; result.Portname = poc; result.ETA = eta; if (result.IMO.Length > 7) { _log.WarnFormat("IMO {0} is longer than 7 chars, truncating!", result.IMO); result.IMO = result.IMO.Substring(0, 7); } DBManager.Instance.Save(result); } return result; } private static DateTime ConstructDate(string etaDateString, string etaTime) { DateTime result = DateTime.Now; if (DateTime.TryParse(etaDateString, out result)) { TimeSpan sp; if (TimeSpan.TryParse(etaTime, out sp)) result += sp; } return result; } private static Message GetMessageWithType(List messages, MessageCore core, Message.NotificationClass type) { foreach(Message message in messages) if (message.MessageNotificationClass == type) return message; Message newMessage = new Message(); newMessage.MessageNotificationClass = type; messages.Add(newMessage); newMessage.MessageCore = core; return newMessage; } } }