unit TMS.ServerWizard.Creation.Module;

{$I bcl.inc}

interface

{$IFDEF DELPHIXE2_LVL}

uses
  System.SysUtils, ToolsAPI, TMS.ServerWizard.Types;

type
  TModuleKind = (mkUnit, mkVCLForm, mkFMXForm, mkService, mkDataModule);

  TModuleCreator = class(TInterfacedObject, IOTACreator, IOTAModuleCreator)
  private
    FOwningProject : IOTAProject;
    FKind : TModuleKind;
    FIdentiferMap : TIdentifierMap;
    FFilename: string;
    FOnFormCreated: TProc<IOTAFormEditor>;
    function IsFormOrServiceModule : Boolean;
  public
    constructor Create(const Project : IOTAProject; const ModuleKind : TModuleKind;
      const Filename : string; const IdentiferMap : TIdentifierMap);
    property OnFormCreated: TProc<IOTAFormEditor> read FOnFormCreated write FOnFormCreated;
  public
    // IOTACreator
    function GetCreatorType: string;
    function GetExisting: Boolean; virtual;
    function GetFileSystem: string;
    function GetOwner: IOTAModule;
    function GetUnnamed: Boolean;
    // IOTAModuleCreator
    function GetAncestorName: string;
    function GetImplFileName: string;
    function GetIntfFileName: string;
    function GetFormName: string;
    function GetMainForm: Boolean;
    function GetShowForm: Boolean;
    function GetShowSource: Boolean;
    function NewFormFile(const FormIdent, AncestorIdent: string): IOTAFile; virtual; abstract;
    function NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile; virtual; abstract;
    function NewIntfSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile;
    procedure FormCreated(const FormEditor: IOTAFormEditor);
  end;

  TModuleCreatorFromResource = class(TModuleCreator)
  private
    FResourceName : string;
  public
    constructor Create(const Project : IOTAProject; const ModuleKind : TModuleKind;
      const ResourceName : string; const Filename : string; const IdentifierMap : TIdentifierMap);

    function NewFormFile(const FormIdent, AncestorIdent: string): IOTAFile; override;
    function NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile; override;
  end;

  TModuleCreatorFromIOTAFile = class(TModuleCreator)
  private
    FExistingFile : IOTAFile;
  public
    constructor Create(const Project : IOTAProject; const ModuleKind : TModuleKind;
      const ExistingFile : IOTAFile; const Filename : string; const IdentifierMap : TIdentifierMap);

    function GetExisting: Boolean; override;
    function NewFormFile(const FormIdent, AncestorIdent: string): IOTAFile; override;
    function NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile; override;
  end;

  TModuleCreatorBlankDataModule = class(TModuleCreator)
  public
    constructor Create(const Project : IOTAProject; const ModuleKind : TModuleKind;
      const Filename : string; const IdentifierMap : TIdentifierMap);

    function GetExisting: Boolean; override;
    function NewFormFile(const FormIdent, AncestorIdent: string): IOTAFile; override;
    function NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile; override;
  end;

{$ENDIF}

implementation

{$IFDEF DELPHIXE2_LVL}

uses
  TMS.ServerWizard.Files, TMS.ServerWizard.Toolsapi.Utils,
  Vcl.Dialogs;

{ TModuleCreator }

constructor TModuleCreator.Create(const Project : IOTAProject;
  const ModuleKind : TModuleKind; const Filename : string; const IdentiferMap : TIdentifierMap);
begin
  inherited Create();
  FOwningProject := Project;
  FKind := ModuleKind;
  FIdentiferMap := IdentiferMap;
  FFilename := Filename;
end;

function TModuleCreator.IsFormOrServiceModule: Boolean;
begin
  Result := FKind in [TModuleKind.mkVCLForm, TModuleKind.mkFMXForm,
    TModuleKind.mkService, TModuleKind.mkDataModule];
end;

{$REGION 'IOTACreator'}
  function TModuleCreator.GetCreatorType: string;
  begin
    Result := sUnit; // or sForm
  end;

  function TModuleCreator.GetExisting: Boolean;
  begin
    Result := false; // This is a new unit
  end;

  function TModuleCreator.GetFileSystem: string;
  begin
    Result := '';
  end;

  function TModuleCreator.GetOwner: IOTAModule;
  begin
    Result := FOwningProject;
  end;

  function TModuleCreator.GetUnnamed: Boolean;
  begin
    Result := true; // IDE will let user save the file somewhere, possibly rename it
  end;

  function TModuleCreator.GetImplFileName: string;
  begin
    Result := IncludeTrailingPathDelimiter(GetDefaultFolder) + ChangeFileExt(FFilename, '.pas');
  end;

{$ENDREGION}

{$REGION 'IOTAModuleCreator'}
  procedure TModuleCreator.FormCreated(const FormEditor: IOTAFormEditor);
  begin
    if Assigned(FOnFormCreated) then
      FOnFormCreated(FormEditor);
  end;

  function TModuleCreator.GetAncestorName: string;
  begin
    case FKind of
      TModuleKind.mkVCLForm, TModuleKind.mkFMXForm : Result := 'TForm';
      TModuleKind.mkService : Result := 'TService';
      TModuleKind.mkDataModule : Result := 'TDataModule';
    end;
  end;

  function TModuleCreator.GetFormName: string;
  begin
    Result := '';
    case FKind of
      TModuleKind.mkVCLForm,
      TModuleKind.mkFMXForm,
      TModuleKind.mkService,
      TModuleKind.mkDataModule: Result := ChangeFileExt(FFilename, '');
    end;

    // If it's a form, has to have a name; if not, no name
    assert((not IsFormOrServiceModule) or (IsFormOrServiceModule and (Result <> '')));
  end;

  function TModuleCreator.GetIntfFileName: string;
  begin
    Result := ''; // Only for C++, the header file
  end;

  function TModuleCreator.GetMainForm: Boolean;
  begin
    Result := False; // Only one form, assume it's the main form
  end;

  function TModuleCreator.GetShowForm: Boolean;
  begin
    Result := IsFormOrServiceModule; // Show the form once it's created
  end;

  function TModuleCreator.GetShowSource: Boolean;
  begin
    // Show the source once created, but don't open the same file several times
    Result := (not IsFormOrServiceModule) and (not GetExisting);
  end;

  function TModuleCreator.NewIntfSource(const ModuleIdent, FormIdent,
    AncestorIdent: string): IOTAFile;
  begin
    Result := nil; // For a C++ header file
  end;
{$ENDREGION}

{ TModuleCreatorFromResource }

constructor TModuleCreatorFromResource.Create(const Project: IOTAProject;
  const ModuleKind: TModuleKind; const ResourceName: string;
  const Filename : string;  const IdentifierMap: TIdentifierMap);
begin
  inherited Create(Project, ModuleKind, Filename, IdentifierMap);
  FResourceName := ResourceName;
end;

function TModuleCreatorFromResource.NewFormFile(const FormIdent,
  AncestorIdent: string): IOTAFile;
begin
  // Forms have two resources, with FORM and UNIT suffixes
  if IsFormOrServiceModule then
    Result := TFileFromResource.Create(FResourceName + 'FORM', FIdentiferMap)
  else
    Result := TFileFromResource.Create(FResourceName, FIdentiferMap);
end;

function TModuleCreatorFromResource.NewImplSource(const ModuleIdent, FormIdent,
  AncestorIdent: string): IOTAFile;
begin
  // Forms have two resources, with FORM and UNIT suffixes
  if IsFormOrServiceModule then
    Result := TFileFromResource.Create(FResourceName + 'UNIT', FIdentiferMap)
  else
    Result := TFileFromResource.Create(FResourceName, FIdentiferMap);
end;

{ TModuleCreatorFromIOTAFile }

constructor TModuleCreatorFromIOTAFile.Create(const Project: IOTAProject;
  const ModuleKind: TModuleKind; const ExistingFile: IOTAFile; const Filename : string;
  const IdentifierMap: TIdentifierMap);
begin
  inherited Create(Project, ModuleKind, Filename, IdentifierMap);
  FExistingFile := ExistingFile;
end;

function TModuleCreatorFromIOTAFile.GetExisting: Boolean;
begin
  // Is this a new module or not? True if it exists already
  // Search for all modules in all projects for this file
  Result := Assigned(GetExistingModule(FFilename));
end;

function TModuleCreatorFromIOTAFile.NewFormFile(const FormIdent,
  AncestorIdent: string): IOTAFile;
begin
  assert(IsFormOrServiceModule);
  Result := FExistingFile;
end;

function TModuleCreatorFromIOTAFile.NewImplSource(const ModuleIdent, FormIdent,
  AncestorIdent: string): IOTAFile;
begin
  assert(not IsFormOrServiceModule);
  Result := FExistingFile;
end;

{ TModuleCreatorBlankDataModule }

constructor TModuleCreatorBlankDataModule.Create(const Project: IOTAProject;
  const ModuleKind: TModuleKind; const Filename: string;
  const IdentifierMap: TIdentifierMap);
begin
  inherited Create(Project, ModuleKind, Filename, IdentifierMap);
end;

function TModuleCreatorBlankDataModule.GetExisting: Boolean;
begin
  Result := Assigned(GetExistingModule(FFilename));
end;

function TModuleCreatorBlankDataModule.NewFormFile(const FormIdent,
  AncestorIdent: string): IOTAFile;
var
  Module : IOTAModule;
begin
  Module := GetExistingModule(FFilename);
  if Assigned(Module) then begin
    //Module.
  end else
    Result := TFileFromString.Create('object {CONNMODULE_VARNAME}: {CONNMODULE_CLASSNAME} end', FIdentiferMap);
end;

function TModuleCreatorBlankDataModule.NewImplSource(const ModuleIdent,
  FormIdent, AncestorIdent: string): IOTAFile;
var
  Module : IOTAModule;
begin
  Module := GetExistingModule(FFilename);
  if Assigned(Module) then begin

  end else
    Result := TFileFromString.Create('unit ' + ChangeFileExt(ExtractFileName(FFilename), '') + '; interface'
      + ' uses System.SysUtils, System.Classes; type {CONNMODULE_CLASSNAME} = class(TDataModule) private { Private declarations }'
      + ' public { Public declarations } end; var {CONNMODULE_VARNAME}: {CONNMODULE_CLASSNAME}; implementation '
      +' {%CLASSGROUP ''System.Classes.TPersistent''} {$R *.dfm} end.', FIdentiferMap);
end;

{$ENDIF}

end.
