// 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 get/set attributes of viewer preference
// and values of metadata in a PDF file.

#include "FSPDFObjC.h"

NSString *input_path = @"../input_files/";
NSString *output_path = @"../output_files/";
NSString *content = @"";

NSString *sn = @"bPxThFlBAYifO3yiW0C51bKbjPap1zHaf5aG5sX378TjFvB7Q0802A==";
NSString *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";

NSString *output_directory = @"../output_files/docinfo/";

// The results are displayed in the terminal.
void textOutput(NSString *str) {
    content = [[NSString alloc] initWithFormat:@"%@%@", content, str];
}

FSDateTime *GetLocalDateTime() {
    time_t t = time(NULL);
    struct tm *rime = localtime(&t);
    tzset();
    int timezone_hour = (int) timezone / 3600 * -1;
    int timezone_minute = (abs((int) timezone) % 3600) / 60;

    FSDateTime *datetime = [[FSDateTime alloc] initWithYear:(rime->tm_year + 1900) month:(rime->tm_mon + 1) day:(rime->tm_mday) hour:(rime->tm_hour) minute:(rime->tm_min) second:(rime->tm_sec) milliseconds:0 utc_hour_offset:timezone_hour utc_minute_offset:timezone_minute];

    return datetime;
}

NSString *DateTimeToString(const FSDateTime *datetime) {
    NSString *s_datetime = [[NSString alloc] initWithFormat:@"%d/%d/%d-%d:%d:%d %@%d:%d", datetime.year, datetime.month, datetime.day, datetime.hour, datetime.minute, datetime.second, datetime.utc_hour_offset > 0 ? @"+" : @"-", datetime.utc_hour_offset, datetime.utc_minute_offset];
    return s_datetime;
}

FSDocViewerPrefsViewerPref kUIItems[6] = {FSDocViewerPrefsHideToolbar, FSDocViewerPrefsHideMenubar, FSDocViewerPrefsHideWindowUI, FSDocViewerPrefsFitWindow, FSDocViewerPrefsCenterWindow, FSDocViewerPrefsDisplayDocTitle};

const FSPDFDocDisplayMode kDisplayModes[6] = {FSPDFDocDisplayUseNone, FSPDFDocDisplayUseOutlines, FSPDFDocDisplayUseThumbs, FSPDFDocDisplayFullScreen, FSPDFDocDisplayUseOC, FSPDFDocDisplayUseAttachment};

NSString *kDisplayModeStrings[6] = {@"UseNone", @"UseOutlines", @"UseThumbs", @"FullScreen", @"UseOC", @"UseAttachment"};

NSString *kBoxItemStrings[4] = {@"ViewArea", @"ViewClip", @"PrintArea", @"PrintClip"};

NSString *GetPageBoxName(FSPDFPageBoxType type) {
    switch (type) {
    case FSPDFPageMediaBox:
        return @"MediaBox";
    case FSPDFPageCropBox:
        return @"CropBox";
    case FSPDFPageTrimBox:
        return @"TrimBox";
    case FSPDFPageArtBox:
        return @"ArtBox";
    case FSPDFPageBleedBox:
        return @"BleedBox";
    default:
        return @"";
    }
}

NSString *GetViewerPrefName(FSDocViewerPrefsViewerPref ui_item) {
    switch (ui_item) {
    case FSDocViewerPrefsHideToolbar:
        return @"HideToolbar";
    case FSDocViewerPrefsHideMenubar:
        return @"HideMenubar";
    case FSDocViewerPrefsHideWindowUI:
        return @"HideWindowUI";
    case FSDocViewerPrefsFitWindow:
        return @"FitWindow";
    case FSDocViewerPrefsCenterWindow:
        return @"CenterWindow";
    case FSDocViewerPrefsDisplayDocTitle:
        return @"DisplayDocTitle";
    default:
        return @"";
    }
}

NSString *GetViewerPrefPrintScaleName(FSDocViewerPrefsPrintScale ui_item) {
    switch (ui_item) {
    case FSDocViewerPrefsPrintScaleNone:
        return @"PrintScaleNone";
    case FSDocViewerPrefsPrintScaleAppDefault:
        return @"PrintScaleAppDefault";
    default:
        return @"";
    }
}

void ShowDocViewerPrefsInfo(FSPDFDoc *doc, NSString *file_name) {
    content = @"";
    FSDocViewerPrefs *prefs = [[FSDocViewerPrefs alloc] initWithDocument:doc pdf_dict:NULL];
    textOutput(@"Document viewer preferences information:\r\n");
    // Get UI visibility status.
    for (unsigned int i = 0; i < sizeof(kUIItems) / (sizeof(kUIItems[0])); i++) {
        textOutput([[NSString alloc] initWithFormat:@"Visibility of %@:\t%@\r\n", GetViewerPrefName(kUIItems[i]), [prefs getUIDisplayStatus:kUIItems[i]] ? @"Yes" : @"No"]);
    }
    // Get display mode for non full-screen mode.
    FSPDFDocDisplayMode mode = prefs.nonFullScreenPageMode;
    NSString *display_mode = @"";
    for (unsigned int i = 0; i < sizeof(kDisplayModes) / sizeof(kDisplayModes[i]); i++) {
        if (mode == kDisplayModes[i]) {
            display_mode = kDisplayModeStrings[i];
            break;
        }
    }
    textOutput([[NSString alloc] initWithFormat:@"None full screen page mode:\t%@\r\n", display_mode]);
    // Get reading direction.
    textOutput([[NSString alloc] initWithFormat:@"Reading direction:\t%@\r\n", prefs.readingDirection ? @"left to right" : @"right to left"]);
    // Get the type of area item.
    FSPDFPageBoxType type = prefs.printClip;
    textOutput([[NSString alloc] initWithFormat:@"The GetPrintClip returned:\t%@\r\n", GetPageBoxName(type)]);
    type = prefs.printArea;
    textOutput([[NSString alloc] initWithFormat:@"The GetPrintArea returned:\t%@\r\n", GetPageBoxName(type)]);
    type = prefs.viewArea;
    textOutput([[NSString alloc] initWithFormat:@"The GetViewArea returned:\t%@\r\n", GetPageBoxName(type)]);
    type = prefs.viewClip;
    textOutput([[NSString alloc] initWithFormat:@"The GetViewClip returned:\t%@\r\n", GetPageBoxName(type)]);

    // Get page scaling option.
    textOutput([[NSString alloc] initWithFormat:@"Page scaling option:\t%@\r\n", GetViewerPrefPrintScaleName(prefs.printScale)]);
    // Get the number of copies to be printed.
    textOutput([[NSString alloc] initWithFormat:@"The number of copies to be printed:\t%d\r\n", prefs.printCopies]);
    // Get page ranges which allowed to print
    textOutput(@"Page ranges for printing:\r");
    FSRange *print_ranges = prefs.printRange;
    if (![print_ranges isEmpty]) {
        for (int i = 0; i < [print_ranges getSegmentCount]; i++)
            textOutput([[NSString alloc] initWithFormat:@"\tfirst:\t%d\tlast:\t%d\r\n", [print_ranges getSegmentStart:i], [print_ranges getSegmentEnd:i]]);
    }
    NSString *file_info = [[NSString alloc] initWithFormat:@"%@DocViewerPrefsInfo_%@", output_directory, file_name];
    NSError *error;
    [content writeToFile:file_info atomically:YES encoding:NSUTF8StringEncoding error:&error];
}

void SetDocViewerPrefsInfo(FSPDFDoc *doc) {
    doc.displayMode = FSPDFDocDisplayFullScreen;
    FSDocViewerPrefs *prefs = [[FSDocViewerPrefs alloc] initWithDocument:doc pdf_dict:NULL];
    // Set UI visibility status.
    for (unsigned int i = 0; i < sizeof(kUIItems) / (sizeof(kUIItems[0])); i++) {
        [prefs setUIDisplayStatus:kUIItems[i] value:YES];
    }
    // Set display mode for non full-screen mode.
    prefs.nonFullScreenPageMode = FSPDFDocDisplayUseOutlines;
    // Set reading direction.
    prefs.readingDirection = false;
    // Set the type of area item.
    prefs.viewArea = FSPDFPageCropBox;
    prefs.viewClip = FSPDFPageCropBox;
    prefs.printArea = FSPDFPageCropBox;
    prefs.printClip = FSPDFPageCropBox;
    // Set page scaling option.
    prefs.printScale = FSDocViewerPrefsPrintScaleNone;
    // Set the number of copies to be printed.
    prefs.printCopies = 4;
    FSRange *print_range = [[FSRange alloc] initWithStart_index:0 end_index:[doc getPageCount] / 2 filter:FSRangeAll];
    prefs.printRange = print_range;
}

NSString *kMetadataItems[8] = {@"Title", @"Author", @"Subject", @"Keywords", @"Creator", @"Producer", @"CreationDate", @"ModDate"};

void ShowMetaDataInfo(FSPDFDoc *doc, NSString *file_name) {
    content = @"";
    textOutput(@"Metadata information:\r\n");
    FSMetadata *metadata = [[FSMetadata alloc] initWithDocument:doc];
    for (unsigned int i = 0; i < sizeof(kMetadataItems) / sizeof(kMetadataItems[0]); i++) {
        NSString *item = kMetadataItems[i];
        textOutput([[NSString alloc] initWithFormat:@"%@: ", item]);
        NSArray<NSString *> *value = [metadata getValues:item];
        for (int j = 0; j < [value count]; j++) {
            textOutput([[NSString alloc] initWithFormat:@"%@", value[j]]);
        }
        textOutput(@"\r\n");
    }
    NSString *file_info = [[NSString alloc] initWithFormat:@"%@MetaDataInfo_%@", output_directory, file_name];
    NSError *error;
    [content writeToFile:file_info atomically:YES encoding:NSUTF8StringEncoding error:&error];
}

void SetMetaDataInfo(FSPDFDoc *doc) {
	NSString *kMetadataValues[] = {@"Title set by simple demo", @"Simple demo", @"Subject set by simple demo", @"Keywords set by simple demo", @"Foxit PDF SDK", @"Foxit"};
    FSMetadata *metadata = [[FSMetadata alloc] initWithDocument:doc];
    for (unsigned int i = 0; i < sizeof(kMetadataValues) / sizeof(kMetadataValues[0]); i++) {
        NSArray *MetadataValues = [[NSArray alloc] initWithObjects:kMetadataValues[i], nil];
        [metadata setValues:kMetadataItems[i] value_array:MetadataValues];
    }
    metadata.creationDateTime = GetLocalDateTime();
    metadata.modifiedDateTime = GetLocalDateTime();
}

int main(int argc, const char *argv[]) {
    @autoreleasepool {
        NSString *input_file = [[NSString alloc] initWithFormat:@"%@%@", input_path, @"AboutFoxit.pdf"];
        NSFileManager *fileManager = [NSFileManager defaultManager];
        BOOL isDir = NO;
        if ([fileManager fileExistsAtPath:output_directory isDirectory:&isDir]) {
            if (!isDir) {
                NSError *error = nil;
                if (![fileManager removeItemAtPath:output_directory error:&error] || error) {
                    return -1;
                }
                if (![fileManager createDirectoryAtPath:output_directory withIntermediateDirectories:YES attributes:nil error:&error] || error) {
                    return -1;
                }
            }
        } else {
            NSError *error = nil;
            if (![fileManager createDirectoryAtPath:output_directory withIntermediateDirectories:YES attributes:nil error:&error] || error) {
                return -1;
            }
        }

        // Initialize library
        FSErrorCode errorCode = [FSLibrary initialize:sn key:key];
        if (errorCode != FSErrSuccess) {
            NSLog(@"Library Initialize Error: %ld", errorCode);
            return -1;
        }

        @try {
            FSPDFDoc *doc = [[FSPDFDoc alloc] initWithPath:input_file];
            FSErrorCode errorCode = [doc load:@""];
            if (errorCode != FSErrSuccess) {
                NSLog(@"The Doc [%@] Error: %ld\n", input_file, errorCode);
                return 1;
            }
            // Show original information.
            ShowDocViewerPrefsInfo(doc, @"original.txt");
            ShowMetaDataInfo(doc, @"original.txt");

            // Set information.
            SetDocViewerPrefsInfo(doc);
            SetMetaDataInfo(doc);

            // Show new information.
            ShowDocViewerPrefsInfo(doc, @"new.txt");
            ShowMetaDataInfo(doc, @"new.txt");
            NSString *output_file = [[NSString alloc] initWithFormat:@"%@%@", output_directory, @"AboutFoxit_docinfo.pdf"];
            [doc saveAs:output_file save_flags:FSPDFDocSaveFlagNoOriginal];
        }
        @catch (NSException *exception) {
            NSLog(@"Unknown Exception, %@", exception);
            return -1;
        }
    }
    [FSLibrary destroy];
    return 0;
}
