unit XData.Json.Solver;

interface

uses
  Bcl.Rtti.ObjectFactory,
  Aurelius.Mapping.Optimization,
  Aurelius.Types.Blob,
  Aurelius.Types.Proxy,
  XData.Model.Classes;


type
  IJsonReferenceSolver = interface
  ['{98EBAA0C-FB64-48ED-93CB-85E85E9BA2FF}']
    function SolveReference(const Ref: string; RttiInfo: TRttiOptimization; Depth: integer): TObject;
    function SolveBlob(const Ref: string; RttiInfo: TRttiOptimization): TArray<byte>;
  end;

  IJsonExpander = interface
  ['{A73CEA4B-635C-4974-98B7-36F90C13BB4C}']
    function MustExpand(Prop: TXDataProperty): Boolean;
  end;

  TDeserializerProxyController = class(TInterfacedObject, IProxyController)
  private
    FSolver: IJsonReferenceSolver;
    FRef: string;
    FRttiInfo: TRttiOptimization;
    FProxyInfo: IProxyInfo;
    FDepth: integer;
    function LoadProxyValue: TObject;
    function ProxyInfo: IProxyInfo;
    procedure AfterLoad;
  public
    constructor Create(const ARef: string; ARttiInfo: TRttiOptimization;
      AProxyType: TProxyType; ASolver: IJsonReferenceSolver; ADepth: integer);
  end;

  TPlainProxyInfo = class(TInterfacedObject, IProxyInfo)
  private
    FRttiInfo: TRttiOptimization;
    FProxyType: TProxyType;
    function ProxyType: TProxyType;
    function ClassName: string;
    function MemberName: string;
    function Key: Variant;
  public
    constructor Create(ARttiInfo: TRttiOptimization; AProxyType: TProxyType);
  end;

  TDummyProxyController = class(TInterfacedObject, IProxyController)
  private
    FRttiInfo: TRttiOptimization;
    FProxyInfo: IProxyInfo;
    FFactory: IObjectFactory;
    function LoadProxyValue: TObject;
    function ProxyInfo: IProxyInfo;
    procedure AfterLoad;
  public
    constructor Create(ARttiInfo: TRttiOptimization; AProxyType: TProxyType;
      AFactory: IObjectFactory);
  end;

  TDeserializerBlobController = class(TInterfacedObject, IBlobController)
  private
    FSolver: IJsonReferenceSolver;
    FRef: string;
    FRttiInfo: TRttiOptimization;
    FBlobInfo: IBlobInfo;
    function ReadBlob: TArray<byte>;
    function BlobInfo: IBlobInfo;
    procedure AfterLoad;
  public
    constructor Create(const ARef: string; ARttiInfo: TRttiOptimization; ASolver: IJsonReferenceSolver);
  end;

  TPlainBlobInfo = class(TInterfacedObject, IBlobInfo)
  private
    FRttiInfo: TRttiOptimization;
    function ClassName: string;
    function MemberName: string;
    function Key: Variant;
  public
    constructor Create(ARttiInfo: TRttiOptimization);
  end;

implementation

uses
  System.Variants;

{ TPlainProxyInfo }

function TPlainProxyInfo.ClassName: string;
begin
  Result := '';
end;

constructor TPlainProxyInfo.Create(ARttiInfo: TRttiOptimization; AProxyType: TProxyType);
begin
  FRttiInfo := ARttiInfo;
  FProxyType := AProxyType;
end;

function TPlainProxyInfo.Key: Variant;
begin
  Result := System.Variants.Null;
end;

function TPlainProxyInfo.MemberName: string;
begin
  Result := '';
end;

function TPlainProxyInfo.ProxyType: TProxyType;
begin
  Result := FProxyType;
end;

{ TDeserializerProxyController }

procedure TDeserializerProxyController.AfterLoad;
begin
end;

constructor TDeserializerProxyController.Create(const ARef: string;
  ARttiInfo: TRttiOptimization; AProxyType: TProxyType; ASolver: IJsonReferenceSolver; ADepth: integer);
begin
  FRef := ARef;
  FRttiInfo := ARttiInfo;
  FSolver := ASolver;
  FDepth := ADepth;
  FProxyInfo := TPlainProxyInfo.Create(FRttiInfo, AProxyType);
end;

function TDeserializerProxyController.LoadProxyValue: TObject;
begin
  Result := FSolver.SolveReference(FRef, FRttiInfo, FDepth);
end;

function TDeserializerProxyController.ProxyInfo: IProxyInfo;
begin
  Result := FProxyInfo;
end;

{ TPlainBlobInfo }

function TPlainBlobInfo.ClassName: string;
begin
  Result := '';
end;

constructor TPlainBlobInfo.Create(ARttiInfo: TRttiOptimization);
begin
  FRttiInfo := ARttiInfo;
end;

function TPlainBlobInfo.Key: Variant;
begin
  Result := System.Variants.Null;
end;

function TPlainBlobInfo.MemberName: string;
begin
  Result := '';
end;

{ TDeserializerBlobController }

procedure TDeserializerBlobController.AfterLoad;
begin
end;

function TDeserializerBlobController.BlobInfo: IBlobInfo;
begin
  Result := FBlobInfo;
end;

constructor TDeserializerBlobController.Create(const ARef: string; ARttiInfo: TRttiOptimization;
  ASolver: IJsonReferenceSolver);
begin
  FRef := ARef;
  FRttiInfo := ARttiInfo;
  FSolver := ASolver;
  FBlobInfo := TPlainBlobInfo.Create(FRttiInfo);
end;

function TDeserializerBlobController.ReadBlob: TArray<byte>;
begin
  Result := FSolver.SolveBlob(FRef, FRttiInfo);
end;

{ TDummyProxyController }

procedure TDummyProxyController.AfterLoad;
begin

end;

constructor TDummyProxyController.Create(ARttiInfo: TRttiOptimization;
  AProxyType: TProxyType; AFactory: IObjectFactory);
begin
  FRttiInfo := ARttiInfo;
  FFactory := AFactory;
  FProxyInfo := TPlainProxyInfo.Create(FRttiInfo, AProxyType);
end;

function TDummyProxyController.LoadProxyValue: TObject;
begin
  if ProxyInfo.ProxyType = TProxyType.List then
    Result := FFactory.CreateInstance(FRttiInfo.MemberClass)
  else
    Result := nil;
end;

function TDummyProxyController.ProxyInfo: IProxyInfo;
begin
  Result := FProxyInfo;
end;

end.