unit Myc.Data.Types.Ordinal;

interface

uses
    Myc.Data.Types,
    System.SysUtils;

type
    // Implements the ordinal data type.
    TImplDataOrdinalType = class(TInterfacedObject, IDataType, IDataOrdinalType)
    strict private
        class var
            FSingleton: IDataOrdinalType;
            FMinusOne, FZero, FOne: IDataOrdinalValue; // Singletons for -1, 0, 1
        class constructor CreateClass;
    public
        function GetName: String;
        function GetKind: TDataKind;
        function CreateValue(Init: Int64): IDataOrdinalValue;
        class property Singleton: IDataOrdinalType read FSingleton;
    end;

implementation

uses
    System.Rtti;

type
    // Implements the ordinal data value.
    TImplDataOrdinalValue = class(TInterfacedObject, IDataValue, IDataOrdinalValue)
    private
        FValue: Int64;
    public
        constructor Create(const AValue: Int64);

        // IDataValue
        function GetDataType: IDataType;
        function GetAsString: string;

        // IDataOrdinalValue
        function GetValue: Int64;
    end;

    // Specialized implementation for the value -1.
    TDataOrdinalValueMinusOne = class(TInterfacedObject, IDataValue, IDataOrdinalValue)
    strict private
        class var
            FValue: TValue;
        class constructor CreateClass;
    public
        function GetDataType: IDataType;
        function GetAsString: string;
        function GetValue: Int64;
    end;

    // Specialized implementation for the value 0.
    TDataOrdinalValueZero = class(TInterfacedObject, IDataValue, IDataOrdinalValue)
    strict private
        class var
            FValue: TValue;
        class constructor CreateClass;
    public
        function GetDataType: IDataType;
        function GetAsString: string;
        function GetValue: Int64;
    end;

    // Specialized implementation for the value 1.
    TDataOrdinalValueOne = class(TInterfacedObject, IDataValue, IDataOrdinalValue)
    strict private
        class var
            FValue: TValue;
        class constructor CreateClass;
    public
        function GetDataType: IDataType;
        function GetAsString: string;
        function GetValue: Int64;
    end;

{ TImplDataOrdinalValue }

constructor TImplDataOrdinalValue.Create(const AValue: Int64);
begin
    inherited Create;
    FValue := AValue;
end;

function TImplDataOrdinalValue.GetDataType: IDataType;
begin
    Result := TImplDataOrdinalType.Singleton;
end;

function TImplDataOrdinalValue.GetAsString: string;
begin
    Result := FValue.ToString;
end;

function TImplDataOrdinalValue.GetValue: Int64;
begin
    Result := FValue;
end;

{ TDataOrdinalValueMinusOne }

class constructor TDataOrdinalValueMinusOne.CreateClass;
begin
    FValue := TValue.From<Int64>(-1);
end;

function TDataOrdinalValueMinusOne.GetDataType: IDataType;
begin
    Result := TImplDataOrdinalType.Singleton;
end;

function TDataOrdinalValueMinusOne.GetAsString: string;
begin
    Result := '-1';
end;

function TDataOrdinalValueMinusOne.GetValue: Int64;
begin
    Result := -1;
end;

{ TDataOrdinalValueZero }

class constructor TDataOrdinalValueZero.CreateClass;
begin
    FValue := TValue.From<Int64>(0);
end;

function TDataOrdinalValueZero.GetDataType: IDataType;
begin
    Result := TImplDataOrdinalType.Singleton;
end;

function TDataOrdinalValueZero.GetAsString: string;
begin
    Result := '0';
end;

function TDataOrdinalValueZero.GetValue: Int64;
begin
    Result := 0;
end;

{ TDataOrdinalValueOne }

class constructor TDataOrdinalValueOne.CreateClass;
begin
    FValue := TValue.From<Int64>(1);
end;

function TDataOrdinalValueOne.GetDataType: IDataType;
begin
    Result := TImplDataOrdinalType.Singleton;
end;

function TDataOrdinalValueOne.GetAsString: string;
begin
    Result := '1';
end;

function TDataOrdinalValueOne.GetValue: Int64;
begin
    Result := 1;
end;

{ TImplDataOrdinalType }

class constructor TImplDataOrdinalType.CreateClass;
begin
    FSingleton := TImplDataOrdinalType.Create;
    FMinusOne := TDataOrdinalValueMinusOne.Create;
    FZero := TDataOrdinalValueZero.Create;
    FOne := TDataOrdinalValueOne.Create;
end;

function TImplDataOrdinalType.GetName: String;
begin
    Result := 'Integer';
end;

function TImplDataOrdinalType.GetKind: TDataKind;
begin
    Result := dkOrdinal;
end;

function TImplDataOrdinalType.CreateValue(Init: Int64): IDataOrdinalValue;
begin
    // Use specialized singletons for common values.
    case Init of
        -1: Result := FMinusOne;
        0: Result := FZero;
        1: Result := FOne;
    else
        Result := TImplDataOrdinalValue.Create(Init);
    end;
end;

end.
