// 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 mark PDF content and
// get marked content from graphics objects.

// Include Foxit SDK header files.
#include <time.h>
#include<stdarg.h>
#include<direct.h>
#include <stdio.h>

#include "../../../include/fs_basictypes_c.h"
#include "../../../include/fs_common_c.h"
#include "../../../include/fs_pdfdoc_c.h"
#include "../../../include/fs_pdfpage_c.h"
#include "../../../include/fs_image_c.h"
#include "../../../include/fs_pdfgraphicsobject_c.h"
#include "../../../include/fs_pdfobject_c.h"

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

#ifndef NULL
#define NULL (void*)0
#endif

#define MAX_FILE_PATH 260

static const char* sn = "bPxThFlBAYifO3yiW0C51bKbjPap1zHaf5aG5sX378TjFvB7Q0802A==";
static const char* 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";

static const wchar_t* output_path = L"../output_files/";
static const wchar_t* input_path = L"../input_files/";

wchar_t output_directory[MAX_FILE_PATH];

void WriteByteString(FILE* file, const char* format, ...) {
  va_list vars;
  if (file) {
    // Get variable list
    va_start(vars, format);
    // Call vfprintf to format log data and output to log file
    vfprintf(file, format, vars);
    // End variable list
    va_end(vars);
  }
}

void CreateMarkedContent(FS_PDFPAGE_HANDLE page) {
  FS_POSITION position;
  FS_TEXTOBJECT_HANDLE text_object = NULL;
  FSTextState state;
  FSRectF rect;
  float width, height;
  float offset_x, offset_y;
  FSMatrix matrix;
  FS_BOOL return_result;
  FS_MARKEDCONTENT_HANDLE content = NULL;
  FS_PDFDICTIONARY_HANDLE span_dict = NULL;
  int value;
  FS_BOOL return_value;

  FSDK_GraphicsObjects_GetLastGraphicsObjectPosition(page, e_FSTypeText, &position);

  FSDK_TextObject_Create(&text_object);

  FSDK_GraphicsObject_SetFillColor(text_object, 0xFF83AF9B);

  // Prepare text state
  state.font_size = 72.f;
  FSDK_Font_Create0(e_FSStdIDTimesB, &state.font);
  state.textmode = e_FSModeFill;
  state.origin_position.x = 0;
  state.origin_position.y = 0;
  state.wordspace = 0.0f;
  state.charspace = 0.0f;
  state.textmatrix[0] = 1;
  state.textmatrix[1] = 0;
  state.textmatrix[2] = 0;
  state.textmatrix[3] = 1;
  state.version = 1;

  FSDK_TextObject_SetTextState(text_object, page, state, FALSE, 750);

  FSDK_TextObject_SetText(text_object, L"Marked-Content");
  FSDK_GraphicsObjects_InsertGraphicsObject(page, position, text_object, &position);

  FSDK_GraphicsObject_GetRect(text_object, &rect);

  FSDK_PDFPage_GetWidth(page, &width);
  offset_x = (width - (rect.right - rect.left)) / 2;
  FSDK_PDFPage_GetHeight(page, &height);
  offset_y = height * 0.618f - (rect.top - rect.bottom) / 2;

  matrix.a = 1;
  matrix.b = 0;
  matrix.c = 0;
  matrix.d = 1;
  matrix.e = offset_x;
  matrix.f = offset_y;

  FSDK_GraphicsObject_Transform(text_object, matrix, FALSE, &return_result);

  FSDK_GraphicsObject_GetMarkedContent(text_object, &content);

  FSDK_PDFDictionary_Create(&span_dict);
  FSDK_PDFDictionary_SetAtInteger(span_dict, "Direct", 55);

  FSDK_MarkedContent_AddItem(content, "Span", span_dict, &value);
  FSDK_PDFObject_Release(span_dict);
  // Generate content
  FSDK_GraphicsObjects_GenerateContent(page, &return_value);
}

FS_BOOL GetMarkedContentObject(const wchar_t* pdf_file) {
  FS_PDFDOC_HANDLE doc = NULL;
  FSErrorCode ret = e_FSErrSuccess;
  FS_PDFPAGE_HANDLE page = NULL;
  FS_PROGRESSIVE_HANDLE progressive = NULL;
  FS_POSITION position;
  FS_TEXTOBJECT_HANDLE text_obj = NULL;
  FS_MARKEDCONTENT_HANDLE content = NULL;
  int item_count, i = 0;
  wchar_t file_info[MAX_FILE_PATH];
  FILE* file = NULL;

  FSDK_PDFDoc_Create0(pdf_file, &doc);
  ret = FSDK_PDFDoc_Load(doc, NULL);
  if (ret != e_FSErrSuccess) {
    wprintf(L"[Failed] Cannot load PDF document %ls.\r\n Error message:%d\r\n", pdf_file, ret);
    return FALSE;
  }

  FSDK_PDFDoc_GetPage(doc, 0, &page);

  FSDK_PDFPage_StartParse(page, e_FSParseFlagsParsePageNormal, NULL, FALSE, &progressive);

  FSDK_GraphicsObjects_GetFirstGraphicsObjectPosition(page, e_FSTypeText, &position);

  FSDK_GraphicsObjects_GetGraphicsObject(page, position, &text_obj);

  FSDK_GraphicsObject_GetMarkedContent(text_obj, &content);
  FSDK_MarkedContent_GetItemCount(content, &item_count);

  swprintf_s(file_info, MAX_FILE_PATH, L"%lsmarkedcontent.txt", output_directory);

  _wfopen_s(&file, file_info, L"w+b");

  // Get marked content property
  for (i = 0; i < item_count; i++) {
    FS_BSTR tag_name;
    int mcid;
    WriteByteString(file, "index: %d\r\n", i);
    FSDK_BStr_Init(&tag_name);
    FSDK_MarkedContent_GetItemTagName(content, i, &tag_name);
    WriteByteString(file, "Tag name: %s\r\n", (const char*)tag_name.str);

    FSDK_MarkedContent_GetItemMCID(content, i, &mcid);
    WriteByteString(file, "mcid: %d\r\n", mcid);
    FSDK_BStr_Clear(&tag_name);
  }
  return TRUE;
}

int main(int argc, char *argv[]) {
  FSErrorCode error_code = e_FSErrSuccess;
  swprintf_s(output_directory, MAX_FILE_PATH, L"%lsmarked_content/", output_path);
  _wmkdir(output_directory);

  error_code = FSDK_Library_Initialize(sn, key);
  if (error_code != e_FSErrSuccess) {
    printf("Library Initialize Error: %d\n", error_code);
    return 1;
  }

  {
    FS_PDFDOC_HANDLE doc = NULL;
    FS_PDFPAGE_HANDLE page = NULL;
    wchar_t output_file[MAX_FILE_PATH];
    FS_BOOL is_save;

    FSDK_PDFDoc_Create(&doc);

    FSDK_PDFDoc_InsertPage0(doc, 0, e_FSSizeLetter, &page);

    CreateMarkedContent(page);

    swprintf_s(output_file, MAX_FILE_PATH, L"%lsmarked_content.pdf", output_directory);
    FSDK_PDFDoc_SaveAs(doc, output_file, e_FSSaveFlagsSaveFlagNormal, &is_save);

    if (!GetMarkedContentObject(output_file)) {
      return 1;
    }

    FSDK_PDFPage_Release(page);
    FSDK_PDFDoc_Release(doc);
    printf("Add marked content to PDF file.\n");
  }

  FSDK_Library_Release();
  printf("marked content demo done.\n");
  return 0;
}
