using Serilog;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using TINK.Model.Bike;
using TINK.Repository.Exception;
using TINK.Repository.Response;
using TINK.Model.Services.CopriApi.ServerUris;
using TINK.Model.State;
namespace TINK.Model.Connector
{
///
/// Conversion helper functionality.
///
public static class TextToTypeHelper
{
/// Holds the text for demo bikes.
private const string DEMOBIKEMARKER = "DEMO";
/// Part text denoting two wheel cargo bike..
private const string TWOWHEELCARGOMARKERFRAGMENT = "LONG";
///
/// Gets the position from StationInfo object.
///
/// Object to get information from.
/// Position information.
public static IPosition GetPosition(this StationsAvailableResponse.StationInfo stationInfo)
=> GetPosition(stationInfo.gps);
/// Gets the position from StationInfo object.
/// Object to get information from.
/// Position information.
public static IEnumerable GetGroup(this AuthorizationResponse authorizationResponse)
{
try
{
return authorizationResponse.user_group.GetGroup();
}
catch (Exception l_oException)
{
throw new Exception($"Can not get group of user from text \"{authorizationResponse.user_group}\".", l_oException);
}
}
/// Gets the position from StationInfo object.
/// Object to get information from.
/// Position information.
public static IEnumerable GetGroup(this string[] group)
{
if (group == null || group.Length == 0)
{
// If not logged in stations groups are empty form COPRI version v4.1.
Log.Debug("Can not get goup form string. Group text can not be null.");
return new List();
}
return new HashSet(group).ToList();
}
/// Gets if user acknowldged ags or not.
/// Object to get information from.
/// Position information.
public static bool GetIsAgbAcknowledged(this AuthorizationResponse authorizationResponse)
=> int.TryParse(authorizationResponse?.agb_checked, out int result)
&& result != 0;
/// Gets the position from StationInfo object.
/// Object to get information from.
/// Position information.
public static string GetGroup(this IEnumerable group)
{
return string.Join(",", group);
}
/// Gets the position from StationInfo object.
/// Object to get information from.
/// Position information.
public static IEnumerable GetGroup(this StationsAvailableResponse.StationInfo stationInfo)
{
try
{
return stationInfo.station_group.GetGroup();
}
catch (Exception l_oException)
{
throw new Exception($"Can not get group of stations from text \"{stationInfo.station_group}\".", l_oException);
}
}
///
/// Gets the position from StationInfo object.
///
/// Object to get information from.
/// Position information.
public static InUseStateEnum GetState(this BikeInfoBase bikeInfo)
{
var l_oState = bikeInfo.state;
if (string.IsNullOrEmpty(l_oState))
{
throw new InvalidResponseException(
string.Format("Unknown reservation state detected. Member {0}.{1}.", typeof(BikeInfoBase), nameof(BikeInfoBase.state)),
bikeInfo);
}
if (l_oState == "available")
{
return InUseStateEnum.Disposable;
}
else if (l_oState == "reserved" ||
l_oState == "requested")
{
return InUseStateEnum.Reserved;
}
else if (l_oState == "booked" ||
l_oState == "occupied")
{
return InUseStateEnum.Booked;
}
throw new CommunicationException(string.Format("Unknown bike state detected. State is {0}.", l_oState));
}
///
/// Gets the from date information from JSON.
///
/// JSON to get information from..
/// From information.
public static DateTime GetFrom(this BikeInfoReservedOrBooked bikeInfo)
{
return DateTime.Parse(bikeInfo.start_time);
}
///
/// Gets whether the bike is a trike or not.
///
/// JSON to get information from..
/// From information.
public static bool? GetIsDemo(this BikeInfoBase bikeInfo)
{
return bikeInfo?.description != null
? bikeInfo.description.ToUpper().Contains(DEMOBIKEMARKER)
: (bool?) null;
}
///
/// Gets whether the bike is a trike or not.
///
/// JSON to get information from.
/// From information.
public static IEnumerable GetGroup(this BikeInfoBase bikeInfo)
{
try
{
return bikeInfo?.bike_group?.GetGroup()?.ToList() ?? new List();
}
catch (Exception l_oException)
{
throw new Exception($"Can not get group of user from text \"{bikeInfo.bike_group}\".", l_oException);
}
}
/// Gets whether the bike has a bord computer or not.
/// JSON to get information from.
/// From information.
public static bool GetIsManualLockBike(this BikeInfoBase bikeInfo)
{
return !string.IsNullOrEmpty(bikeInfo.system)
&& bikeInfo.system.ToUpper().StartsWith("LOCK");
}
/// Gets whether the bike has a bord computer or not.
/// JSON to get information from..
/// From information.
public static bool GetIsBluetoothLockBike(this BikeInfoBase bikeInfo)
{
return !string.IsNullOrEmpty(bikeInfo.system)
&& bikeInfo.system.ToUpper().StartsWith("ILOCKIT");
}
/// Gets whether the bike has a bord computer or not.
/// JSON to get information from..
/// From information.
public static int GetBluetoothLockId(this BikeInfoAvailable bikeInfo)
{
return TextToLockItTypeHelper.GetBluetoothLockId(bikeInfo?.Ilockit_ID);
}
/// Gets whether the bike has a bord computer or not.
/// JSON to get information from..
/// From information.
public static Guid GetBluetoothLockGuid(this BikeInfoAvailable bikeInfo)
{
// return new Guid("00000000-0000-0000-0000-e57e6b9aee16");
return Guid.TryParse(bikeInfo?.Ilockit_GUID, out Guid lockGuid)
? lockGuid
: TextToLockItTypeHelper.INVALIDLOCKGUID;
}
public static byte[] GetUserKey(this BikeInfoReservedOrBooked bikeInfo)
{
return GetKey(bikeInfo.K_u);
}
public static byte[] GetAdminKey(this BikeInfoReservedOrBooked bikeInfo)
{
return GetKey(bikeInfo.K_a);
}
public static byte[] GetSeed(this BikeInfoReservedOrBooked bikeInfo)
{
return GetKey(bikeInfo.K_seed);
}
///
/// Get array of keys from string of format "[12, -9, 5]"
///
///
///
private static byte[] GetKey(string keyArrayText)
{
try
{
if (string.IsNullOrEmpty(keyArrayText))
return new byte[0];
return Regex.Replace(keyArrayText, @"\[(.*)\]", "$1").Split(',').Select(x => (byte)sbyte.Parse(x)).ToArray();
}
catch (Exception exception)
{
Log.Error("Can not extract K_u/ K_a/ or K_seed. Key {ArrayText} does not is not of expected format. {Exception}", keyArrayText, exception);
return new byte[0];
}
}
///
/// Gets whether the bike is a trike or not.
///
/// JSON to get information from..
/// From information.
public static WheelType? GetWheelType(this BikeInfoBase bikeInfo)
{
var l_oDescription = bikeInfo.description;
if (l_oDescription == null)
{
// Can not get type of wheel if description text is empty.
return null;
}
foreach (WheelType l_oWheelType in Enum.GetValues(typeof(WheelType)))
{
if (l_oDescription.ToUpper().Contains(l_oWheelType.ToString().ToUpper()))
{
return l_oWheelType;
}
}
// Check for custom value "Long".
if (l_oDescription.ToUpper().Contains(TWOWHEELCARGOMARKERFRAGMENT))
{
return WheelType.Two;
}
// Check for Stadrad.
if (GetTypeOfBike(bikeInfo) == TypeOfBike.Citybike)
{
return WheelType.Two;
}
return null;
}
///
/// Gets the type of bike.
///
/// Object to get bike type from.
/// Type of bike.
public static TypeOfBike? GetTypeOfBike(this BikeInfoBase bikeInfo)
{
var l_oDescription = bikeInfo?.description;
if (l_oDescription == null)
{
// Can not get type of wheel if description text is empty.
return null;
}
foreach (TypeOfBike l_oTypeOfBike in Enum.GetValues(typeof(TypeOfBike)))
{
if (l_oDescription.ToUpper().Contains(l_oTypeOfBike.GetCopriText().ToUpper()))
{
return l_oTypeOfBike;
}
}
return null;
}
/// Get position from a ,- separated string.
/// Text to extract positon from.
/// Position object.
public static IPosition GetPosition(Repository.Response.Position gps)
=> PositionFactory.Create(
double.TryParse(gps?.latitude, NumberStyles.Float, CultureInfo.InvariantCulture, out double latitude) ? latitude : double.NaN,
double.TryParse(gps?.longitude, NumberStyles.Float, CultureInfo.InvariantCulture, out double longitude) ? longitude : double.NaN);
/// Get position from a ,- separated string.
/// Text to extract positon from.
/// Position object.
public static Map.IMapSpan GetMapSpan(this MapSpan mapSpan)
=> Map.MapSpanFactory.Create(
GetPosition(mapSpan?.center),
double.TryParse(mapSpan?.radius, NumberStyles.Float, CultureInfo.InvariantCulture, out double radius) ? radius: double.NaN);
/// Gets text of bike from.
/// Type to get text for.
///
public static string GetCopriText(this TypeOfBike p_eType)
{
switch (p_eType)
{
case TypeOfBike.Citybike:
return "Stadtrad";
default:
return p_eType.ToString();
}
}
public static Uri GetOperatorUri(this BikeInfoBase bikeInfo)
{
return bikeInfo?.uri_operator != null && !string.IsNullOrEmpty(bikeInfo?.uri_operator)
? new Uri($"{bikeInfo.uri_operator}/{CopriServerUriList.REST_RESOURCE_ROOT}")
: null;
}
/// Tries to get the copriversion from response.
/// Response to get version info from.
/// COPRI version
public static bool TryGetCopriVersion(this CopriVersion response, out Version copriVersion)
{
copriVersion = new Version(0, 0);
return response != null
&& !string.IsNullOrEmpty(response.copri_version)
&& Version.TryParse(response.copri_version, out copriVersion);
}
/// Gets the copriversion from.
/// Response to get version info from.
/// COPRI version
public static Version GetCopriVersion(this CopriVersion response)
=> response.TryGetCopriVersion(out Version copriVersion)
? copriVersion
: throw new InvalidResponseException($"Can not get version info from copri response {response?.copri_version}.");
}
}