unit MainForm;

{$I ..\..\..\Lib\PDFlibDefines.inc}

interface

uses
{$IFDEF XE2+}
  Winapi.Windows,
  Winapi.Messages,
  System.SysUtils,
  System.Classes,
  Vcl.Graphics,
  Vcl.Controls,
  Vcl.Forms,
  Vcl.Dialogs,
  Vcl.StdCtrls,
  Vcl.ComCtrls,
{$ELSE}
  Windows,
  Messages,
  SysUtils,
  Classes,
  Graphics,
  Controls,
  Forms,
  Dialogs,
  StdCtrls,
  ComCtrls,
{$ENDIF}
  PDFlibrary;

type
  TForm1 = class(TForm)
    GroupBox1: TGroupBox;
    btnRemoveLastPage: TButton;
    btnAppendPDF: TButton;
    lblStatus: TLabel;
    OpenDialog1: TOpenDialog;
    lblPageToDelete: TLabel;
    edtPageToDelete: TEdit;
    udPageToDelete: TUpDown;
    btnDeleteSpecificPage: TButton;
    procedure FormCreate(Sender: TObject);
    procedure btnRemoveLastPageClick(Sender: TObject);
    procedure btnAppendPDFClick(Sender: TObject);
    procedure btnDeleteSpecificPageClick(Sender: TObject);
  private
    { Private declarations }
    procedure ShowStatus(const Msg: string);
    function GetErrorDescription(Code: Integer): string;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  OpenDialog1.Filter := 'PDF Files (*.pdf)|*.pdf';
  ShowStatus('Ready');
end;

procedure TForm1.ShowStatus(const Msg: string);
begin
  lblStatus.Caption := Msg;
  lblStatus.Update;
  Application.ProcessMessages;
  lblStatus.Refresh;
  Refresh;
end;

function TForm1.GetErrorDescription(Code: Integer): string;
begin
  case Code of
    0:
      Result := 'No error';
    101:
      Result := 'Font error';
    102, 103, 104:
      Result := 'Image error';
    301, 302, 303:
      Result := 'Page operation error';
    401:
      Result := 'File access error';
    402:
      Result := 'Cannot delete existing file';
    403:
      Result := 'Cannot create or write file';
    404:
      Result := 'Password error';
    405:
      Result := 'Invalid page range';
    406:
      Result := 'Format error';
    407:
      Result := 'Out of memory';
    408:
      Result := 'Incomplete file';
    409:
      Result := 'Not a valid PDF file';
    411, 412:
      Result := 'Page structure error';
    501:
      Result := 'Invalid file handle';
    601:
      Result := 'Cannot process document with different page sizes';
  else
    Result := Format('Unknown error (%d)', [Code]);
  end;
end;

procedure TForm1.btnRemoveLastPageClick(Sender: TObject);
var
  PDFLib: TPDFLib;
  PageCount: Integer;
  SourceFileName, OutputFileName: string;
  ErrorCode: Integer;
  ErrorMsg: string;
  OperationSuccess: Boolean;
begin
  PageCount := 0;
  OperationSuccess := False;
  Screen.Cursor := crHourGlass;
  try
    if not OpenDialog1.Execute then
    begin
      ShowStatus('Operation cancelled');
      Exit;
    end;

    SourceFileName := OpenDialog1.FileName;
    OutputFileName := ChangeFileExt(ExtractFileName(OpenDialog1.FileName), '') + '-LastPageRemoved.pdf';

    ShowStatus('Processing...');
    Sleep(200);

    PDFLib := TPDFLib.Create;
    try
      // Open source PDF file
      ShowStatus('Opening PDF file...');
      Sleep(100);

      if PDFLib.LoadFromFile(SourceFileName, '') <> 1 then
      begin
        ErrorCode := PDFLib.LastErrorCode;
        ErrorMsg := GetErrorDescription(ErrorCode);
        ShowStatus(Format('Error: Cannot open PDF file. Error code: %d (%s)', [ErrorCode, ErrorMsg]));
        Exit;
      end;

      // Get total page count
      PageCount := PDFLib.PageCount;

      if PageCount <= 1 then
      begin
        ShowStatus('Error: PDF file has only one page or no pages, cannot delete');
        Exit;
      end;

      // Delete last page
      try
        ShowStatus(Format('Deleting page %d of %d...', [PageCount, PageCount]));
        Sleep(100);

        // Delete the last page - The key issue here is PageCount as index, but we need to verify the return value
        // DeletePages returns the page count after operation, which should be PageCount-1 if successful
        if PDFLib.DeletePages(PageCount, 1) <> PageCount - 1 then
        begin
          ErrorCode := PDFLib.LastErrorCode;
          ErrorMsg := GetErrorDescription(ErrorCode);

          // Log detailed error information to debug output
          OutputDebugString(PChar(Format('DeletePages failed. File: %s, Page count: %d, Error code: %d (%s)', [SourceFileName, PageCount, ErrorCode,
            ErrorMsg])));

          // Special handling for different page sizes error (code 601)
          if ErrorCode = 601 then
            ShowStatus('Error: Document contains pages with different sizes, cannot complete delete operation')
          else
            ShowStatus(Format('Error: Cannot delete the last page. Error code: %d (%s)', [ErrorCode, ErrorMsg]));

          Exit;
        end;

        // Save the result
        ShowStatus('Saving file...');
        Sleep(100);

        // Check if the page was actually deleted before saving
        if PDFLib.PageCount <> PageCount - 1 then
        begin
          ShowStatus(Format('Error: Page deletion verification failed. Current page count: %d, Expected: %d', [PDFLib.PageCount, PageCount - 1]));
          Exit;
        end;

        if PDFLib.SaveToFile(OutputFileName) <> 1 then
        begin
          ErrorCode := PDFLib.LastErrorCode;
          ErrorMsg := GetErrorDescription(ErrorCode);
          ShowStatus(Format('Error: Cannot save file. Error code: %d (%s)', [ErrorCode, ErrorMsg]));
          Exit;
        end;

        OperationSuccess := True;
        ShowStatus(Format('Success: Last page deleted and saved to %s', [OutputFileName]));

      except
        on E: Exception do
        begin
          ShowStatus(Format('Exception occurred: %s', [E.Message]));
          Exit;
        end;
      end;
    finally
      PDFLib.Free;

      // Final status update if needed
      if not OperationSuccess then
      begin
        if (lblStatus.Caption = 'Processing...') or (lblStatus.Caption = 'Opening PDF file...') or
          ((PageCount > 0) and (lblStatus.Caption = 'Deleting page ' + IntToStr(PageCount) + ' of ' + IntToStr(PageCount) + '...')) or
          (lblStatus.Caption = 'Saving file...') then
        begin
          ShowStatus('Operation failed. Please try another file.');
          MessageBox(Handle, 'Operation failed to complete. The status indicator may not show the correct status.', 'Status Update Issue', MB_ICONINFORMATION);
        end;
      end;
    end;
  finally
    Screen.Cursor := crDefault;
  end;
end;

procedure TForm1.btnAppendPDFClick(Sender: TObject);
var
  PDFLib: TPDFLib;
  TargetFileName, SourceFileName, OutputFileName: string;
  ErrorCode: Integer;
  ErrorMsg: string;
begin
  // Select target PDF file (append to the end of this file)
  ShowStatus('Please select the first PDF file (target file)');
  OpenDialog1.Title := 'Select first (target) PDF File';
  if not OpenDialog1.Execute then
  begin
    ShowStatus('Operation cancelled');
    Exit;
  end;

  TargetFileName := OpenDialog1.FileName;

  // Select source PDF file (file to be appended)
  ShowStatus('Please select the second PDF file (file to append)');
  OpenDialog1.Title := 'Select PDF File to Append';
  if not OpenDialog1.Execute then
  begin
    ShowStatus('Operation cancelled');
    Exit;
  end;

  SourceFileName := OpenDialog1.FileName;

  // Save output file
  OutputFileName := '.\PageMerged.pdf';

  ShowStatus('Merging files...');

  PDFLib := TPDFLib.Create;
  try
    // Merge the files
    if PDFLib.MergeFiles(TargetFileName, SourceFileName, OutputFileName) <> 1 then
    begin
      ErrorCode := PDFLib.LastErrorCode;
      ErrorMsg := GetErrorDescription(ErrorCode);
      ShowStatus(Format('Error: Cannot merge the files. Error code: %d (%s)', [ErrorCode, ErrorMsg]));
      Exit;
    end;

    ShowStatus(Format('Success: Files merged and saved to %s', [OutputFileName]));
  finally
    PDFLib.Free;
  end;
end;

procedure TForm1.btnDeleteSpecificPageClick(Sender: TObject);
var
  PDFLib: TPDFLib;
  PageCount: Integer;
  PageToDelete: Integer;
  SourceFileName, OutputFileName: string;
  ErrorCode: Integer;
  ErrorMsg: string;
  OperationSuccess: Boolean;
begin
  PageCount := 0;
  OperationSuccess := False;
  Screen.Cursor := crHourGlass;
  try
    // Get page number to delete
    PageToDelete := udPageToDelete.Position;

    if not OpenDialog1.Execute then
    begin
      ShowStatus('Operation cancelled');
      Exit;
    end;

    SourceFileName := OpenDialog1.FileName;
    OutputFileName := ChangeFileExt(ExtractFileName(OpenDialog1.FileName), '') + '-Page' + IntToStr(PageToDelete) + 'Removed.pdf';

    ShowStatus('Processing...');
    Sleep(200);

    PDFLib := TPDFLib.Create;
    try
      // Open source PDF file
      ShowStatus('Opening PDF file...');
      Sleep(100);

      if PDFLib.LoadFromFile(SourceFileName, '') <> 1 then
      begin
        ErrorCode := PDFLib.LastErrorCode;
        ErrorMsg := GetErrorDescription(ErrorCode);
        ShowStatus(Format('Error: Cannot open PDF file. Error code: %d (%s)', [ErrorCode, ErrorMsg]));
        Exit;
      end;

      // Get total page count
      PageCount := PDFLib.PageCount;

      // Validate page to delete
      if PageToDelete > PageCount then
      begin
        ShowStatus(Format('Error: Invalid page number. The document only has %d pages.', [PageCount]));
        Exit;
      end;

      if PageCount <= 1 then
      begin
        ShowStatus('Error: PDF file has only one page or no pages, cannot delete');
        Exit;
      end;

      // Delete specified page
      try
        ShowStatus(Format('Deleting page %d of %d...', [PageToDelete, PageCount]));
        Sleep(100);

        // Delete the specified page
        if PDFLib.DeletePages(PageToDelete, 1) <> PageCount - 1 then
        begin
          ErrorCode := PDFLib.LastErrorCode;
          ErrorMsg := GetErrorDescription(ErrorCode);

          // Log detailed error information
          OutputDebugString(PChar(Format('DeletePages failed. File: %s, Page: %d, Total pages: %d, Error code: %d (%s)', [SourceFileName, PageToDelete,
            PageCount, ErrorCode, ErrorMsg])));

          // Special handling for different page sizes error
          if ErrorCode = 601 then
            ShowStatus('Error: Document contains pages with different sizes, cannot complete delete operation')
          else
            ShowStatus(Format('Error: Cannot delete page %d. Error code: %d (%s)', [PageToDelete, ErrorCode, ErrorMsg]));

          Exit;
        end;

        // Save the result
        ShowStatus('Saving file...');
        Sleep(100);

        // Check if the page was actually deleted before saving
        if PDFLib.PageCount <> PageCount - 1 then
        begin
          ShowStatus(Format('Error: Page deletion verification failed. Current page count: %d, Expected: %d', [PDFLib.PageCount, PageCount - 1]));
          Exit;
        end;

        if PDFLib.SaveToFile(OutputFileName) <> 1 then
        begin
          ErrorCode := PDFLib.LastErrorCode;
          ErrorMsg := GetErrorDescription(ErrorCode);
          ShowStatus(Format('Error: Cannot save file. Error code: %d (%s)', [ErrorCode, ErrorMsg]));
          Exit;
        end;

        OperationSuccess := True;
        ShowStatus(Format('Success: Page %d deleted and saved to %s', [PageToDelete, OutputFileName]));

      except
        on E: Exception do
        begin
          ShowStatus(Format('Exception occurred: %s', [E.Message]));
          Exit;
        end;
      end;
    finally
      PDFLib.Free;

      // Final status update if needed
      if not OperationSuccess then
      begin
        if (lblStatus.Caption = 'Processing...') or (lblStatus.Caption = 'Opening PDF file...') or
          (lblStatus.Caption = Format('Deleting page %d of %d...', [PageToDelete, PageCount])) or (lblStatus.Caption = 'Saving file...') then
        begin
          ShowStatus('Operation failed. Please try another file.');
          MessageBox(Handle, 'Operation failed to complete. The status indicator may not show the correct status.', 'Status Update Issue', MB_ICONINFORMATION);
        end;
      end;
    end;
  finally
    Screen.Cursor := crDefault;
  end;
end;

end.
