AirlineReservation.cpp

// AirlineReservation.cpp
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2008

@import "Ceda/cxOperation/UTRoot.h"
@import "Ceda/cxOperation/IWorkingSetMachine.h"

@import "Ceda/cxWorkingSetIpc/WorkingSetIPC.h"

@import "Ceda/cxPersistStore/IPersistStore.h"

@import "Ceda/cxObject/IObjectVisitor.h"
@import "Ceda/cxObject/PrintReflectedVariable.h"
@import "Ceda/cxObject/ReflectedHPTime.h"
@import "Ceda/cxObject/Guid2.h"

#include "Ceda/cxUtils/CedaAssert.h"
#include "Ceda/cxUtils/HPTime.h"
#include "Ceda/cxUtils/Tracer.h"
#include "Ceda/cxUtils/Environ.h"
#include "Ceda/cxUtils/ScopeWriter.h"

namespace airlineres
{
    $typedef+ assignable<string8> TString;    // UTF-8

    /////////// version

    $model+ TVersion
    {
        uint32 Major;
        uint32 Minor;
        uint32 Build;
        uint32 Revision;
    };

    $struct+ TAppVersionInfo <<multiline>> isa ceda::IPersistable :
        model
        {
            assignable<ceda::xstring> AppName;
            ceda::MGuid AppId;
            ceda::HPTime FirstOpenTime;
            ceda::HPTime LastOpenTime;
            assignable<TVersion> FirstOpenVersion;
            assignable<TVersion> LastOpenVersion;
        }
    {
    };

    /////////// Date-time

    $enum+ class TMonth
    {
        January,
        February,
        March,
        April,
        May,
        June,
        July,
        August,
        September,
        October,
        November,
        December
    };
    
    $model+ TDate
    {
        int16 Year;
        TMonth Month;   // 1-12
        int8 Day;       // 1-31
    };

    $model+ TTime
    {
        int8 Hour;      // 0-23
        int8 Minute;    // 0-59
        int8 Second;    // 0-59
    };

    $model+ TDateTime <<multiline>>
    {
        TDate Date;
        TTime Time;
    };

    /////////// Address
    
    $model+ TAddress <<multiline>>
    {
        TString Street;
        TString City;
        TString State;
        TString PostalCode;
    };
    
    /////////// Passenger

    $enum+ class TSex
    {
        Male,
        Female
    };

    $enum+ class TMarriedStatus
    {
        Single,
        Married
    };

    $model+ TPassenger <<multiline>>
    {
        TString LastName;
        TString FirstName;
        TAddress Address;
        TSex Sex;
        assignable<TDate> DateOfBirth;
        TMarriedStatus MarriedStatus;
        TString PhoneNumber;
        TString EmailAddress;
        int32 FrequentFlyerMiles;
    };

    /////////// AirPlane
    
    $typedef+ int32 TSeatNumber;
    
    $enum+ class TSeatType
    {
        Window,
        Aisle
    };

    $enum+ class TSeatClass
    {
        First,
        Business,
        Economy
    };

    $enum+ class TSmoking
    {
        Smoking,
        NonSmoking
    };
    
    $model+ TSeatInfo <<multiline>>
    {
        int32 Level;
        int32 Row;
        char8 Pos;          // '0'-'5'
        TSmoking Smoking;
        TSeatType SeatType;
        TSeatClass SeatClass;
    };
    
    $enum+ class TAirplaneMake
    {
        Boeing,
        Airbus,
        Bombardier,
        Embraer,
        Raytheon,
        Cessna
    };
    
    $model+ TAirPlane <<multiline>>
    {
        TAirplaneMake AirPlaneMake;
        TString ModelNumber;
        TString RegistrationNumber;
        int32 SeatingCapacity;
        float64 CruisingSpeed;
        xmap<TSeatNumber,TSeatInfo> SeatInfo;
    };

    /////////// Flight
    
    $model+ TEftPOS
    {
        bool DomesticOnly;
        bool ChipEnabled;
        TString AccountName;
    };

    $model+ TCheque
    {
        int32 Number;
        TString AccountName;
    };
    
    $variant+ TPayment
    {
        void;
        TEftPOS;
        TCheque;
    };

    $typedef+ float64 TWeight;

    $model+ TSeatAllocation <<multiline>>
    {
        assignable<TDateTime> DateTime;
        bool Allocated;
        TPassenger Passenger;
        TPayment Payment;
        xvector<TWeight> BaggageItems;
    };
    
    $typedef+ int32 TFlightNumber;
    $typedef+ int32 TGate;
    $typedef+ TString TAirline;
    
    $model+ TAirport <<multiline>>
    {
        TString IATACode;
        TString City;
        TString Country;
    };

    $class+ TFlight <<multiline>> isa ceda::IPersistable :
        model
        {
            TAirline AirLine;
            TAirPlane AirPlane;
            xmap<TSeatNumber, TSeatAllocation> SeatAllocations;
            TFlightNumber FlightNumber;

            assignable<TDateTime> DepartureDateTime;
            TAirport DepartureAirport;
            TGate DepartureGate;

            assignable<TDateTime> ArrivalDateTime;
            TAirport ArrivalAirport;
            TGate ArrivalGate;
        }
    {
    };

    $class+ TAirplaneReservationSystem isa ceda::IPersistable :
        model
        {
            cref<TAppVersionInfo> AppVersionInfo;
            xvector<movable<cref<TFlight> > > Flights;
        }
    {
    public:
        TFlight& AddFlight()
        {
            TFlight* f = $new TFlight;
            Flights.insert(0,f);
            return *f;
        }    
    };

    ///////////////////////////////////////////////////////////////////////////////////////////////////
    /*
    A simple test that creates a database containing two independent working sets, populates one with
    some data and creates a TCP socket connection to allow them to synchronise

    Generated ouput:

          Open persistent store
          Open PSpace
          Open two working sets
          Open client and server
          Create AirplaneReservationSystem on first working set
          Generate operations on first working set
          Wait for operations to be applied to second working set
          Show result on second working set

          TFlight
          {
              AirLine = Quantas
              AirPlane = TAirPlane
              {
                  AirPlaneMake = Boeing
                  ModelNumber = 747-400
                  RegistrationNumber = R-1025
                  SeatingCapacity = 416
                  CruisingSpeed = 920
                  SeatInfo =
                  {
                      0 --> TSeatInfo
                      {
                          Level = 1
                          Row = 1
                          Pos = 0
                          Smoking = Smoking
                          SeatType = Window
                          SeatClass = First
                      }
                      1 --> TSeatInfo
                      {
                          Level = 1
                          Row = 1
                          Pos = 1
                          Smoking = Smoking
                          SeatType = Aisle
                          SeatClass = First
                      }
                      2 --> TSeatInfo
                      {
                          Level = 1
                          Row = 1
                          Pos = 2
                          Smoking = Smoking
                          SeatType = Window
                          SeatClass = First
                      }
                      3 --> TSeatInfo
                      {
                          Level = 1
                          Row = 2
                          Pos = 0
                          Smoking = Smoking
                          SeatType = Aisle
                          SeatClass = First
                      }
                      4 --> TSeatInfo
                      {
                          Level = 1
                          Row = 2
                          Pos = 1
                          Smoking = Smoking
                          SeatType = Aisle
                          SeatClass = First
                      }
                      5 --> TSeatInfo
                      {
                          Level = 1
                          Row = 2
                          Pos = 2
                          Smoking = Smoking
                          SeatType = Aisle
                          SeatClass = First
                      }
                  }
              }
              SeatAllocations =
              {
                  0 --> TSeatAllocation
                  {
                      DateTime = TDateTime
                      {
                          Date = TDate(2009,February,10)
                          Time = TTime(21,17,23)
                      }
                      Allocated = 1
                      Passenger = TPassenger
                      {
                          LastName = Smith
                          FirstName = Jane
                          Address = TAddress
                          {
                              Street = Old Kent Road
                              City = London
                              State =
                              PostalCode =
                          }
                          Sex = Female
                          DateOfBirth = TDate(1985,June,23)
                          MarriedStatus = Single
                          PhoneNumber =
                          EmailAddress =
                          FrequentFlyerMiles = 0
                      }
                      Payment = TEftPOS(1,1,Joe Smith)
                      BaggageItems = [24.7,12.2]
                  }
              }
              FlightNumber = 10
              DepartureDateTime = TDateTime
              {
                  Date = TDate(2009,February,10)
                  Time = TTime(22,30,0)
              }
              DepartureAirport = TAirport
              {
                  IATACode = PER
                  City = Perth
                  Country = Australia
              }
              DepartureGate = 22
              ArrivalDateTime = TDateTime
              {
                  Date = TDate(2009,February,11)
                  Time = TTime(5,12,0)
              }
              ArrivalAirport = TAirport
              {
                  IATACode = LHR
                  City = London
                  Country = England
              }
              ArrivalGate = 7
          }
    */

    void AirplaneReservationSystemExample()
    {
        Tracer() << "AirplaneReservationSystem example\n";
        ceda::TraceIndenter indent;

        ceda::xstring path = ceda::GetCedaTestPath("AirplaneReservationSystem.ceda");
        
        Tracer() << "Open persistent store\n";
        ceda::PersistStore* pstore = ceda::OpenPersistStore(path.c_str(),ceda::OM_CREATE_ALWAYS);
        {
            Tracer() << "Open PSpace\n";
            ceda::WPSpace pspace(ceda::OpenPSpace(pstore, "MyPSpace"));

            Tracer() << "Open two working sets\n";
            ceda::WorkingSetMachine* ws1 = nullptr;
            ceda::WorkingSetMachine* ws2 = nullptr;
            {
                ceda::CSpaceTxn txn;
                ws1 = ceda::OpenWorkingSetMachine("WS1",true);
                ws2 = ceda::OpenWorkingSetMachine("WS2",false);
            }
            
            {
                ceda::TcpMsgServer* server;
                ceda::TcpMsgClient* client;
                {
                    Tracer() << "Open client and server\n";
                    ceda::CSpaceTxn txn;
                    const ceda::WsipcSessionProtocolId protocolId = { "AirlineReservation", 1 };
                    ceda::WsipcHostInfo localHostInfo;
                    auto protocol = ceda::EProtocol::TCP_IPv4;
                    int port = 3000;
                    bool reuse_addr = false;
                    ceda::TcpMsgSessionSettings sessionSettings;
                    server = CreateTcpMsgServer(protocol, port, reuse_addr, 
                        *CreateWsipcEndPoint(ws1, protocolId, localHostInfo), sessionSettings);
                    
                    const char* host = "127.0.0.1";
                    const char* service = "3000";
                    client = CreateTcpMsgClient(host, service, 
                        *CreateWsipcEndPoint(ws2, protocolId, localHostInfo), sessionSettings);
                }
                
                {
                    Tracer() << "Create AirplaneReservationSystem on first working set\n";
                    ceda::CSpaceTxn txn;
                    ceda::UTRoot& r = GetUTRoot(ws1);
                    TAirplaneReservationSystem* s1 = $new TAirplaneReservationSystem;
                    r.Map["AirlineReservationSystem"].insert(0,s1);
                    TFlight& f = s1->AddFlight();
                    f.AirLine = "Quantas";
                    f.AirPlane.AirPlaneMake = TAirplaneMake::Boeing;
                    f.AirPlane.ModelNumber = "747-400";
                    f.AirPlane.RegistrationNumber = "R-1025";
                    f.AirPlane.SeatingCapacity = 416;
                    f.AirPlane.CruisingSpeed = 920.0;   // km/h
                    for (int i=0 ; i < 6 ; ++i)
                    {
                        f.AirPlane.SeatInfo[i].Level = 1;
                        f.AirPlane.SeatInfo[i].Row = 1+i/3;
                        f.AirPlane.SeatInfo[i].Pos = '0' + i%3;
                        f.AirPlane.SeatInfo[i].Smoking = TSmoking::Smoking;
                        f.AirPlane.SeatInfo[i].SeatType = (i==0 || i == 2) ? TSeatType::Window : TSeatType::Aisle;
                        f.AirPlane.SeatInfo[i].SeatClass = TSeatClass::First;
                    }
                }

                {
                    Tracer() << "Generate operations on first working set\n";
                    ceda::CSpaceTxn txn;
                    TAirplaneReservationSystem* s1 = ceda::GetUTRootEntry<TAirplaneReservationSystem>(ws1,"AirlineReservationSystem");

                    const ceda::Guid appId = { 0xea9d7f10, 0x4164, 0x4434, { 0xed, 0x1e, 0x78, 0x5e, 0x3e, 0x55, 0x59, 0x2f } };

                    s1->AppVersionInfo = $new TAppVersionInfo();
                    s1->AppVersionInfo->AppName = "AirlineReservationSystem";
                    s1->AppVersionInfo->AppId.Value = appId;
                    s1->AppVersionInfo->FirstOpenTime = ceda::HPTime::GetCurrentTime();
                    s1->AppVersionInfo->FirstOpenVersion = TVersion(3, 1, 0, 0);

                    TFlight& f = *s1->Flights.read()[0];
                    f.SeatAllocations[0].DateTime = TDateTime( TDate(2009,TMonth::February,10), TTime(21,17,23) );
                    f.SeatAllocations[0].Allocated = true;
                    f.SeatAllocations[0].Passenger.FirstName = "Jane";
                    f.SeatAllocations[0].Passenger.LastName = "Smith";
                    f.SeatAllocations[0].Passenger.Address.Street = "Old Kent Road";
                    f.SeatAllocations[0].Passenger.Address.City = "London";
                    f.SeatAllocations[0].Passenger.DateOfBirth = TDate(1985,TMonth::June,23);
                    f.SeatAllocations[0].Passenger.Sex = TSex::Female;
                    f.SeatAllocations[0].Payment = TEftPOS(true,true,"Joe Smith");
                    f.SeatAllocations[0].BaggageItems.push_back(24.7);
                    f.SeatAllocations[0].BaggageItems.push_back(12.2);
                    f.FlightNumber = 10;
                    f.DepartureDateTime = TDateTime( TDate(2009,TMonth::February,10), TTime(22,30,00) );
                    f.DepartureGate = 22;
                    f.DepartureAirport.IATACode = "PER";
                    f.DepartureAirport.City = "Perth";
                    f.DepartureAirport.Country = "Australia";
                    f.ArrivalDateTime = TDateTime( TDate(2009,TMonth::February,11), TTime(05,12,00) );
                    f.ArrivalGate = 7;
                    f.ArrivalAirport.IATACode = "LHR";
                    f.ArrivalAirport.City = "London";
                    f.ArrivalAirport.Country = "England";
                }

                Tracer() << "Wait for operations to be applied to second working set\n";
                while(1)
                {
                    Sleep(10);
                    ceda::CSpaceTxn txn;
                    if (HistoryBufferSize(ws2) == 2) break;
                }
                
                {
                    Tracer() << "Show result on second working set\n";
                    ceda::CSpaceTxn txn;

                    TAirplaneReservationSystem* s2 = 
                        ceda::GetUTRootEntry<TAirplaneReservationSystem>(
                            ws2,"AirlineReservationSystem");
                    TFlight& f = *s2->Flights.read()[0];
                    ceda::PrintInstance(Tracer(), &f);
                    Tracer() << '\n';
                    ceda::PrintInstance(Tracer(), s2->AppVersionInfo.Get());
                    Tracer() << '\n';
                }
                Close(server);
                Close(client);
            }

            {
                ceda::CSpaceTxn txn;
                Close(ws1);
                Close(ws2);
            }
        }
        Close(pstore);
    }
} // namespace airlineres