git_bsmd/nsw/Source/bsmd.ExcelReadService/Util.cs

667 lines
24 KiB
C#

//
// 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<Message> messages = DBManager.Instance.GetMessagesForCore(messageCore);
// start parsing fields
if (messageCore.IsTransit)
{
// scan for transit messages
ScanAGNT(messages, messageCore, reader);
// NOA_NOD
// SEC
ScanPOBA(messages, messageCore, reader);
ScanPOBD(messages, messageCore, reader);
ScanTIEFA(messages, messageCore, reader);
ScanBKRA(messages, messageCore, reader);
ScanSTAT(messages, messageCore, reader);
// MDH
// CREW
// PAS
// BPOL
// TOWA
// HAZA
// HAZD
}
else
{
// scan for visit messages
ScanAGNT(messages, messageCore, reader);
// NOA_NOD
ScanATA(messages, messageCore, reader);
ScanATD(messages, messageCore, reader);
// SEC
ScanPOBA(messages, messageCore, reader);
ScanPOBD(messages, messageCore, reader);
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;
DBManager.Instance.Save(messageCore);
// save all messages now
foreach(Message message in messages)
{
DBManager.Instance.Save(message);
message.SaveElements();
}
return true;
}
#region ATA
static void ScanATA(List<Message> 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<Message> 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<Message> 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<Message> 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<Message> 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 POBA
static void ScanPOBA(List<Message> messages, MessageCore messageCore, ExcelReader reader)
{
Message pobaMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.POBA);
if(pobaMessage.Elements.Count == 0)
{
POBA newPoba = new POBA();
newPoba.MessageHeader = pobaMessage;
pobaMessage.Elements.Add(newPoba);
}
POBA poba = pobaMessage.Elements[0] as POBA;
Util.ScanMessage(poba, reader);
if (((poba.TotalPersonsOnBoardUponArrival ?? 0) == 0) && poba.IsNew)
messages.Remove(pobaMessage);
}
#endregion
#region POBD
static void ScanPOBD(List<Message> messages, MessageCore messageCore, ExcelReader reader)
{
Message pobdMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.POBD);
if(pobdMessage.Elements.Count == 0)
{
POBD newPobd = new POBD();
newPobd.MessageHeader = pobdMessage;
pobdMessage.Elements.Add(newPobd);
}
POBD pobd = pobdMessage.Elements[0] as POBD;
Util.ScanMessage(pobd, reader);
if (((pobd.TotalPersonsOnBoardUponDeparture ?? 0) == 0) && pobd.IsNew)
messages.Remove(pobdMessage);
}
#endregion
#region STAT
static void ScanSTAT(List<Message> 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 AGNT
static void ScanAGNT(List<Message> messages, MessageCore messageCore, ExcelReader reader)
{
Message agntMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.AGNT);
if(agntMessage.Elements.Count == 0)
{
AGNT newAgnt = new AGNT();
newAgnt.MessageHeader = agntMessage;
agntMessage.Elements.Add(newAgnt);
}
AGNT agnt = agntMessage.Elements[0] as AGNT;
Util.ScanMessage(agnt, reader);
// wird nicht mehr entfernt, egal welche Felder gelesen werden
}
#endregion
#region MDH
static void ScanMDH(List<Message> messages, MessageCore messageCore, ExcelReader reader)
{
Message mdhMessage = Util.GetMessageWithType(messages, messageCore, Message.NotificationClass.MDH);
if(mdhMessage.Elements.Count == 0)
{
MDH newMDH = new MDH();
newMDH.MessageHeader = mdhMessage;
mdhMessage.Elements.Add(newMDH);
}
MDH mdh = mdhMessage.Elements[0] as MDH;
Util.ScanMessage(mdh, reader);
// POC last 30 days
for (int i = 0; i < 15; i++)
{
string portName = string.Format("MDH.PortOfCallLast30DaysPort_{0}", i + 1);
string portCountry = string.Format("MDH.PortOfCallLast30DaysCountry_{0}", i + 1);
string locode = string.Format("MDH.PortOfCallLast30DaysLocode_{0}", i + 1);
string crewJoined = string.Format("MDH.PortOfCallLast30DaysCrewMembersJoined_{0}", i + 1);
string crewName = string.Format("MDH.PortOfCallLast30DaysCrewJoinedShipName_{0}", i + 1);
string depDate = string.Format("MDH.PortOfCallLast30DaysDateOfDeparture_{0}", i + 1);
PortOfCallLast30Days poc30d = mdh.GetSublistElementWithIdentifier((i + 1).ToString()) as PortOfCallLast30Days;
if (poc30d == null)
{
poc30d = new PortOfCallLast30Days();
poc30d.Identifier = (i + 1).ToString();
poc30d.MessageHeader = mdhMessage;
mdh.PortOfCallLast30Days.Add(poc30d);
}
// TODO! geht nicht weil sich der Index ändert und das Namensattribut konstant ist
// Util.ScanMessage(poc30d, reader);
// Leer/def. Zeilen entfernen
if (!poc30d.PortOfCallLast30DaysDateOfDeparture.HasValue && (poc30d.PortOfCallLast30DaysLocode == null))
mdh.PortOfCallLast30Days.Remove(poc30d);
string crewJoinedText = reader.ReadText(crewName);
if (!crewJoinedText.IsNullOrEmpty())
{
PortOfCallLast30DaysCrewJoinedShip poc30C = mdh.GetSublistElementWithIdentifier("1") as PortOfCallLast30DaysCrewJoinedShip;
if (poc30C == null)
{
poc30C = new PortOfCallLast30DaysCrewJoinedShip();
poc30C.PortOfCallLast30Days = poc30d;
poc30d.CrewJoinedShip.Add(poc30C);
}
poc30C.PortOfCallLast30DaysCrewJoinedShipName = crewJoinedText;
}
}
// wird nicht wieder entfernt falls keine Daten vorliegen
}
#endregion
#region BKRA
static void ScanBKRA(List<Message> 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<Message> 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<Message> 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<PropertyInfo> props = new List<PropertyInfo>();
// 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 {
}
}
}
/// <summary>
/// Check with cell values if this message core is already in our DB
/// </summary>
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<Message> 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;
}
}
}