unit Myc.Aura.Parameter;

interface

type
    TAuraParameterType = (apNone, apInteger, apFloat, apString, apUTC);

    TAuraParameterValue = record
    private
        FKind: TAuraParameterType;
        FPtr: Pointer;
        function GetAsInteger: Int64;
        procedure SetAsInteger(const Value: Int64);
        procedure SetKind(Kind: TAuraParameterType); inline;
        procedure FreeValue;
        function GetAsFloat: Double;
        function GetAsString: string;
        function GetAsUTC: TDateTime;
        procedure SetAsFloat(const Value: Double);
        procedure SetAsString(const Value: string);
        procedure SetAsUTC(const Value: TDateTime);
    public
        class operator Initialize(out Dest: TAuraParameterValue);
        class operator Finalize(var Dest: TAuraParameterValue);
        class operator Assign(var Dest: TAuraParameterValue; const [ref] Src: TAuraParameterValue);
        property AsInteger: Int64 read GetAsInteger write SetAsInteger;
        property AsFloat: Double read GetAsFloat write SetAsFloat;
        property AsString: string read GetAsString write SetAsString;
        property AsUTC: TDateTime read GetAsUTC write SetAsUTC;
    end;

implementation

{ TAuraParameterValue }

function TAuraParameterValue.GetAsInteger: Int64;
begin
    SetKind(apInteger);
    if FPtr = nil then
        exit(0);
    Result := Int64(FPtr^);
end;

procedure TAuraParameterValue.SetAsInteger(const Value: Int64);
begin
    SetKind(apInteger);
    if FPtr = nil then
        GetMem(FPtr, sizeof(Int64));
    Int64(FPtr^) := Value;
end;

procedure TAuraParameterValue.SetKind(Kind: TAuraParameterType);
begin
    if FKind <> Kind then
    begin
        FreeValue;
        FKind := Kind;
        FPtr := nil;
    end;
end;

class operator TAuraParameterValue.Assign(var Dest: TAuraParameterValue; const [ref] Src: TAuraParameterValue);
begin
    case Src.FKind of
        apInteger: Dest.AsInteger := Src.AsInteger;
        apFloat: Dest.AsInteger := Src.AsInteger;
        apString: Dest.AsString := Src.AsString;
        apUTC: Dest.AsUTC := Src.AsUTC;
    end;
end;

class operator TAuraParameterValue.Finalize(var Dest: TAuraParameterValue);
begin
    if Dest.FPtr <> nil then
        FreeMem(Dest.FPtr);
end;

class operator TAuraParameterValue.Initialize(out Dest: TAuraParameterValue);
begin
    Dest.FPtr := nil;
    Dest.FKind := apInteger;
end;

procedure TAuraParameterValue.FreeValue;
begin
    if FPtr <> nil then
    begin
        case FKind of
            apInteger, apFloat: FreeMem(FPtr);
            apString:
            begin
                String(FPtr^) := '';
                FreeMem(FPtr);
            end;
        end;
        FPtr := nil;
    end;
end;

function TAuraParameterValue.GetAsFloat: Double;
begin
    SetKind(apFloat);
    if FPtr = nil then
        exit(0);
    Result := Double(FPtr^);
end;

function TAuraParameterValue.GetAsString: string;
begin
    SetKind(apString);
    if FPtr = nil then
        exit('');
    Result := String(FPtr^);
end;

function TAuraParameterValue.GetAsUTC: TDateTime;
begin
    SetKind(apUTC);
    if FPtr = nil then
        exit(0);
    Result := TDateTime(FPtr^);
end;

procedure TAuraParameterValue.SetAsFloat(const Value: Double);
begin
    SetKind(apFloat);
    if FPtr = nil then
        GetMem(FPtr, sizeof(Double));
    Double(FPtr^) := Value;
end;

procedure TAuraParameterValue.SetAsString(const Value: string);
begin
    SetKind(apString);
    if FPtr = nil then
    begin
        GetMem(FPtr, sizeof(String));
        FillChar(FPtr^, sizeof(String), 0);
    end;
    String(FPtr^) := Value;
end;

procedure TAuraParameterValue.SetAsUTC(const Value: TDateTime);
begin
    SetKind(apUTC);
    if FPtr = nil then
        GetMem(FPtr, sizeof(TDateTime));
    TDateTime(FPtr^) := Value;
end;

end.
