{
    This file is part of the Free Pascal run time library.
    Copyright (c) 2019 by the Free Pascal development team

    SQLDB REST rest bridge demo applocation.

    See the file COPYING.FPC, included in this distribution,
    for details about the copyright.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 **********************************************************************}

program demorestbridge;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, SysUtils, CustApp, sqldbrestbridge, fphttpapp, IBConnection, odbcconn, mysql55conn, mysql56conn, pqconnection,
  mssqlconn, oracleconnection, sqldbrestxml, sqldbrestio, sqldbrestschema, sqldbrestdata, sqldbrestjson, sqldbrestcsv, sqldbrestcds,
  sqldbrestado,  sqldbrestconst, sqldbrestauth, sqldbrestini, sqldb, sqldbrestauthini;

type
  { TXMLSQLDBRestDispatcher }

  TXMLSQLDBRestDispatcher = class(TSQLDBRestDispatcher)
    Function CreateOutputStreamer(IO: TRestIO): TRestOutputStreamer; override;
  end;

  { TRestServerDemoApplication }

  TRestServerDemoApplication = class(THTTPApplication)
  private
    procedure DoAfterRequest(Sender: TObject; aConn: TSQLConnection; aResource: TSQLDBRestResource);
  Protected
    FAuth : TRestBasicAuthenticator;
    FDisp : TSQLDBRestDispatcher;
    FRequestCount,
    FMaxRequests : integer;
  protected
    procedure DoRun; override;
  public
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
    procedure WriteHelp; virtual;
  end;

{ TXMLSQLDBRestDispatcher }

function TXMLSQLDBRestDispatcher.CreateOutputStreamer(IO: TRestIO): TRestOutputStreamer;
begin
  io.Response.ContentStream:=TMemoryStream.Create;
  io.Response.FreeContentStream:=True;
  Result:=TXMLOutputStreamer.Create(IO.Response.ContentStream,Strings,Statuses, @IO.DoGetVariable);
end;

{ TRestServerDemoApplication }

procedure TRestServerDemoApplication.DoAfterRequest(Sender: TObject; aConn: TSQLConnection; aResource: TSQLDBRestResource);
begin
  inc(FRequestCount);
  if (FMaxRequests>0) and (FRequestCount>=FMaxRequests) then
    begin
    DoLog(etInfo,'Maximum requests reached');
    Terminate;
    end;
end;

procedure TRestServerDemoApplication.DoRun;
var
  ErrorMsg: String;
begin
  // quick check parameters
  ErrorMsg:=CheckOptions('hc:s:m:', ['help','config:','save-config:','max-requests:']);
  if ErrorMsg<>'' then begin
    ShowException(Exception.Create(ErrorMsg));
    Terminate;
    Exit;
  end;

  // parse parameters
  if HasOption('h', 'help') then begin
    WriteHelp;
    Terminate;
    Exit;
  end;
  Port:=3000;
  if HasOption('x','xml-only') then
    FDisp:=TXMLSQLDBRestDispatcher.Create(Self)
  else
    FDisp:=TSQLDBRestDispatcher.Create(Self);
  if HasOption('c', 'config') then
    FDisp.LoadFromFile(GetOptionValue('c', 'config'),[dioSkipReadSchemas])
  else
    begin
    // create a Default setup
    FAuth:=TRestBasicAuthenticator.Create(Self);
    // This is not the DB user !
    FAuth.DefaultUserName:='me';
    FAuth.DefaultPassword:='secret';
    FAuth.AuthenticateUserSQL.Text:='select uID from users where (uLogin=:UserName) and (uPassword=:Password)';
    FDisp.DispatchOptions:=FDisp.DispatchOptions+[rdoCustomView,rdoHandleCORS];
    FDisp.ExposeDatabase(TPQConnectionDef.TypeName,'localhost','expensetracker','You','YourSecret',Nil,[foFilter,foInInsert,foInUpdate,foOrderByDesc]);
    With FDisp.Schemas[0].Schema.Resources do
      begin
      FindResourceByName('users').Fields.FindByFieldName('uID').GeneratorName:='seqUsersID';
      FindResourceByName('projects').Fields.FindByFieldName('pID').GeneratorName:='seqProjectsID';
      FindResourceByName('expensetypes').Fields.FindByFieldName('etID').GeneratorName:='seqExpenseTypesID';
      FindResourceByName('expenses').Fields.FindByFieldName('eID').GeneratorName:='seqExpenseID';
      end;
    FDisp.Authenticator:=Fauth;
    if HasOption('s','save-config') then
      FDisp.SaveToFile(GetOptionValue('s','save-config'));
    end;
  // Mostly for debug purposes, to get e.g. a heap trace
  if HasOption('m','max-requests') then
    FMaxRequests:=StrToIntDef(GetOptionValue('m','max-requests'),0);
  FDisp.AfterGet:=@DoAfterRequest;
  FDisp.AfterPost:=@DoAfterRequest;
  FDisp.AfterPut:=@DoAfterRequest;
  FDisp.AfterDelete:=@DoAfterRequest;
  FDisp.Active:=True;
  Inherited DoRun;
end;

constructor TRestServerDemoApplication.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  StopOnException:=True;
end;

destructor TRestServerDemoApplication.Destroy;
begin
  FreeAndNil(FDisp);
  FreeAndNil(FAuth);
  inherited Destroy;
end;

procedure TRestServerDemoApplication.WriteHelp;
begin
  writeln('Usage: ', ExeName, ' [options]');
  Writeln('Where options is one or more of:');
  Writeln('-h --help             this message');
  Writeln('-c --config=File      Read config from .ini file');
  Writeln('-m --max-requests=N   Server at most N requests, then quit.');
  Writeln('-s --saveconfig=File  Write config to .ini file (ignored when -c or --config is used)');
  Writeln('-x --xml-only         Only allow XML requests)');
end;

var
  Application: TRestServerDemoApplication;

begin
  Application:=TRestServerDemoApplication.Create(nil);
  Application.Title:='SQLDB REST bridge Application';
  Application.Run;
  Application.Free;
end.

