2023-01-18 14:22:51 +01:00
using System ;
2022-08-30 15:42:25 +02:00
using System.Collections.Generic ;
using Serilog ;
2023-01-18 14:22:51 +01:00
using TINK.Model.Bikes.BikeInfoNS.BC ;
2022-08-30 15:42:25 +02:00
using TINK.Model.Bikes.BikeInfoNS.BikeNS ;
using TINK.Model.MiniSurvey ;
using TINK.Model.State ;
using TINK.Repository.Response ;
using BikeExtension = TINK . Model . Bikes . BikeInfoNS . BikeNS . BikeExtension ;
using BikeInfo = TINK . Model . Bikes . BikeInfoNS . BC . BikeInfo ;
namespace TINK.Model.Connector.Updater
{
2022-09-06 16:08:19 +02:00
/// <summary>
/// Constructs bike info instances/ bike info derived instances.
/// </summary>
public static class BikeInfoFactory
{
/// <summary> Set default lock type to . </summary>
public static LockModel DEFAULTLOCKMODEL = LockModel . Sigo ;
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
/// <summary> Creates a bike info object from copri response. </summary>
/// <param name="bikeInfo">Copri response for a disposable bike. </param>
2023-01-18 14:22:51 +01:00
/// <param name="dataSource">Specifies the data source.</param>
public static BikeInfo Create (
BikeInfoAvailable bikeInfo ,
DataSource dataSource )
2022-09-06 16:08:19 +02:00
{
if ( bikeInfo = = null ) throw new ArgumentNullException ( nameof ( bikeInfo ) ) ;
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
var lockModel = bikeInfo . GetLockModel ( ) ;
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
if ( lockModel . HasValue
& & lockModel . Value = = LockModel . BordComputer )
{
// Manual lock bikes are no more supported.
Log . Error (
$"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. " +
"Manual lock bikes are no more supported." +
$"Bike number: {bikeInfo.bike}{(bikeInfo.station != null ? $" station number { bikeInfo . station } " : string.Empty)}."
) ;
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
return null ;
}
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
switch ( bikeInfo . GetState ( ) )
{
case InUseStateEnum . Disposable :
case InUseStateEnum . FeedbackPending :
break ;
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
default :
Log . Error ( $"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Unexpected state {bikeInfo.GetState()} detected." ) ;
return null ;
}
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
if ( string . IsNullOrEmpty ( bikeInfo . station ) )
{
// Bike available must always have a station id because bikes can only be returned at a station.
Log . Error ( $"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. No station info set." ) ;
return null ;
}
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
var lockType = lockModel . HasValue
? BikeExtension . GetLockType ( lockModel . Value )
: BikeExtension . GetLockType ( DEFAULTLOCKMODEL ) ; // Map bikes without "system"- entry in response to backend- locks.
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
try
{
switch ( lockType )
{
case LockType . Backend :
return new Bikes . BikeInfoNS . CopriLock . BikeInfo (
new Bike (
bikeInfo . bike ,
LockModel . Sigo ,
bikeInfo . GetWheelType ( ) ,
bikeInfo . GetTypeOfBike ( ) ,
bikeInfo . description ) ,
DriveFactory . Create ( bikeInfo ? . bike_type ) ,
2023-01-18 14:22:51 +01:00
dataSource ,
2022-09-06 16:08:19 +02:00
bikeInfo . station ,
new Bikes . BikeInfoNS . CopriLock . LockInfo . Builder { State = bikeInfo . GetCopriLockingState ( ) } . Build ( ) ,
bikeInfo . GetState ( ) = = InUseStateEnum . FeedbackPending ,
bikeInfo . GetOperatorUri ( ) ,
2022-08-30 15:42:25 +02:00
#if ! NOTARIFFDESCRIPTION
2022-09-06 16:08:19 +02:00
bikeInfo . rental_description ! = null
? RentalDescriptionFactory . Create ( bikeInfo . rental_description )
: TariffDescriptionFactory . Create ( bikeInfo . tariff_description ) ,
2022-08-30 15:42:25 +02:00
#else
Create ( ( TINK . Repository . Response . TariffDescription ) null ) ,
#endif
2022-09-06 16:08:19 +02:00
bikeInfo . GetIsDemo ( ) ,
bikeInfo . GetGroup ( ) ,
miniSurvey : bikeInfo . user_miniquery ! = null
? new MiniSurveyModel ( new Dictionary < string , IQuestionModel > {
{ "q1" , new QuestionModel ( ) } // Add a dummy querry. Querries are not yet read from COPRI but compiled into the app.
2022-08-30 15:42:25 +02:00
} )
2022-09-06 16:08:19 +02:00
: new MiniSurveyModel ( ) ,
co2Saving : bikeInfo . co2saving ) ;
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
case LockType . Bluethooth :
return new Bikes . BikeInfoNS . BluetoothLock . BikeInfo (
new Bike (
bikeInfo . bike ,
LockModel . ILockIt ,
bikeInfo . GetWheelType ( ) ,
bikeInfo . GetTypeOfBike ( ) ,
bikeInfo . description ) ,
DriveFactory . Create ( bikeInfo ? . bike_type ) ,
2023-01-18 14:22:51 +01:00
dataSource ,
2022-09-06 16:08:19 +02:00
bikeInfo . GetBluetoothLockId ( ) ,
bikeInfo . GetBluetoothLockGuid ( ) ,
bikeInfo . station ,
bikeInfo . GetOperatorUri ( ) ,
2022-08-30 15:42:25 +02:00
#if ! NOTARIFFDESCRIPTION
2022-09-06 16:08:19 +02:00
bikeInfo . rental_description ! = null
? RentalDescriptionFactory . Create ( bikeInfo . rental_description )
: TariffDescriptionFactory . Create ( bikeInfo . tariff_description ) ,
2022-08-30 15:42:25 +02:00
#else
Create ( ( TINK . Repository . Response . TariffDescription ) null ) ,
#endif
2022-09-06 16:08:19 +02:00
bikeInfo . GetIsDemo ( ) ,
bikeInfo . GetGroup ( ) ) ;
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
default :
throw new ArgumentException ( $"Unsupported lock type {lockType} detected." ) ;
}
}
catch ( ArgumentException ex )
{
// Contructor reported invalid arguemts (missing lock id, ....).
Log . Error ( $"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Invalid response detected. Available bike with id {bikeInfo.bike} skipped. {ex.Message}" ) ;
return null ;
}
}
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
/// <summary> Creates a bike info object from copri response. </summary>
/// <param name="bikeInfo">Copri response. </param>
/// <param name="mailAddress">Mail address of user.</param>
/// <param name="dateTimeProvider">Date and time provider function.</param>
2023-01-18 14:22:51 +01:00
/// <param name="dataSource">Specified the source of the data.</param>
2022-09-06 16:08:19 +02:00
public static BikeInfo Create (
BikeInfoReservedOrBooked bikeInfo ,
string mailAddress ,
2023-01-18 14:22:51 +01:00
Func < DateTime > dateTimeProvider ,
DataSource dataSource )
2022-09-06 16:08:19 +02:00
{
if ( bikeInfo = = null ) throw new ArgumentNullException ( nameof ( bikeInfo ) ) ;
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
var lockModel = bikeInfo . GetLockModel ( ) ;
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
if ( lockModel . HasValue
& & lockModel . Value = = LockModel . BordComputer )
{
// Manual lock bikes are no more supported.
Log . Error (
$"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. " +
"Manual lock bikes are no more supported." +
$"Bike number: {bikeInfo.bike}{(bikeInfo.station != null ? $" , station number { bikeInfo . station } " : string.Empty)}."
) ;
return null ;
}
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
var lockType = lockModel . HasValue
? BikeExtension . GetLockType ( lockModel . Value )
: BikeExtension . GetLockType ( DEFAULTLOCKMODEL ) ; // Map bikes without "system"- entry in response to backend- locks.
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
// Check if bike is a bluetooth lock bike.
int lockSerial = bikeInfo . GetBluetoothLockId ( ) ;
Guid lockGuid = bikeInfo . GetBluetoothLockGuid ( ) ;
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
switch ( bikeInfo . GetState ( ) )
{
case InUseStateEnum . Reserved :
try
{
switch ( lockType )
{
case LockType . Bluethooth :
return new Bikes . BikeInfoNS . BluetoothLock . BikeInfo (
new Bike (
bikeInfo . bike ,
LockModel . ILockIt ,
bikeInfo . GetWheelType ( ) ,
bikeInfo . GetTypeOfBike ( ) ,
bikeInfo . description ) ,
DriveFactory . Create ( bikeInfo ? . bike_type ) ,
2023-01-18 14:22:51 +01:00
dataSource ,
2022-09-06 16:08:19 +02:00
lockSerial ,
lockGuid ,
bikeInfo . GetUserKey ( ) ,
bikeInfo . GetAdminKey ( ) ,
bikeInfo . GetSeed ( ) ,
bikeInfo . GetFrom ( ) ,
mailAddress ,
bikeInfo . station ,
bikeInfo . GetOperatorUri ( ) ,
2022-08-30 15:42:25 +02:00
#if ! NOTARIFFDESCRIPTION
2022-09-06 16:08:19 +02:00
bikeInfo . rental_description ! = null
? RentalDescriptionFactory . Create ( bikeInfo . rental_description )
: TariffDescriptionFactory . Create ( bikeInfo . tariff_description ) ,
2022-08-30 15:42:25 +02:00
#else
Create ( ( TINK . Repository . Response . TariffDescription ) null ) ,
#endif
2022-09-06 16:08:19 +02:00
dateTimeProvider ,
bikeInfo . GetIsDemo ( ) ,
bikeInfo . GetGroup ( ) ) ;
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
case LockType . Backend :
return new Bikes . BikeInfoNS . CopriLock . BikeInfo (
new Bike (
bikeInfo . bike ,
LockModel . Sigo ,
bikeInfo . GetWheelType ( ) ,
bikeInfo . GetTypeOfBike ( ) ,
bikeInfo . description ) ,
DriveFactory . Create ( bikeInfo ? . bike_type ) ,
2023-01-18 14:22:51 +01:00
dataSource ,
2022-09-06 16:08:19 +02:00
bikeInfo . GetFrom ( ) ,
mailAddress ,
bikeInfo . station ,
new Bikes . BikeInfoNS . CopriLock . LockInfo . Builder { State = bikeInfo . GetCopriLockingState ( ) } . Build ( ) ,
bikeInfo . GetOperatorUri ( ) ,
2022-08-30 15:42:25 +02:00
#if ! NOTARIFFDESCRIPTION
2022-09-06 16:08:19 +02:00
bikeInfo . rental_description ! = null
? RentalDescriptionFactory . Create ( bikeInfo . rental_description )
: TariffDescriptionFactory . Create ( bikeInfo . tariff_description ) ,
2022-08-30 15:42:25 +02:00
#else
Create ( ( TINK . Repository . Response . TariffDescription ) null ) ,
#endif
2022-09-06 16:08:19 +02:00
dateTimeProvider ,
bikeInfo . GetIsDemo ( ) ,
bikeInfo . GetGroup ( ) ) ;
default :
throw new ArgumentException ( $"Unsupported lock type {lockType} detected." ) ;
}
}
catch ( ArgumentException ex )
{
// Contructor reported invalid arguemts (missing lock id, ....).
Log . Error ( $"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoReservedOrBooked)} argument. Invalid response detected. Reserved bike with id {bikeInfo.bike} skipped. {ex.Message}" ) ;
return null ;
}
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
case InUseStateEnum . Booked :
try
{
switch ( lockModel )
{
case LockModel . ILockIt :
return new Bikes . BikeInfoNS . BluetoothLock . BikeInfo (
new Bike (
bikeInfo . bike ,
LockModel . ILockIt ,
bikeInfo . GetWheelType ( ) ,
bikeInfo . GetTypeOfBike ( ) ,
bikeInfo . description ) ,
DriveFactory . Create ( bikeInfo ? . bike_type ) ,
2023-01-18 14:22:51 +01:00
dataSource ,
2022-09-06 16:08:19 +02:00
lockSerial ,
bikeInfo . GetBluetoothLockGuid ( ) ,
bikeInfo . GetUserKey ( ) ,
bikeInfo . GetAdminKey ( ) ,
bikeInfo . GetSeed ( ) ,
bikeInfo . GetFrom ( ) ,
mailAddress ,
bikeInfo . station ,
bikeInfo . GetOperatorUri ( ) ,
2022-08-30 15:42:25 +02:00
#if ! NOTARIFFDESCRIPTION
2022-09-06 16:08:19 +02:00
bikeInfo . rental_description ! = null
? RentalDescriptionFactory . Create ( bikeInfo . rental_description )
: TariffDescriptionFactory . Create ( bikeInfo . tariff_description ) ,
2022-08-30 15:42:25 +02:00
#else
Create ( ( TINK . Repository . Response . TariffDescription ) null ) ,
#endif
2022-09-06 16:08:19 +02:00
bikeInfo . GetIsDemo ( ) ,
bikeInfo . GetGroup ( ) ) ;
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
case LockModel . BordComputer :
return new BikeInfo (
new Bike (
bikeInfo . bike ,
LockModel . BordComputer ,
bikeInfo . GetWheelType ( ) ,
bikeInfo . GetTypeOfBike ( ) ,
bikeInfo . description ) ,
DriveFactory . Create ( bikeInfo ? . bike_type ) ,
2023-01-18 14:22:51 +01:00
dataSource ,
2022-09-06 16:08:19 +02:00
bikeInfo . GetIsDemo ( ) ,
bikeInfo . GetGroup ( ) ,
bikeInfo . station ,
bikeInfo . GetOperatorUri ( ) ,
2022-08-30 15:42:25 +02:00
#if ! NOTARIFFDESCRIPTION
2022-09-06 16:08:19 +02:00
bikeInfo . rental_description ! = null
? RentalDescriptionFactory . Create ( bikeInfo . rental_description )
: TariffDescriptionFactory . Create ( bikeInfo . tariff_description ) ,
2022-08-30 15:42:25 +02:00
#else
Create ( ( TINK . Repository . Response . TariffDescription ) null ) ,
#endif
2022-09-06 16:08:19 +02:00
bikeInfo . GetFrom ( ) ,
mailAddress ,
bikeInfo . timeCode ) ;
default :
return new Bikes . BikeInfoNS . CopriLock . BikeInfo (
new Bike (
bikeInfo . bike ,
LockModel . Sigo ,
bikeInfo . GetWheelType ( ) ,
bikeInfo . GetTypeOfBike ( ) ,
bikeInfo . description ) ,
DriveFactory . Create ( bikeInfo ? . bike_type ) ,
2023-01-18 14:22:51 +01:00
DataSource . Copri ,
2022-09-06 16:08:19 +02:00
bikeInfo . GetFrom ( ) ,
mailAddress ,
bikeInfo . station ,
new Bikes . BikeInfoNS . CopriLock . LockInfo . Builder { State = bikeInfo . GetCopriLockingState ( ) } . Build ( ) ,
bikeInfo . GetOperatorUri ( ) ,
2022-08-30 15:42:25 +02:00
#if ! NOTARIFFDESCRIPTION
2022-09-06 16:08:19 +02:00
bikeInfo . rental_description ! = null
? RentalDescriptionFactory . Create ( bikeInfo . rental_description )
: TariffDescriptionFactory . Create ( bikeInfo . tariff_description ) ,
2022-08-30 15:42:25 +02:00
#else
Create ( ( TINK . Repository . Response . TariffDescription ) null ) ,
#endif
2022-09-06 16:08:19 +02:00
bikeInfo . GetIsDemo ( ) ,
bikeInfo . GetGroup ( ) ) ;
}
}
catch ( ArgumentException ex )
{
// Contructor reported invalid arguemts (missing lock id, ....).
Log . Error ( $"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoReservedOrBooked)} argument. Invalid response detected. Booked bike with id {bikeInfo.bike} skipped. {ex.Message}" ) ;
return null ;
}
2022-08-30 15:42:25 +02:00
2022-09-06 16:08:19 +02:00
default :
Log . Error ( $"Can not create new {nameof(BikeInfo)}-object from {nameof(BikeInfoAvailable)} argument. Unexpected state {bikeInfo.GetState()} detected." ) ;
return null ;
}
}
}
2022-08-30 15:42:25 +02:00
}