git_bsmd/nsw/Source/bsmd.database/Message.cs

653 lines
24 KiB
C#

using System;
using System.Data;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
namespace bsmd.database
{
/// <summary>
/// Basisklasse aller Nachrichtentypen, zentrale Klasse für die NSW App
/// </summary>
public class Message : DatabaseEntity, ISublistContainer, IComparable<Message>
{
#region Fields
private Guid? messageCoreId;
private Guid? reportingPartyId;
private ReportingParty reportingParty;
private DateTime? created;
private List<MessageError> errorList = new List<MessageError>();
private List<MessageViolation> violationList = new List<MessageViolation>();
private List<DatabaseEntity> elements = new List<DatabaseEntity>();
#endregion
#region ANSWSortList
public static IList<NotificationClass> ANSWSortList = new ReadOnlyCollection<NotificationClass>(
new List<NotificationClass>{
NotificationClass.TIEFA,
NotificationClass.POBA,
NotificationClass.BKRA,
NotificationClass.TOWA,
NotificationClass.NOA_NOD,
NotificationClass.STAT,
NotificationClass.NAME,
NotificationClass.INFO,
NotificationClass.SERV,
NotificationClass.LADG,
NotificationClass.TIEFD,
NotificationClass.POBD,
NotificationClass.BKRD,
NotificationClass.TOWD,
NotificationClass.SEC,
NotificationClass.PRE72H,
NotificationClass.BPOL,
NotificationClass.CREW,
NotificationClass.PAS,
NotificationClass.MDH,
NotificationClass.HAZA,
NotificationClass.HAZD,
NotificationClass.WAS,
NotificationClass.ATA,
NotificationClass.ATD,
NotificationClass.AGNT,
NotificationClass.STO
});
#endregion
#region Enumerations
/// <summary>
/// NSW notification class
/// </summary>
public enum NotificationClass
{
VISIT, // 0
TRANSIT, // 1
NOA_NOD, // 2
ATA,
ATD,
SEC, // 5
POBA,
POBD,
NAME,
TIEFA,
TIEFD, // 10
BKRA,
BKRD,
STAT,
LADG,
INFO, // 15
SERV,
PRE72H,
MDH,
WAS,
CREW, // 20
PAS,
BPOL,
TOWA,
TOWD,
HAZA, // 25
HAZD,
AGNT,
STO // DK - only
}
public enum MessageStatus
{ ACCEPTED, REJECTED }
/// <summary>
/// Anhand dieses Filters und den Parametern können die Klassen das passende LoadQuery generieren
/// </summary>
public enum LoadFilter
{
ALL,
MESSAGETYPE,
REPORTINGPARTY,
MESSAGEHEADER,
BSMDSTATUS,
WETRIS_SHIP_ID,
MDH_ID,
POC30_ID,
WAS_ID,
WDSP_ID,
BPOL_ID,
SEC_ID,
HERBERG_FORMGUID,
BY_ID,
BY_CORE,
NOA_NODID,
HAZ_ID,
IMDG_ID,
REPORTSTATUS,
IMO_ETA_POC,
BY_VISITID,
BY_TRANSITID,
BY_CORE_ENI,
BY_CORE_EXCEL,
BY_CORE_HE
}
/// <summary>
/// Message Status einer NSW Einzelnachricht
/// </summary>
public enum BSMDStatus
{
UNDEFINED = 0,
PREPARE,
TOSEND,
SENT,
SEND_FAILED,
CONFIRMED,
VIOLATION,
ERROR,
SUSPENDED = 8
}
/// <summary>
/// Spezifiziert das gewünschte HIS zur Übertragung der Daten
/// </summary>
public enum NSWProvider
{
UNDEFINED,
DBH,
DAKOSY,
DUDR,
DBH_TEST,
DAKOSY_TEST,
DUDR_TEST
}
#endregion
#region Construction
public Message()
{
this.tablename = "[dbo].[MessageHeader]";
}
#endregion
#region Properties
/// <summary>
/// Dieser Wert wird vom NSW / HIS vergeben
/// </summary>
public string ClientRequestId { set; get; }
public Guid? MessageId { get; set; }
public Guid? MessageCoreId { get { return this.messageCoreId; } set { this.messageCoreId = value; } }
public DateTime? SentAt { get; set; }
public DateTime? ReceivedAt { get; set; }
public DateTime? RequestedAt { get; set; }
public bool Reset { get; set; }
public bool Cancel { get; set; }
public MessageStatus? Status { get; set; }
[ShowReport]
public DateTime? Created { get { return this.created; } }
/// <summary>
/// Vorwärts-Referenzen auf die von diesem Header-Element abhängigen speziellen Nachrichten-Datensätzen
/// Folgende Objekte können pro Nachricht n-fach vorkommen
/// BRKA, BRKD, LADG, CREW, PAS, SERV, TOWA, TOWD, STO
/// sonst hat die Liste immer ein Element
/// </summary>
public List<DatabaseEntity> Elements { get { return this.elements; } }
/// <summary>
/// Der Meldende
/// </summary>
public ReportingParty ReportingParty
{
get { return this.reportingParty; }
set
{
if (value == null)
{
this.reportingPartyId = null;
}
else
{
this.reportingPartyId = value.Id;
}
this.reportingParty = value;
}
}
/// <summary>
/// Status für Services
/// </summary>
public BSMDStatus InternalStatus { get; set; }
/// <summary>
/// die zur Kommunikation zu verwendende HIS Schnittstelle
/// </summary>
public NSWProvider HIS { get; set; }
/// <summary>
/// Fehlerliste (Rückgabe vom NSW)
/// </summary>
public List<MessageError> ErrorList { get { return this.errorList; } }
/// <summary>
/// Violation-Liste (Rückgabe vom NSW)
/// </summary>
public List<MessageViolation> ViolationList { get { return this.violationList; } }
/// <summary>
/// Property to overwrite reporting party in certain circumstances (other melder meldet)
/// </summary>
public Guid? ReportingPartyId { get { return this.reportingPartyId; } set { this.reportingPartyId = value; } }
/// <summary>
/// Urheber der Nachricht (Excel oder HE)
/// </summary>
public string CreatedBy { get; set; }
/// <summary>
/// Bearbeiter für Änderungshistorie (=Name des angemeldeten Melders), wird vom ENI-2 Speicherprozess befüllt
/// </summary>
public string ChangedBy { get; set; }
#endregion
#region IDatabaseEntity implementation
public override void PrepareSave(IDbCommand cmdParam)
{
SqlCommand cmd = cmdParam as SqlCommand;
if (this.ClientRequestId != null)
cmd.Parameters.AddWithValue("@CLIENTREQUESTID", Guid.Parse(this.ClientRequestId));
else
cmd.Parameters.AddWithValue("@CLIENTREQUESTID", DBNull.Value);
cmd.Parameters.AddWithValue("@MESSAGECOREID", this.MessageCore.Id);
if (this.MessageId.HasValue)
cmd.Parameters.AddWithValue("@MESSAGEID", this.MessageId.Value);
else
cmd.Parameters.AddWithValue("@MESSAGEID", DBNull.Value);
if (this.SentAt.HasValue)
cmd.Parameters.AddWithValue("@SENTAT", this.SentAt.Value);
else
cmd.Parameters.AddWithValue("@SENTAT", DBNull.Value);
if (this.ReceivedAt.HasValue)
cmd.Parameters.AddWithValue("@RECEIVEDAT", this.ReceivedAt.Value);
else
cmd.Parameters.AddWithValue("@RECEIVEDAT", DBNull.Value);
if (this.RequestedAt.HasValue)
cmd.Parameters.AddWithValue("@REQUESTEDAT", this.RequestedAt.Value);
else
cmd.Parameters.AddWithValue("@REQUESTEDAT", DBNull.Value);
cmd.Parameters.AddWithValue("@NOTIFICATIONCLASS", (int)this.MessageNotificationClass);
cmd.Parameters.AddWithValue("@RESET", this.Reset);
cmd.Parameters.AddWithValue("@CANCEL", this.Cancel);
if (this.Status.HasValue)
cmd.Parameters.AddWithValue("@STATUS", (int)this.Status.Value);
else
cmd.Parameters.AddWithValue("@STATUS", DBNull.Value);
cmd.Parameters.AddWithNullableValue("@REPORTINGPARTYID", this.reportingPartyId);
cmd.Parameters.AddWithValue("@BSMDSTATUS", this.InternalStatus);
cmd.Parameters.AddWithValue("@HIS", this.HIS);
cmd.Parameters.AddWithNullableValue("@CREATEDBY", this.CreatedBy);
cmd.Parameters.AddWithNullableValue("@CHANGEDBY", this.ChangedBy);
if (this.IsNew)
{
this.CreateId();
cmd.Parameters.AddWithValue("@ID", this.Id);
string query = string.Format("INSERT INTO {0} (Id, ClientRequestId, MessageCoreId, MessageId, SentAt, ReceivedAt, RequestedAt, NotificationClass, Reset, Cancel, Status, ReportingPartyId, BSMDStatus, HIS, CreatedBy, ChangedBy) " +
"VALUES (@ID, @CLIENTREQUESTID, @MESSAGECOREID, @MESSAGEID, @SENTAT, @RECEIVEDAT, @REQUESTEDAT, @NOTIFICATIONCLASS, @RESET, @CANCEL, @STATUS, @REPORTINGPARTYID, @BSMDSTATUS, @HIS, @CREATEDBY, @CHANGEDBY)",
this.Tablename);
cmd.CommandText = query;
}
else
{
cmd.Parameters.AddWithValue("@ID", this.Id);
cmd.CommandText = string.Format("UPDATE {0} SET ClientRequestId = @CLIENTREQUESTID, MessageId = @MESSAGEID, SentAt = @SENTAT, ReceivedAt = @RECEIVEDAT, RequestedAt = @REQUESTEDAT, " +
"NotificationClass = @NOTIFICATIONCLASS, Reset = @RESET, Cancel = @CANCEL, Status = @STATUS, ReportingPartyId = @REPORTINGPARTYID, BSMDStatus = @BSMDSTATUS, HIS = @HIS, " +
"CreatedBy = @CREATEDBY, ChangedBy = @CHANGEDBY WHERE Id = @ID", this.Tablename);
}
}
public override void PrepareLoadCommand(IDbCommand cmd, LoadFilter filter, params object[] criteria )
{
string query = string.Format("SELECT Id, ClientRequestId, MessageCoreId, MessageId, SentAt, ReceivedAt, RequestedAt, NotificationClass, " +
"Reset, Cancel, Status, ReportingPartyId, BSMDStatus, HIS, Created, CreatedBy, ChangedBy FROM {0} ", this.Tablename);
switch (filter)
{
case LoadFilter.REPORTINGPARTY:
{
query += "WHERE ReportingPartyId = @RPID";
((SqlCommand)cmd).Parameters.AddWithValue("RPID", criteria[0]);
break;
}
case LoadFilter.BSMDSTATUS:
{
query += "WHERE BSMDStatus = @BSMDSTATUS";
((SqlCommand)cmd).Parameters.AddWithValue("@BSMDSTATUS", criteria[0]);
break;
}
case LoadFilter.BY_ID:
{
query += "WHERE Id = @ID";
((SqlCommand)cmd).Parameters.AddWithValue("@ID", criteria[0]);
break;
}
case LoadFilter.BY_CORE:
{
query += "WHERE MessageCoreId = @COREID";
((SqlCommand)cmd).Parameters.AddWithValue("@COREID", criteria[0]);
break;
}
case LoadFilter.BY_CORE_ENI:
{
query += "WHERE MessageCoreId = @COREID AND ChangedBy IS NOT NULL";
((SqlCommand)cmd).Parameters.AddWithValue("@COREID", criteria[0]);
break;
}
case LoadFilter.BY_CORE_EXCEL:
{
query += "WHERE MessageCoreId = @COREID AND CreatedBy = 'EXCEL'";
((SqlCommand)cmd).Parameters.AddWithValue("@COREID", criteria[0]);
break;
}
case LoadFilter.BY_CORE_HE:
{
query += "WHERE MessageCoreId = @COREID AND (CreatedBy = 'HE' OR CreatedBy IS NULL)"; // TODO: letzte Bedingung nach Übergangsphase entfernen
((SqlCommand)cmd).Parameters.AddWithValue("@COREID", criteria[0]);
break;
}
case LoadFilter.ALL:
default:
break;
}
cmd.CommandText = query;
}
public override List<DatabaseEntity> LoadList(IDataReader reader)
{
List<DatabaseEntity> result = new List<DatabaseEntity>();
while (reader.Read())
{
Message msg = new Message();
msg.id = reader.GetGuid(0);
if (!reader.IsDBNull(1)) msg.ClientRequestId = reader.GetGuid(1).ToString();
msg.messageCoreId = reader.GetGuid(2);
if(!reader.IsDBNull(3)) msg.MessageId = reader.GetGuid(3);
if (!reader.IsDBNull(4)) msg.SentAt = reader.GetDateTime(4);
if (!reader.IsDBNull(5)) msg.ReceivedAt = reader.GetDateTime(5);
if (!reader.IsDBNull(6)) msg.RequestedAt = reader.GetDateTime(6);
if (!reader.IsDBNull(7)) msg.MessageNotificationClass = (NotificationClass) Enum.ToObject(typeof(NotificationClass), reader.GetByte(7));
if (!reader.IsDBNull(8)) msg.Reset = reader.GetBoolean(8);
if (!reader.IsDBNull(9)) msg.Cancel = reader.GetBoolean(9);
if (!reader.IsDBNull(10)) msg.Status = (MessageStatus)Enum.ToObject(typeof(MessageStatus), reader.GetByte(10));
if (!reader.IsDBNull(11)) msg.reportingPartyId = reader.GetGuid(11);
if (!reader.IsDBNull(12)) msg.InternalStatus = (BSMDStatus)Enum.ToObject(typeof(BSMDStatus), reader.GetByte(12));
if (!reader.IsDBNull(13)) msg.HIS = (NSWProvider)Enum.ToObject(typeof(NSWProvider), reader.GetByte(13));
if (!reader.IsDBNull(14)) msg.created = reader.GetDateTime(14);
if (!reader.IsDBNull(15)) msg.CreatedBy = reader.GetString(15);
if (!reader.IsDBNull(16)) msg.ChangedBy = reader.GetString(16);
result.Add(msg);
}
reader.Close();
return result;
}
#endregion
#region public static helpers
public static void AssignReportingParties(List<Message> messages, Dictionary<Guid, ReportingParty> reportingParties)
{
foreach (Message message in messages)
{
if (message.reportingPartyId.HasValue && reportingParties.ContainsKey(message.reportingPartyId.Value))
message.reportingParty = reportingParties[message.reportingPartyId.Value];
}
}
public static void AssignMessageCores(List<Message> messages, Dictionary<Guid, MessageCore> messageCores)
{
foreach (Message message in messages)
{
if (message.messageCoreId.HasValue && messageCores.ContainsKey(message.messageCoreId.Value))
message.MessageCore = messageCores[message.messageCoreId.Value];
}
}
#endregion
#region ISublistContainer implementation
public ISublistElement GetSublistElementWithIdentifier(string identifier)
{
foreach (DatabaseEntity entity in this.Elements)
{
ISublistElement sublistElement = entity as ISublistElement;
if ((sublistElement != null ) && (sublistElement.Identifier != null))
{
if (((ISublistElement)entity).Identifier.Equals(identifier))
return entity as ISublistElement;
}
}
return null;
}
public int NumberOfExcelRows
{
get
{
switch (this.MessageNotificationClass)
{
case NotificationClass.BKRA: return 5;
case NotificationClass.BKRD: return 5;
case NotificationClass.LADG: return 36;
case NotificationClass.CREW: return 40;
case NotificationClass.PAS: return 30;
case NotificationClass.TOWA: return 1;
case NotificationClass.TOWD: return 1;
case NotificationClass.STO: return 10;
default:
return 0;
}
}
}
public void SaveElements()
{
foreach (DatabaseEntity dbEntity in this.Elements)
{
DBManager.Instance.Save(dbEntity);
if (dbEntity is ISublistContainer)
{
((ISublistContainer)dbEntity).SaveElements();
}
}
}
public void DeleteElements()
{
foreach (DatabaseEntity dbEntity in this.Elements)
{
if (dbEntity is ISublistContainer)
{
((ISublistContainer)dbEntity).DeleteElements();
}
DBManager.Instance.Delete(dbEntity);
}
}
#endregion
#region IMessageParagraph implementation
public override string Title
{
get
{
if (this.Elements.Count > 0)
{
return this.Elements[0].Title;
}
else
{
if (this.MessageNotificationClass == NotificationClass.VISIT) return "VISIT";
if (this.MessageNotificationClass == NotificationClass.TRANSIT) return "TRANSIT";
return "unknown";
}
}
}
public override string Subtitle
{
get
{
if (this.Elements.Count > 0)
return this.Elements[0].Subtitle;
else
return string.Empty;
}
}
public override List<KeyValuePair<string, string>> MessageText
{
get
{
switch (this.MessageNotificationClass)
{
case NotificationClass.VISIT:
case NotificationClass.TRANSIT:
return base.MessageText;
case NotificationClass.ATA:
case NotificationClass.ATD:
case NotificationClass.BPOL:
case NotificationClass.HAZA:
case NotificationClass.HAZD:
case NotificationClass.INFO:
case NotificationClass.MDH:
case NotificationClass.NAME:
case NotificationClass.NOA_NOD:
case NotificationClass.POBA:
case NotificationClass.POBD:
case NotificationClass.PRE72H:
case NotificationClass.SEC:
case NotificationClass.STAT:
case NotificationClass.AGNT:
case NotificationClass.TIEFA:
case NotificationClass.TIEFD:
case NotificationClass.WAS:
if (this.Elements.Count > 0)
{
return this.Elements[0].MessageText;
}
else
{
return null;
}
default:
return null;
}
}
}
public override bool ShowChildrenAsTable
{
get
{
switch (this.MessageNotificationClass)
{
case NotificationClass.CREW:
case NotificationClass.PAS:
return true;
default:
return false;
}
}
}
public override List<IMessageParagraph> ChildParagraphs
{
get
{
switch (this.MessageNotificationClass)
{
case NotificationClass.VISIT:
case NotificationClass.TRANSIT:
return null;
case NotificationClass.ATA:
case NotificationClass.ATD:
case NotificationClass.BPOL:
case NotificationClass.HAZA:
case NotificationClass.HAZD:
case NotificationClass.INFO:
case NotificationClass.MDH:
case NotificationClass.NAME:
case NotificationClass.NOA_NOD:
case NotificationClass.POBA:
case NotificationClass.POBD:
case NotificationClass.PRE72H:
case NotificationClass.SEC:
case NotificationClass.STAT:
case NotificationClass.AGNT:
case NotificationClass.TIEFA:
case NotificationClass.TIEFD:
case NotificationClass.WAS:
if (this.Elements.Count > 0)
{
return this.Elements[0].ChildParagraphs;
}
else
{
return null;
}
default:
List<IMessageParagraph> result = new List<IMessageParagraph>();
foreach (DatabaseEntity element in this.Elements)
result.Add(element);
return result;
}
}
}
#endregion
#region IComparable implementation
/// <summary>
/// Sort messages by notification class
/// </summary>
public int CompareTo(Message other)
{
return this.MessageNotificationClass.CompareTo(other.MessageNotificationClass);
}
#endregion
}
}