unit XData.JSchema.ListGenerator;

interface

uses
  Bcl.Collections,
  System.Rtti,
  XData.JSchema.Classes,
  XData.JSchema.Generators;

type
  TJSchemaListGenerator = class(TJSchemaGenerator)
  private
    {$IFDEF AUTOREFCOUNT}[Weak]{$ENDIF}
    FGenerators: TJSchemaGenerators;
    FItemTypeToken: TTypeToken;
  public
    constructor Create(const ATypeToken, AItemTypeToken: TTypeToken; AGenerators: TJSchemaGenerators);
    function CreateSchema: TJsonSchema; override;
  end;

  TJSchemaListGeneratorFactory = class(TInterfacedObject, IJSchemaGeneratorFactory)
  strict protected
    function CreateGenerator(Context: TJSchemaGeneratorContext; const ATypeToken: TTypeToken): IJSchemaGenerator;
  end;

implementation

{ TJSchemaListGenerator }

constructor TJSchemaListGenerator.Create(const ATypeToken,
  AItemTypeToken: TTypeToken; AGenerators: TJSchemaGenerators);
begin
  FItemTypeToken := AItemTypeToken;
  FGenerators := AGenerators;
end;

function TJSchemaListGenerator.CreateSchema: TJsonSchema;
var
  Schema: TArraySchema;
begin
  Schema := TArraySchema.Create;
  try
    FGenerators.TrySchemaDefinitions(Schema.Definitions);
    Schema.ItemSchemas.Add(FGenerators.ProcessRef(FItemTypeToken));
    Result := Schema;
  except
    Schema.Free;
    raise;
  end;
end;

{ TJSchemaListGeneratorFactory }

function TJSchemaListGeneratorFactory.CreateGenerator(
  Context: TJSchemaGeneratorContext;
  const ATypeToken: TTypeToken): IJSchemaGenerator;
var
  ItemTypeToken: TTypeToken;
  Clazz: TClass;
  ItemType: TRttiType;
begin
  Result := nil;
  Clazz := ATypeToken.GetClass;
  if IsValueList(Clazz) then
  begin
    if ATypeToken.ItemTypeInfo <> nil then
      ItemTypeToken := ATypeToken.ItemTypeInfo
    else
    begin
      ItemType := ValueListType(Clazz);
      if ItemType <> nil then
        ItemTypeToken := ItemType.Handle
      else
        ItemTypeToken := TTypeToken.Create(nil); // invalid
    end;

    if ItemTypeToken.TypeInfo <> nil then
      Result := TJSchemaListGenerator.Create(Clazz, ItemTypeToken, Context.Generators);
  end;
end;

end.
