// 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("@fuxinsoft/foxit-pdf-sdk-node");
const fs = require('fs');
const os = require('os');
const path = require('path');
const util = require('util');

var sn = "Rew1vB0TqoMIxX444UcpScARWdhgJpsJfzmyMLR32a0+EgrCjp2NaQ==";
var key = "8f3g1sFttW8NAgfSNv+BvaJWy4Pp8flcm7ncNDkdvCCO4JwUFbGLyZdujReMaiplbYJwwxam3lr7uHtQaEf0xTSu8j2ZBdrZ8FS4OQkEUjOI9UEGb3Ic0GqmlP9T9OnSItOYqoZZA/OnYg5EaVP+c/ha32nUquOk+5riEdhYgINAZDdgJkPc+YSWsrfixOIROf6t34j3eRcyFnOY0MS7tSXi1AEPE0VZdyu+5bfmBSGvLI+WR5lQ+oOQR5hRGwqf990WEdBelNO7dxhZELVhEZ+/L60PpDf5y9A8qmrY6PiEU8nhqIyLpks0BxeIsYyZ3Cr82jjfbItPGyEARsIVzluBSgVMD4oGjojz8T6wGDEXUbmZH/pra94XAs8wZ28mzbmIEppWnhBqX0c6Ov8iXCfFfUZr4KNuPxMEgk4VOYTMOd70GEjGnylivw18hbn7ZpkWh2Zql+uU2HejvOgn+WHvT0HF9NhK0Xb5vH8aFkgBP92PJx8obIbxBVeeExczxvsqWufuPdXS2sPNIgMYZ2TtvqVVsiUToeGB2FQo09fzZOSH5Vi18u/siyvC3FmjeMf4+OYWPuDPNCcrb21NgcHam7XI8AAoGLTGtLLWR+fxynbBBcg2d2ZPcZ5CMFIfOBHRWCkcA0sDT3cl9nsBppHNJze/jVxHy+lREeQEA/etSIgohTGAWW3ZlpibRXqMxlmVWEPifCubbWTzQ6U54mRMpW2UghH3gvCNFNgdday3Av7EtlIJOdUuiMq3zmmd5J4Jt4C82CKnVewA0DtZ4EEtwRG9IYuLrfpuZlnjBAtoeXRV1lqUZ6BcCe0E3m9jO28sGkALuIeJQ74XG7X8lMC7lMWWQYiYD7D6G9QT6X3qV4vXJwNKRKpYc/rI+amEawTSnDYAMEaYPwtZ0rb/7BL+atsZZaI+ncebdfVfjDJZbCZAc+JnkuNlUn2xrNRuObw8h/G0lm2pNOEJ10S8R4+yplo5B1QmC2dCDhaTaW67QJPqnJPKbVmjw7i6KGBi+CDP3JnAKlOX/YUu8uk56JfeQUuGcQg/KaBMGctnchH2n1i3+oGbibhurQj22+OO66Q6mijKoCRP/QJm5WTGcO4c0iVX0B8dIlai/uv/pGU8Wps9MxysH5ViVIj56LWKuNfy1FNO9+wx4iHYnUxfW0Iccq3YJYAlOBkMv8VZIJl9aTEEFJ626LJEw/UbEBdR9CdlwnylPf4RuNW/lcGYMgq3xNVpp/bzYKwZivvQOFgMdX1tv8D33SHvAm3zrRCU+v94BJXnBi9k25fnKsc705IMwv+I6bueXA+mDnagj1oTqsWXZ0WnPAYI3WUO7sBf7XUH230wfYXnTSVhujJxiEP/2oWqi2813gtQkKwz9N2p6yT8Vsh3+BaAwwDvtOZMJKUFcabTBSL6NoouzmzwItJ4mIboT6KXaef66rs8jCU=";

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();