// Copyright (C) 2003-2026, Foxit Software Inc..
// All Rights Reserved.
//
// http://www.foxitsoftware.com
//
// The following code is copyrighted and contains proprietary information and trade secrets of Foxit Software Inc..
// You cannot distribute any part of Foxit PDF SDK to any third party or general public,
// unless there is a separate license agreement with Foxit Software Inc. which explicitly grants you such rights.
//
// This file contains an example to demonstrate how to use Foxit PDF SDK to do PDF page organization,
// such as inserting, removing, and so on.


const FSDK = require("@foxitsoftware/foxit-pdf-sdk-node");
const fs = require('fs');
const os = require('os');
const path = require('path');
const util = require('util');

var sn = "bPxThFlBAYifO3yiW0C51bKbjPap1zHaf5aG5sX378TjFvB7Q0802A==";
var key = "8f3g1sGNtR8NAgfSNv+BvaJWy2fnrw36NZvzh8GUxYXvs+/YczAk4e34yqlOnmL4asgxGMO7+rlOcSHUSSKagx5g4G7VEXfkYLXnDDx77FOOedZPrFFcOCu1vT4+wOKzy1zkORq9cKtiFf44byH5sfRqf+OvELjep2teT9eF9yPCsSw2vRKljXlPy40DMP9XX1O5OTe+mSG3RvwKUMb0+RpG3YobM87j+/ynTDlJMMXw4vgwuTb1ZuAtlvkTdFz7HDLV81C6TYnn73ddHeGD3qYWBVsD4uJkDwyyH/SWr7QX0HSgVg8HSZqnab1VGdAUYxKY2vGWeOTJdu6qDGb5ZEb9O3kZZg+9LYAmUKzDfCYwfIsYZ8Y9LPC4wMx70kIq7JpNnzPvigrdshV8/ew1F0+qP/P5Z1EB53vDVrp2LVSuL873Wv4g3PzjZlNH+1qgT87hC+Buto4qsSUfP5Y2z0uApu+c/TfttCXbeMLSsw9TY1HQD3mkrZExMaQqRrAuXAcZWdvBnVuG3DCZmm8q0DLxJiCfYfViAU/AkbeKMIGaTJdrvIXBcssfde4nmU6qr0M4x4+Hs2ESddtY2QRtLAUBq/7h7GJlJHkEZr8ueaUy/6D/2vvAWz6wMLgmjlPbDTLqzfnCJylHCPtcJmu1SPPT9v1VreBX3+zNWcIT8HueyHEiUniqzwWkRKaotrnNb/zhnHLPpgaBSwKjyi8rOzzVwu/nY84G9ye4jsVjmkIRItKDrW7z22iS+QQuTwfqLVuMB0OD4jMkPCC2slzPfEeZnuh4+Rewln2qLRJVgI72zJ20OBWAelGSpO1Ii2Y3gOvojdmtUwx6R3Z1qFNWTTB25o9ytcux8BLOtTCkA8T8xaT4N339OTCsu/TmfahIDixKvr8cDa6F2WkBT8SOfv64W9PgiNv5B/BMOD2VWYaAl0N7yD0NkYYg/cDWRC4dfpdeip1jrr0k3mND0oSpIkxC+FicZbaYYwRdtJ9OSVWJ5OE0voLv8HgLze8mw6s4TrN3z+a2NQCveMa2VRN7YcEF7agPrvb/qU+otMwHae/wM7+f+HFAaOW+WTfzfxIVFB8/A1DN0NiEX+em4G7nO5F5ZcvfYPpaaioe8Nn33BbVLtMjXqsOBeM8AXiVfpD6YO75j7BqnBUPnivvD8BxJaaIQZvVSuQmvGm0ynt03IYwE8Rq+jYsunvsZ86jh5BiUR+Nm7sK0Qe9BdZn/7jdqohMv9czfMGUAscX+xBMunFbDpcRbWVpUADcm209L8Ndek2XY7YlCMxPgPVNvfWRF2jxehib9Tpd7zB5ZIDfAEH9zrpLfp29DLvCh2Yx8mH7xxdKG1O9Q0GdHphYHhej6smAcPm68R0GUQaTOLfXqNpueGJC1GAOI3Y4swjyt7jMTWcibnKLzwukWE5rnEDhn5n64JnyUM0ZFkRmtOiV";

const input_path = "../input_files/";
const output_path = "../output_files/";

function AddTextObjects(page, content) {
  let position = page.GetLastGraphicsObjectPosition(FSDK.GraphicsObject.e_TypeText);
  let text_object = FSDK.TextObject.Create();

  text_object.SetFillColor(0xFFAAAAAA);
  text_object.SetStrokeColor(0xFFF68C21);

  // Prepare text state
  let state = new FSDK.TextState;
  state.font_size = 64.0;
  state.font = new FSDK.Font(FSDK.Font.e_StdIDTimes);
  state.textmode = FSDK.TextState.e_ModeFillStrokeClip;

  text_object.SetTextState(page, state, false, 750);

  // Set content
  text_object.SetText(content);
  page.InsertGraphicsObject(position, text_object);

  // Transform to center
  let rect = text_object.GetRect();
  let offset_x = (page.GetWidth() - (rect.right - rect.left)) / 2;
  let offset_y = (page.GetHeight() - (rect.top - rect.bottom)) / 2;
  text_object.Transform(new FSDK.Matrix2D(1, 0, 0, 1, offset_x, offset_y), false);

  // Generator content
  page.GenerateContent();
}

function InsertPage() {
  let input_file = input_path + "page_organization_123.pdf";
  let doc = new FSDK.PDFDoc(input_file);
  let code = doc.Load("");
  if (code != FSDK.e_ErrSuccess) {
    console.log("The Doc [%s] Error: %d\n", input_file, code);
    return false;
  }

  let page = doc.InsertPage(-1, FSDK.PDFPage.e_SizeLetter);
  AddTextObjects(page, "insert in first");
  page = doc.InsertPage(2, FSDK.PDFPage.e_SizeLetter);
  AddTextObjects(page, "insert in 2 (based 0)");
  page = doc.InsertPage(doc.GetPageCount(), FSDK.PDFPage.e_SizeLetter);
  AddTextObjects(page, "insert in last");
  let output_file = output_directory + "insert_page.pdf";
  doc.SaveAs(output_file, FSDK.PDFDoc.e_SaveFlagNormal);
  console.log("Insert pages.");
  return true;
}

function RemovePage() {
  let input_file = input_path + "page_organization_123.pdf";
  let doc = new FSDK.PDFDoc(input_file);
  let code = doc.Load("");
  if (code != FSDK.e_ErrSuccess) {
    console.log("The Doc [%s] Error: %d\n", input_file, code);
    return false;
  }

  while (doc.GetPageCount() > 1) {
    doc.RemovePage(0);
  }
  let output_file = output_directory + "remove_all_pages_exceptt_the_last_page.pdf";
  doc.SaveAs(output_file,  FSDK.PDFDoc.e_SaveFlagNormal);
  console.log("Remove pages.");
  return true;
}

// You can implement the functionality of exporting pages by creating an empty document
// and importing part of the source document into the empty document.
// You can also import the target document as a source document
// to implement the copy page functionality.
function ImportPage() {
  let file_dest = input_path + "page_organization_123.pdf";
  let file_src = input_path + "page_organization_abc.pdf";
  let doc_dest = new FSDK.PDFDoc(file_dest);
  let code = doc_dest.Load("");
  if (code != FSDK.e_ErrSuccess) {
    console.log("The Doc [%s] Error: %d\n", file_dest, code);
    return false;
  }
  let doc_src = new FSDK.PDFDoc(file_src);
  code = doc_src.Load("");
  if (code != FSDK.e_ErrSuccess) {
    console.log("The Doc [%s] Error: %d\n", file_src, code);
    return false;
  }
  // Import page from PDFDoc object.
  let import_ranges = new FSDK.Range(0);
  import_ranges.AddSingle(doc_src.GetPageCount()-1);
  let progressive =
    doc_dest.StartImportPages(-1,  doc_src, FSDK.PDFDoc.e_ImportFlagNormal, "abc", import_ranges, null);
  while (progressive.Continue() != FSDK.Progressive.e_Finished) {
  }
  let output_file = output_directory + "page_organization_abc_to_123_import_pages.pdf";
  doc_dest.SaveAs(output_file, FSDK.PDFDoc.e_SaveFlagNormal);

  doc_dest = new FSDK.PDFDoc(file_dest);
  code = doc_dest.Load("");
  if (code != FSDK.e_ErrSuccess) {
    console.log("The Doc [%s] Error: %d\n", file_dest, code);
    return false;
  }
  // Import page from file path.
  progressive = doc_dest.StartImportPagesFromFilePath(-1, file_src, "", FSDK.PDFDoc.e_ImportFlagNormal, "abc",
    import_ranges, null);
  while (progressive.Continue() != FSDK.Progressive.e_Finished) {
  }
  output_file = output_directory + "abc_to_123_import_pages_form_filepath.pdf";
  doc_dest.SaveAs(output_file, FSDK.PDFDoc.e_SaveFlagNormal);
  console.log("Import pages.");
  return true;
}

// This example shows how to use the use the functions StartExtractPages and InsertDocument together,
// instead of the StartImportPagesFromFilePath function. The execution efficiency of importing pages has
// been optimized in these new functions.
function ImportPageOptimized() {
  let file_dest = input_path + "page_organization_123.pdf";
  let file_src = input_path + "page_organization_abc.pdf";
  let doc_dest = new FSDK.PDFDoc(file_dest);
  let code = doc_dest.Load("");
  if (code != FSDK.e_ErrSuccess) {
    console.log("The Doc [%s] Error: %d\n", file_dest, code);
    return false;
  }
  let doc_src = new FSDK.PDFDoc(file_src);
  code = doc_src.Load("");
  if (code != FSDK.e_ErrSuccess) {
    console.log("The Doc [%s] Error: %d\n", file_src, code);
    return false;
  }
  // Extract pages to temporary document
  let import_ranges = new FSDK.Range(0);
  import_ranges.AddSingle(doc_src.GetPageCount() - 1);
  let file_temp = output_directory + "page_organization_import_extracted_pages.pdf";
  let progressive =
    doc_src.StartExtractPages(file_temp, FSDK.PDFDoc.e_ExtractPagesOptionAnnotation, import_ranges, null);
  while (progressive.Continue() != FSDK.Progressive.e_Finished) {
  }

  let doc_temp = new FSDK.PDFDoc(file_temp);
  code = doc_temp.Load("");
  if (code != FSDK.e_ErrSuccess) {
    console.log("The Doc [%s] Error: %d\n", file_temp, code);
    return false;
  }

  // Insert temporary document into destination
  doc_dest.InsertDocument(-1, doc_temp, FSDK.PDFDoc.e_InsertDocOptionAttachments);
  let output_file = output_directory + "abc_to_123_insert_document.pdf";
  doc_dest.SaveAs(output_file, FSDK.PDFDoc.e_SaveFlagNormal);
  console.log("Import pages optimized.");
  return true;
}

function MovePages()
{
  let input_file = input_path + "page_organization_123.pdf";
  let input_file1 = input_path + "page_organization_abc.pdf";
  // Move page
  let doc = new FSDK.PDFDoc(input_file);
  let code = doc.Load("");
  if (code != FSDK.e_ErrSuccess) {
    console.log("The Doc [%s] Error: %d\n", input_file, code);
    return false;
  }
  let count = doc.GetPageCount();
  let page = doc.GetPage(0);
  doc.MovePageTo(page, doc.GetPageCount() - 1);
  let output_file1 = output_directory + "move_first_page_to_last.pdf";
  doc.SaveAs(output_file1, FSDK.PDFDoc.e_SaveFlagNormal);

  doc = new FSDK.PDFDoc(input_file1);
  code = doc.Load("");
  if (code != FSDK.e_ErrSuccess) {
    return false;
  }
  let page_set = new FSDK.Range;
  for (let i = 0; i < count / 2; i++)
    page_set.AddSingle(2 * i);
  doc.MovePagesTo(page_set, doc.GetPageCount() - 1);
  let output_file = output_directory + "move_pages.pdf";
  doc.SaveAs(output_file, FSDK.PDFDoc.e_SaveFlagNormal);
  console.log("Move pages.");
  return true;
}

let error_code = FSDK.Library.Initialize(sn, key);
if (FSDK.e_ErrSuccess != error_code) {
  if (FSDK.e_ErrInvalidLicense == error_code)
    console.log("[Failed] Current used Foxit PDF SDK key information is invalid.");
  else
    console.log("Library Initialize Error: %d", FSDK.e_ErrSuccess);
  return;
}

let output_directory = output_path + "page_organization/";
if (!fs.existsSync(output_directory))  {
  fs.mkdirSync(output_directory);
}

try {
  if (!(InsertPage() && RemovePage() && ImportPage() && ImportPageOptimized() && MovePages())) {
    return 1;
  }

} catch (e) {
  console.log(e);
}
FSDK.Library.Release();