unit OpenAPI.Classes;

interface

uses
  SysUtils, Classes, Generics.Collections,
  Bcl.Collections, Bcl.Json.Attributes,
  XData.JSchema.Classes,
  OpenAPI.Json.Attributes, OpenAPI.Types;

type
  // Allows referencing an external resource for extended documentation.
  [OAJsonInclusion, OAJsonNaming]
  TExternalDoc = class
  strict private
    FDescription: string;
    FUrl: TUrl;
  public
    // A short description of the target documentation.
    property Description: string read FDescription write FDescription;
    // Required. The URL for the target documentation.
    property Url: TUrl read FUrl write FUrl;
  end;

  THeader = TJsonSchema;

  // Lists the headers that can be sent as part of a response.
  // Key: The name of the property corresponds to the name of the header.
  THeaders = class(TOrderedObjectDictionary<string, THeader>);

  // Describes a single response from an API Operation.
  [OAJsonInclusion, OAJsonNaming]
  TResponse = class
  strict private
    FDescription: string;
    FSchema: TJsonSchema;
    FHeaders: THeaders;
    function GetHeaders: THeaders;
    function GetDefinition: string;
    procedure SetDefinition(const Value: string);
    function GetAdditionalProperties: TJsonSchema;
    procedure SetAdditionalProperties(const Value: TJsonSchema);
  public
    constructor Create(const ADescription: string; ASchema: TJsonSchema = nil);
    destructor Destroy; override;
    // Required. A short description of the response.
    property Description: string read FDescription write FDescription;
    // A definition of the response structure. It can be a primitive, an array or an object.
    // If this field does not exist, it means no content is returned as part of the response.
    property Schema: TJsonSchema read FSchema;
    property Definition: string read GetDefinition write SetDefinition;
    property AdditionalProperties: TJsonSchema read GetAdditionalProperties write SetAdditionalProperties;
    // A list of headers that are sent with the response.
    property Headers: THeaders read GetHeaders;
    // An example of the response message.
    // property Examples: https://swagger.io/specification/#exampleObject
  end;

  // A container for the expected responses of an operation.
  // Key: Any HTTP status code can be used as the property name (one property per HTTP status code).
  TResponses = class(TOrderedObjectDictionary<string, TResponse>);

  // Allows adding meta data to a single tag that is used by the Operation Object.
  [OAJsonInclusion, OAJsonNaming]
  TTag = class
  strict private
    FName: string;
    FDescription: string;
    FExternalDocs: TExternalDoc;
    function GetExternalDocs: TExternalDoc;
  public
    destructor Destroy; override;
    // Required. The name of the tag.
    property Name: string read FName write FName;
    // A short description for the tag.
    property Description: string read FDescription write FDescription;
    // Additional external documentation for this tag.
    property ExternalDocs: TExternalDoc read GetExternalDocs write FExternalDocs;
  end;

  TTags = class(TObjectList<TTag>)
  public
    function Find(const Name: string): TTag;
  end;

  TMimeTypes = class(TList<string>)
  public
    class function Return(var MT: TMimeTypes): TMimeTypes;
    procedure Assign(Source: TMimeTypes);
  end;

implementation

uses
  OpenAPI.Utils;

{ TTag }

destructor TTag.Destroy;
begin
  FExternalDocs.Free;
  inherited;
end;

function TTag.GetExternalDocs: TExternalDoc;
begin
  if FExternalDocs = nil then
    FExternalDocs := TExternalDoc.Create;
  result := FExternalDocs;
end;

{ TResponse }

constructor TResponse.Create(const ADescription: string; ASchema: TJsonSchema);
begin
  Description := ADescription;
  FSchema := ASchema;
end;

destructor TResponse.Destroy;
begin
  FSchema.Free;
  FHeaders.Free;
  inherited;
end;

function TResponse.GetAdditionalProperties: TJsonSchema;
begin
  if Assigned(FSchema) and (FSchema is TObjectSchema) then
    result := TObjectSchema(FSchema).AdditionalPropertySchema
  else
    result := nil;
end;

function TResponse.GetDefinition: string;
begin
  if Assigned(FSchema) and (FSchema is TNameReferenceSchema) then
    result := TNameReferenceSchema(FSchema).Name
  else
    result := '';
end;

function TResponse.GetHeaders: THeaders;
begin
  if FHeaders = nil then
    FHeaders := THeaders.Create;
  result := FHeaders;
end;

procedure TResponse.SetAdditionalProperties(const Value: TJsonSchema);
begin
  Assert(Assigned(FSchema) and (FSchema is TObjectSchema));
  TObjectSchema(FSchema).AdditionalPropertySchema := Value;
end;

procedure TResponse.SetDefinition(const Value: string);
begin
  if Value > '' then
    TOpenAPIUtils.SetNameReference(FSchema, Value);
end;

{ TMimeTypes }

procedure TMimeTypes.Assign(Source: TMimeTypes);
begin
  Clear;
  AddRange(Source);
end;

class function TMimeTypes.Return(var MT: TMimeTypes): TMimeTypes;
begin
  if MT = nil then
    MT := TMimeTypes.Create;
  result := MT;
end;

{ TTags }

function TTags.Find(const Name: string): TTag;
var
  I: Integer;
begin
  for I := 0 to Count - 1 do
    if SameText(Name, Items[I].Name) then
      Exit(Items[I]);
  Result := nil;
end;

end.

