git_bsmd/bsmd.database/Util.cs

341 lines
14 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Class: Util
// Current CLR: 4.0.30319.34209
// System: Microsoft Visual Studio 10.0
// Author: dani
// Created: 3/21/2015 10:36:56 AM
//
// Copyright (c) 2015 Informatikbüro Daniel Schick. All rights reserved.
using System;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using log4net;
using System.Globalization;
namespace bsmd.database
{
public static class Util
{
private static readonly Regex regexVisit = new Regex("^(DE)([A-Z]{3})-([0-9]{4})-([A-Z]{6})$", RegexOptions.IgnoreCase);
private static readonly Regex regexTransit = new Regex("^(ZZNOK)-([0-9]{4})-([A-Z]{6})$", RegexOptions.IgnoreCase);
private static readonly ILog _log = LogManager.GetLogger(typeof(Util));
/// <summary>
/// Extension helper to add values that can be null:
/// http://stackoverflow.com/questions/13451085/exception-when-addwithvalue-parameter-is-null
/// </summary>
public static SqlParameter AddWithNullableValue(this SqlParameterCollection collection, string parameterName, object value)
{
if (value == null)
return collection.AddWithValue(parameterName, DBNull.Value);
else
return collection.AddWithValue(parameterName, value);
}
public static string GetGenderDisplay(byte? val)
{
if (val.HasValue)
{
switch (val)
{
case 0: return "Male";
case 1: return "Female";
default: return "Other";
}
}
else
{
return "Unknown";
}
}
public static string GetIdentityDocumentTypeDisplay(byte? val)
{
if(val.HasValue)
{
switch (val)
{
case 0: return "Identity card";
case 1: return "Passport";
case 2: return "Muster book";
case 3: return "Picture ID";
case 4: return "Residental permit";
case 5: return "Other legal identity document";
default: return "unknown";
}
}
else
{
return "Unknown";
}
}
public static string GetISSCTypeDisplay(byte? val)
{
if (val.HasValue)
{
switch(val)
{
case 0: return "FULL";
case 1: return "INTERIM";
default:
return "UNKNOWN";
}
}
else
{
return "Unknown";
}
}
public static string GetISSCIssuerTypeDisplay(byte? val)
{
if (val.HasValue)
{
switch (val)
{
case 0: return "ADMINISTRATION";
case 1: return "RSO";
default:
return "UNKNOWN";
}
}
else
{
return "Unknown";
}
}
public static bool IsVisitId(string val)
{
if (val.IsNullOrEmpty()) return false;
return regexVisit.IsMatch(val);
}
public static bool IsTransitId(string val)
{
if (val.IsNullOrEmpty()) return false;
return regexTransit.IsMatch(val);
}
/// <summary>
/// Hilfsfunktion für "manuelle" Anlage eines Schiffsanlaufs. Die Objekte sind bereits gespeichert.
/// Es werden nur noch nicht vorhandene Meldeklassen erzeugt
/// </summary>
public static List<Message> CreateMessagesForCore(MessageCore core, List<Message> existingMessages, ReportingParty user = null)
{
List<Message> result = new List<Message>();
Dictionary<Message.NotificationClass, Message> messageDict = new Dictionary<Message.NotificationClass, Message>();
if(!existingMessages.IsNullOrEmpty())
{
foreach (Message aMessage in existingMessages)
{
if(messageDict.ContainsKey(aMessage.MessageNotificationClass))
{
_log.WarnFormat("Core {0} [{1}] has more than one message class for {2}", core.Id, core.DisplayId, aMessage.MessageNotificationClassDisplay);
}
messageDict[aMessage.MessageNotificationClass] = aMessage;
}
}
bool isDE, isDK;
if(core?.PoC != null)
{
isDE = core.PoC.Equals("ZZNOK") || core.PoC.StartsWith("DE");
isDK = core.PoC.StartsWith("DK");
foreach (Message.NotificationClass notificationClass in Enum.GetValues(typeof(Message.NotificationClass)))
{
if(isDE)
{
if ((notificationClass == Message.NotificationClass.CREWD) ||
(notificationClass == Message.NotificationClass.PASD) ||
(notificationClass == Message.NotificationClass.STO)) continue;
}
if(isDK)
{
// gibt es hier etwas, das nicht gebraucht wird? (siehe Mail von Christin, 29.5.17
if ((notificationClass == Message.NotificationClass.MDH) ||
(notificationClass == Message.NotificationClass.BKRA) ||
(notificationClass == Message.NotificationClass.BKRD) ||
(notificationClass == Message.NotificationClass.TOWA) ||
(notificationClass == Message.NotificationClass.TOWD)) continue;
}
if (core.IsTransit && (notificationClass == Message.NotificationClass.VISIT)) continue;
if (!core.IsTransit && (notificationClass == Message.NotificationClass.TRANSIT)) continue;
Message message;
if (!messageDict.ContainsKey(notificationClass))
{
message = new Message();
if (user != null)
message.CreatedBy = string.Format("ENI-2: {0}", user.Logon);
message.MessageCore = core;
message.MessageCoreId = core.Id;
message.MessageNotificationClass = notificationClass;
DBManager.Instance.Save(message);
result.Add(message);
}
else
{
message = messageDict[notificationClass];
}
// abgesehen von "Listen" für die Nachrichtenklassen auch untergeordnete Elemente erzeugen, falls nicht vorhanden!
DatabaseEntity classElement;
if (!Message.IsListClass(notificationClass) && (message.Elements.Count == 0))
{
classElement = DBManager.CreateMessage(notificationClass);
// CH: 6.10.17: Für die manuelle Eingabe (wird leider nicht ganz auszuschließen sein) wäre es hilfreich, wenn alle Checkboxen nicht leer sind, sondern False beinhalten.
if(notificationClass == Message.NotificationClass.MDH)
{
((MDH)classElement).SetBoolsToFalse();
}
if(notificationClass == Message.NotificationClass.BPOL)
{
// Vorbelegung, Spezialwunsch aus BRV 5.2.18
((BPOL)classElement).CruiseShip = false;
((BPOL)classElement).StowawaysOnBoard = false;
}
if (classElement != null) // null für Visit/Transit
{
classElement.MessageHeader = message;
DBManager.Instance.Save(classElement);
message.Elements.Add(classElement);
}
}
}
}
return result;
}
public static int? GetNumericIdentifier(ISublistElement element)
{
if (element != null)
{
string stringIdentifier = element.Identifier;
Regex re = new Regex(@"\d+");
Match m = re.Match(stringIdentifier);
if (m.Success)
{
return Int32.Parse(m.Value);
}
}
return null;
}
public static bool IsIMOValid(string imoAsString)
{
if (imoAsString.IsNullOrEmpty()) return false;
string actualIMO = null;
if(imoAsString.Length == 10)
{
if (imoAsString.Substring(0, 3).Equals("imo", StringComparison.OrdinalIgnoreCase))
actualIMO = imoAsString.Substring(3);
}
if (imoAsString.Length == 7)
actualIMO = imoAsString;
if ((actualIMO != null) && Int32.TryParse(actualIMO, out int _))
{
/* The integrity of an IMO number can be verified using its check digit. This is done by multiplying
* each of the first six digits by a factor of 2 to 7 corresponding to their position from right
* to left. The rightmost digit of this sum is the check digit.
* For example, for IMO 9074729: (9×7) + (0×6) + (7×5) + (4×4) + (7×3) + (2×2) = 139
*/
int sum = 0;
for (int i = 0, multiplier = 7; i < 6; i++, multiplier--)
{
sum += (Convert.ToInt32(actualIMO.Substring(i,1)) * multiplier);
}
int lastdigit = sum % 10; // letzte Stelle
if (Convert.ToInt32(actualIMO.Substring(6,1)) == lastdigit)
return true;
}
return false;
}
#region CoordinateTransformation
public static double NSWToDecimalDegrees(int nswCoordinate)
{
double result = Math.Floor(nswCoordinate / 600000.0);
result += (double) (nswCoordinate % 600000.0) / 600000.0;
return result;
}
public static int DecimalDegreesToNSW(double decimalDegree)
{
int result = ((int)decimalDegree) * 600000;
result += (int) ((decimalDegree - (int)decimalDegree) * 600000);
return result;
}
#endregion
#region Date calculations
// This presumes that weeks start with Monday.
// Week 1 is the 1st week of the year with a Thursday in it.
public static int GetIso8601WeekOfYear(DateTime time)
{
// Seriously cheat. If its Monday, Tuesday or Wednesday, then it'll
// be the same week# as whatever Thursday, Friday or Saturday are,
// and we always get those right
DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
{
time = time.AddDays(3);
}
// Return the week of our adjusted day
return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
public static DateTime StartOfWeek(this DateTime dt)
{
int diff = (7 + (dt.DayOfWeek - DayOfWeek.Monday)) % 7;
return dt.AddDays(-1 * diff).Date;
}
public static DateTime FirstDateOfWeekISO8601(int year, int weekOfYear)
{
DateTime jan1 = new DateTime(year, 1, 1);
int daysOffset = DayOfWeek.Thursday - jan1.DayOfWeek;
// Use first Thursday in January to get first week of the year as
// it will never be in Week 52/53
DateTime firstThursday = jan1.AddDays(daysOffset);
var cal = CultureInfo.CurrentCulture.Calendar;
int firstWeek = cal.GetWeekOfYear(firstThursday, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
var weekNum = weekOfYear;
// As we're adding days to a date in Week 1,
// we need to subtract 1 in order to get the right date for week #1
if (firstWeek == 1)
{
weekNum--;
}
// Using the first Thursday as starting week ensures that we are starting in the right year
// then we add number of weeks multiplied with days
var result = firstThursday.AddDays(weekNum * 7);
// Subtract 3 days from Thursday to get Monday, which is the first weekday in ISO8601
return result.AddDays(-3);
}
#endregion
}
}