 SetLogToFile(const Value: Boolean);
    procedure SetLogFilename(const Value: String);
    procedure ListFiles(const PathName, FileName: string; const InDir: boolean; outFiles: TStrings);
    procedure SetDoSubDirs(const Value: Boolean);
    procedure SetIsDirInput(const Value: Boolean);
    procedure SetIsFileInput(const Value: Boolean);
    function NewFileNameFromBase(OldBase, NewBase, FileName, NewExt: String): String;
    procedure SetOutputExt(const Value: string);
    function GetUrl(Url: string): String;

    function URLEncode(Param : String): String;
    procedure SetHaltOnWordError(const Value: Boolean);
    procedure SetRemoveFileOnConvert(const Value: boolean);
    procedure SetIsDirOutput(const Value: Boolean);
    procedure SetIsFileOutput(const Value: Boolean);
    procedure SetLogLevel(const Value: integer);
    property IsFileInput : Boolean read FIsFileInput write SetIsFileInput;
    property IsDirInput : Boolean read FIsDirInput write SetIsDirInput;
    property IsFileOutput : Boolean read FIsFileOutput write SetIsFileOutput;
    property IsDirOutput : Boolean read FIsDirOutput write SetIsDirOutput;
    property DoSubDirs : Boolean read FDoSubDirs write SetDoSubDirs;
    property OutputExt : string read FOutputExt write SetOutputExt;
    property LogLevel : integer read FLogLevel write SetLogLevel;
    property RemoveFileOnConvert: boolean read FRemoveFileOnConvert write SetRemoveFileOnConvert;
    property Ignore_MACOSX : boolean   read FIgnore_MACOSX write SetIgnore_MACOSX;


    procedure SetExtension(const Value: String); virtual;
    function GetExtension: String;  virtual;
    function OfficeAppVersion() : String; virtual; abstract;

    //Check files and folders
    function AllowDirectory(DirName : String; FullPath : String) : Boolean;
    function AllowFile(FileName : String; Fullpath : String): Boolean;



  public

    Constructor Create();
    Destructor Destroy(); override;
    procedure LoadConfig(Params: TStrings);
    procedure ConfigLoggingLevel(Params: TStrings);

    function Execute() : string; virtual;
    function ExecuteConversion(fileToConvert: String; OutputFilename: String; OutputFileFormat : Integer): TConversionInfo; virtual; abstract;

    function DestroyOfficeApp() : boolean; virtual; abstract;
    function CreateOfficeApp() : boolean; virtual; abstract;
    function AvailableFormats() : TStringList;  virtual; abstract;
    function FormatsExtensions(): TStringList; virtual; abstract;

    procedure Log(Msg: String; Level  : Integer = ERRORS); overload;
    procedure Log(Msg: String; List:  TStrings; Level: Integer); overload;
    procedure LogError(Msg: String);
    function ConvertErrorText(Msg: String) : String;
    function CallWebHook(Params: String) : string;
    FUNCTION AfterConversion(InputFile, OutputFile: String):string;
    Function OnConversionError(InputFile, OutputFile, Error: String):string;
    procedure LogHelp(HelpResName : String);


    property OutputLog : Boolean read FOutputLog write SetOutputLog;
    property OutputLogFile : String read FOutputLogFile write SetOutputLogFile;
    Property InputFile : String read FInputFile write SetInputFile;
    Property OutputFile : String read FOutputFile write SetOutputFile;
    Property OutputFileFormat : Integer read FOutputFileFormat write SetOutputFileFormat;
    Property OutputFileFormatString : String read FOutputFileFormatString write SetOutputFileFormatString;
    Property LogToFile : Boolean read FLogToFile write SetLogToFile;
    property LogFilename: String read FLogFilename write SetLogFilename;
    Property Version : String read FVersionString;
    property HaltOnWordError : Boolean read FHaltOnWordError write SetHaltOnWordError;
    property SkipDocsWithTOC : Boolean read FSkipDocsWithTOC write SetSkipDocsWithTOC;
    property InputExtension: String read GetExtension write SetExtension;
    property CompatibilityMode : Integer read FCompatibilityMode write SetCompatibilityMode;
    property Encoding : Integer read FEncoding write SetEncoding;

  end;



  function IsNumber(Str: String) : Boolean;


implementation


{ TConsoleLog }

procedure  TConsoleLog.Log(Sender: TObject; Log: String);
begin
  Writeln(Log);
end;



function TDocumentConverter.CallWebHook(Params: String):string;
var url : string;
QuestionMarkIndex : Integer;
begin

  try
  if FWebHook > '' then
  begin
    QuestionMarkIndex := pos('?',FWebHook);
    if QuestionMarkIndex = 0  then
    begin
      url := FWebHook + '?'  + Params;
    end
    else if QuestionMarkIndex = length(FWebHook) then  //last character
    begin
      url := FWebHook + Params;
    end
    else
    begin
      url := FWebHook + '&' + Params;
    end;


    GetURL(url);

    log('Webhook Called:' + url, CHATTY);
  end;
  except on E: Exception do
  begin
    logerror(ConvertErrorText( E.ClassName) +'' + ConvertErrorText( E.Message));
  end;

  end;
end;

procedure TDocumentConverter.ConfigLoggingLevel(Params: TStrings);
var
  iParam : Integer;
  id, pstr, value : String;
begin
LogLevel := STANDARD;
iParam := 0;
lOG(ID,VERBOSE);
While iParam <= Params.Count -1 do
  begin
    pstr := Params[iParam];
    log(inttostr(iparam), VERBOSE);
    id := UpperCase( pstr);
    if ParamCount -1  > iParam then
    begin
      try
        value := Trim(Params[iParam +1]);
      except on E: Exception do
        HaltWithError(202,E.message);
      end;
    end
    else
    begin
      value := '';
    end;
    inc(iParam,2);
    lOG(ID,VERBOSE);
    if id  = '-L' then
    begin
      if isNumber(value) then
      begin
        LogLevel := strtoint(value);

      end
    end
    else if id  = '-Q' then
    begin

      OutputLog := false;
      //Doesn't require a value
      dec(iParam);
    end
  end;
  Log('Log Level Set To:' + IntToStr(FLogLevel),CHATTY);
end;


// ConvertErrorText removed a lone CR which can overwrite 1 error
// message with another if concatination see issue #37
// https://github.com/tobya/DocTo/issues/37
function TDocumentConverter.ConvertErrorText(Msg: String): String;
var
  ErrorMessage : String;
begin
  ErrorMessage := StringReplace(Msg,#13,'--',[rfReplaceAll]);
  Result :=  ErrorMessage;
end;

constructor TDocumentConverter.Create;
begin
  ConsoleLog := TConsoleLog.Create();


  //Initial values
  FOutputFileFormatString := '';
  FOutputFileFormat := -1;
  FOutputFile := '';
  FInputFile := '';
  FLogLevel := STANDARD;
  FLogtoFile := false;
  FLogFilename := 'DocTo.Log';
  FRemoveFileOnConvert := false;
  FWebHook := '';
  FOutputExt := '';
  FIsFileInput := false;
  FIsDirInput := false;
  FIsFileOutput := false;
  FIsDirOutput := false;
  FCompatibilityMode := 0;
  FEncoding := -1;
  FIgnore_MACOSX := true;
  fSkipDocsWithTOC := false;
  FFirstLogEntry := true;

  FInputFiles := TStringList.Create;
end;

destructor TDocumentConverter.Destroy;
begin
  ConsoleLog.Free;
  if assigned(FLogFile) then
  begin
    FLogFile.SaveToFile(FLogFilename);
    FLogFile.Free;
    FLogFile := nil;
  end;

  FInputFiles.Free;
end;


(*
  Execute conversion on 1 or more files.
*)
function TDocumentConverter.Execute: string;
var

  Continue : Boolean;
  i :