546 lines
19 KiB
C#
546 lines
19 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
|
|
|
|
// 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<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 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 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;
|
|
}
|
|
|
|
}
|
|
}
|