// 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.

#include "FSPDFObjC.h"

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

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";


void AddTextObjects(FSPDFPage *page, NSString *content) {
	long position = [page getLastGraphicsObjectPosition:FSGraphicsObjectTypeText];
	FSTextObject *text_object = [FSTextObject create];
	
	[text_object setFillColor:0xFFAAAAAA];
	[text_object setStrokeColor:0xFFF68C21];
	
	// Prepare text state
	FSTextState *state = [[FSTextState alloc] init];
	state.font_size = 64.0f;
	FSFont *font = [[FSFont alloc] initWithFont_id:FSFontStdIDTimes];
	state.font = font;
	state.textmode = FSTextStateModeFillStrokeClip;
	
	[text_object setTextState:page text_state:state is_italic:NO weight:750];
	
	// Set content
	[text_object setText:content];
	[page insertGraphicsObject:position graphics_object:text_object];
	
	// Transform to center
	FSRectF *rect = [text_object getRect];
	float offset_x = ([page getWidth] - (rect.right - rect.left)) / 2;
	float offset_y = ([page getHeight] - (rect.top - rect.bottom)) / 2;
	FSMatrix2D *matrix = [[FSMatrix2D alloc] initWithA1:1 b1:0 c1:0 d1:1 e1:offset_x f1:offset_y];
	[text_object transform:matrix need_transform_clippath:NO];
	
	// Generator content
	[page generateContent];
}

bool InsertPage() {
	NSString *input_file = [input_path stringByAppendingPathComponent:@"page_organization_123.pdf"];
	FSPDFDoc *doc = [[FSPDFDoc alloc] initWithPath:input_file];
	FSErrorCode code = [doc load:nil];
	if (code != FSErrSuccess) {
		NSLog(@"The Doc [%@] Error: %d", input_file, (int)code);
		return false;
	}
	
	float w = 612.0;
	float h = 792.0;
	FSPDFPage *page = [doc insertPage:-1 width:w height:h];
	AddTextObjects(page, @"insert in first");
	page = [doc insertPage:2 width:w height:h];
	AddTextObjects(page, @"insert in 2 (based 0)");
	page = [doc insertPage:[doc getPageCount] width:w height:h];
	AddTextObjects(page, @"insert in last");
	NSString *output_file = [output_directory stringByAppendingPathComponent:@"insert_page.pdf"];
	[doc saveAs:output_file save_flags:FSPDFDocSaveFlagNormal];
	NSLog(@"Insert pages.");
	return true;
}

bool RemovePage() {
	NSString *input_file = [input_path stringByAppendingPathComponent:@"page_organization_123.pdf"];
	FSPDFDoc *doc = [[FSPDFDoc alloc] initWithPath:input_file];
	FSErrorCode code = [doc load:nil];
	if (code != FSErrSuccess) {
		NSLog(@"The Doc [%@] Error: %d", input_file, (int)code);
		return false;
	}
	
	while ([doc getPageCount] > 1) {
		[doc removePage:0];
	}
	NSString *output_file = [output_directory stringByAppendingPathComponent:@"remove_all_pages_exceptt_the_last_page.pdf"];
	[doc saveAs:output_file save_flags:FSPDFDocSaveFlagNormal];
	NSLog(@"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.
bool ImportPage() {
	NSString *file_dest = [input_path stringByAppendingPathComponent:@"page_organization_123.pdf"];
	NSString *file_src = [input_path stringByAppendingPathComponent:@"page_organization_abc.pdf"];
	FSPDFDoc *doc_dest = [[FSPDFDoc alloc] initWithPath:file_dest];
	FSErrorCode code = [doc_dest load:nil];
	if (code != FSErrSuccess) {
		NSLog(@"The Doc [%@] Error: %d", file_dest, (int)code);
		return false;
	}
	FSPDFDoc *doc_src = [[FSPDFDoc alloc] initWithPath:file_src];
	code = [doc_src load:nil];
	if (code != FSErrSuccess) {
		NSLog(@"The Doc [%@] Error: %d", file_src, (int)code);
		return false;
	}
	// Import page from PDFDoc object.
	FSRange *import_ranges = [[FSRange alloc] initWithIndex:0];
	[import_ranges addSingle:[doc_src getPageCount]-1];
	FSProgressive *progressive = [doc_dest startImportPages:-1 src_doc:doc_src flags:FSPDFDocImportFlagNormal layer_name:@"abc" page_range:import_ranges pause:nil];
	while ([progressive resume] == FSProgressiveToBeContinued) {
		;
	}
	NSString *output_file = [output_directory stringByAppendingPathComponent:@"page_organization_abc_to_123_import_pages.pdf"];
	[doc_dest saveAs:output_file save_flags:FSPDFDocSaveFlagNormal];
	
	doc_dest = [[FSPDFDoc alloc] initWithPath:file_dest];
	code = [doc_dest load:nil];
	if (code != FSErrSuccess) {
		NSLog(@"The Doc [%@] Error: %d", file_dest, (int)code);
		return false;
	}
	// Import page from file path.
	progressive = [doc_dest startImportPagesFromFilePath:-1 src_file_path:file_src  password:nil flags:FSPDFDocImportFlagNormal layer_name:@"abc" page_range:import_ranges pause:nil];
	while ([progressive resume] == FSProgressiveToBeContinued) {
		;
	}
	output_file = [output_directory stringByAppendingPathComponent:@"abc_to_123_import_pages_form_filepath.pdf"];
	[doc_dest saveAs:output_file save_flags:FSPDFDocSaveFlagNormal];
	NSLog(@"Import pages.");
	return true;
}

bool ImportPageOptimized() {
    NSString *file_dest = [input_path stringByAppendingPathComponent:@"page_organization_123.pdf"];
    NSString *file_src = [input_path stringByAppendingPathComponent:@"page_organization_abc.pdf"];
    FSPDFDoc *doc_dest = [[FSPDFDoc alloc] initWithPath:file_dest];
    FSErrorCode code = [doc_dest load:nil];
    if (code != FSErrSuccess) {
        NSLog(@"The Doc [%@] Error: %d", file_dest, (int)code);
        return false;
    }
    FSPDFDoc *doc_src = [[FSPDFDoc alloc] initWithPath:file_src];
    code = [doc_src load:nil];
    if (code != FSErrSuccess) {
        NSLog(@"The Doc [%@] Error: %d", file_src, (int)code);
        return false;
    }
    // Extract pages to temporary document
    FSRange *import_ranges = [[FSRange alloc] initWithIndex:0];
    [import_ranges addSingle:[doc_src getPageCount] - 1];
    NSString *file_temp = [output_directory stringByAppendingPathComponent:@"page_organization_import_extracted_pages.pdf"];
    FSProgressive *progressive = [doc_src startExtractPages:file_temp options:FSPDFDocExtractPagesOptionAnnotation page_range:import_ranges pause:nil];
    while ([progressive resume] == FSProgressiveToBeContinued) {
        ;
    }
    
    FSPDFDoc *doc_temp = [[FSPDFDoc alloc] initWithPath:file_temp];
    code = [doc_temp load:nil];
    if (code != FSErrSuccess) {
        NSLog(@"The Doc [%@] Error: %d", file_temp, (int)code);
        return false;
    }
    
    // Insert temporary document into destination
    [doc_dest insertDocument:-1 src_doc:doc_temp options:FSPDFDocInsertDocOptionAttachments];
    NSString *output_file = [output_directory stringByAppendingPathComponent:@"abc_to_123_insert_document.pdf"];
    [doc_dest saveAs:output_file save_flags:FSPDFDocSaveFlagNormal];
    
    NSLog(@"Import pages optimized.");
    return true;
}

bool MovePages()
{
	NSString *input_file = [input_path stringByAppendingPathComponent:@"page_organization_123.pdf"];
	NSString *input_file1 = [input_path stringByAppendingPathComponent:@"page_organization_abc.pdf"];
	// Move page
	FSPDFDoc *doc = [[FSPDFDoc alloc] initWithPath:input_file];
	FSErrorCode code = [doc load:nil];
	if (code != FSErrSuccess) {
		NSLog(@"The Doc [%@] Error: %d", input_file, (int)code);
		return false;
	}
	int count = [doc getPageCount];
	FSPDFPage *page = [doc getPage:0];
	[doc movePageTo:page dest_index:[doc getPageCount] - 1];
	NSString *output_file1 = [output_directory stringByAppendingPathComponent:@"move_first_page_to_last.pdf"];
	[doc saveAs:output_file1 save_flags:FSPDFDocSaveFlagNormal];
	
	doc = [[FSPDFDoc alloc] initWithPath:input_file1];
	code = [doc load:nil];
	if (code != FSErrSuccess) {
		return false;
	}
	FSRange *page_set = [[FSRange alloc] init];
	for (int i = 0; i < count / 2; i++)
		 [page_set addSingle:2 * i];
	[doc movePagesTo:page_set dest_index:[doc getPageCount] - 1];
	NSString *output_file = [output_directory stringByAppendingPathComponent:@"move_pages.pdf"];
	[doc saveAs:output_file save_flags:FSPDFDocSaveFlagNormal];
	NSLog(@"Move pages.");
	return true;
}

int main(int argc, const char * argv[]) {
	
	@autoreleasepool {
		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 {
			if (!(InsertPage() && RemovePage() && ImportPage() && ImportPageOptimized() && MovePages())) {
				return 1;
			}
		}
		@catch (NSException *e) {
			NSLog(@"Unknown Exception, %@", e);
			return -1;
		}
	}
	[FSLibrary destroy];
	return 0;
}
