// 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.
// If using a stream to load the html file, set variable isfilestreamload to true.
//
// This file contains an example to demonstrate how to use Foxit PDF SDK to convert from html to pdf.

#include "FSPDFObjC.h"

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

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


bool AnalysisParameter(int argc,const char* argv[], FSHTML2PDFSettingData *pdf_setting_data, NSString*& url_or_html, NSString*& engine_path, NSString*& cookies_path, NSString*& output_path, int& timeout)
{
    FSRectF* page_margin=[[FSRectF alloc]init];
    for (int i = 1; i < argc; i = i + 2) {
        NSString *argv_key = [NSString stringWithUTF8String:argv[i]];
        NSString *argv_value;
        if (argc <= i + 1) {
        	NSLog(@"Please make sure the key %@ is valid and it has value!\n", argv_key);
        	NSLog(@"Usage: html2pdf_xxx <-html <The url or html path>> <-o <output pdf path>> ...\nPlease try 'html2pdf_xxx --help' for more information.\n");
        	return false;
        }
        argv_value = [NSString stringWithUTF8String:argv[i+1]];
        if ([argv_key isEqualToString:@"-w"]) pdf_setting_data.page_width =  [argv_value floatValue];
        else if ([argv_key isEqualToString:@"-h"]) pdf_setting_data.page_height = [argv_value floatValue];
        else if ([argv_key isEqualToString:@"-r"]) pdf_setting_data.rotate_degrees = [argv_value floatValue];
        else if ([argv_key isEqualToString:@"-ml"]) {
            page_margin.left = [argv_value floatValue];
        }
        else if ([argv_key isEqualToString:@"-mr"]) {
            page_margin.right = [argv_value floatValue];
        }
        else if ([argv_key isEqualToString:@"-mt"]) {
            page_margin.top = [argv_value floatValue];
        }
        else if ([argv_key isEqualToString:@"-mb"]) {
            page_margin.bottom = [argv_value floatValue];
        }
        else if ([argv_key isEqualToString:@"-scale"]) pdf_setting_data.scaling_mode = (FSHTML2PDFSettingDataHTML2PDFScalingMode)[argv_value floatValue];
        else if ([argv_key isEqualToString:@"-link"]) pdf_setting_data.is_convert_link = [argv_value isEqualToString:@"yes"] ? true : false;
        else if ([argv_key isEqualToString:@"-tag"]) pdf_setting_data.is_generate_tag = [argv_value isEqualToString:@"yes"] ? true : false;
        else if ([argv_key isEqualToString:@"-bookmarks"]) pdf_setting_data.to_generate_bookmarks = [argv_value isEqualToString:@"yes"] ? true : false;
        else if ([argv_key isEqualToString:@"-mode"]) pdf_setting_data.page_mode =(FSHTML2PDFSettingDataHTML2PDFPageMode)[argv_value floatValue];
        else if ([argv_key isEqualToString:@"-encoding"])  pdf_setting_data.encoding_format = (FSHTML2PDFSettingDataHTML2PDFEncodingFormat)[argv_value floatValue];
        else if ([argv_key isEqualToString:@"-render_images"])  pdf_setting_data.to_render_images = [argv_value isEqualToString:@"yes"] ? true : false;
        else if ([argv_key isEqualToString:@"-remove_underline_for_link"])  pdf_setting_data.to_remove_underline_for_link = [argv_value isEqualToString:@"yes"] ? true : false;
        else if ([argv_key isEqualToString:@"-headerfooter"])  pdf_setting_data.to_set_headerfooter = [argv_value isEqualToString:@"yes"] ? true : false;
        else if ([argv_key isEqualToString:@"-headerfooter_title"])  pdf_setting_data.headerfooter_title = argv_value;
        else if ([argv_key isEqualToString:@"-headerfooter_url"])  pdf_setting_data.headerfooter_url = argv_value;
        else if ([argv_key isEqualToString:@"-bookmark_root_name"]) pdf_setting_data.bookmark_root_name = argv_value;
        else if ([argv_key isEqualToString:@"-resize_objects"]) pdf_setting_data.to_resize_objects = [argv_value isEqualToString:@"yes"] ? true : false;
        else if ([argv_key isEqualToString:@"-print_background"]) pdf_setting_data.to_print_background = [argv_value isEqualToString:@"yes"] ? true : false;
        else if ([argv_key isEqualToString:@"-optimize_tag"]) pdf_setting_data.to_optimize_tag_tree = [argv_value isEqualToString:@"yes"] ? true : false;
        else if ([argv_key isEqualToString:@"-media"]) pdf_setting_data.media_style =(FSHTML2PDFSettingDataHTML2PDFMediaStyle)[argv_value floatValue];
        else if ([argv_key isEqualToString:@"-engine"]) engine_path=argv_value;
        else if ([argv_key isEqualToString:@"-cookies"]) cookies_path=argv_value;
        else if ([argv_key isEqualToString:@"-o"]) output_path=argv_value;
        else if ([argv_key isEqualToString:@"-html"]) url_or_html=argv_value;
        else if ([argv_key isEqualToString:@"-timeout"]) timeout = [argv_value intValue];
        else{ 
        	NSLog(@"Please make sure the key %@ is valid and it has value!\n", argv_key);
        	NSLog(@"Usage: html2pdf_xxx <-html <The url or html path>> <-o <output pdf path>> ...\nPlease try 'html2pdf_xxx --help' for more information.\n");
        	return false;
        }
	}
    pdf_setting_data.page_margin=page_margin;
	return true;
}
typedef long long int       int64;
typedef unsigned long long  FILESIZE;



@interface FSFileReader : NSObject<FSFileReaderCallback>
@property (nonatomic) FILE* file_;
@property (nonatomic, strong) NSString* filePath;
-(BOOL)LoadFile:(NSString *)filePath;
//- (id)initWithSourceFilePath:(NSString *)path;
@end

@implementation FSFileReader

-(BOOL)LoadFile:(NSString *)filePath{
        self.filePath = filePath;
        const char* mfilePath = [filePath cStringUsingEncoding:NSUTF8StringEncoding];
        self.file_ = fopen(mfilePath, "rb");
        if (!self.file_)
            return NO;
        return TRUE;
    }
-(unsigned long long)getSize{
    if (!self.file_) return NO;
    fseek(self.file_, 0, SEEK_END);
    return (uint32)ftell(self.file_);
 }
-(NSData*)readBlock:(unsigned long long)offset  size:(unsigned long long)size {

        NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:self.filePath];
        NSData *data = [fileHandle readDataToEndOfFile];
        return data;
 }
@end

@interface FSFileWriterCallbackImpl : NSObject<FSFileWriterCallback>
@property (nonatomic) FILE* mfile;
@property (nonatomic, strong) NSString* filePath;
-(BOOL)LoadFile:(NSString *)filePath;
@end

@implementation FSFileWriterCallbackImpl
-(BOOL)LoadFile:(NSString *)filePath
{
    self.filePath = filePath;
    const char* mfilePath = [filePath cStringUsingEncoding:NSUTF8StringEncoding];
    self.mfile = fopen(mfilePath, "wb");
    if (!self.mfile) return NO;
    return TRUE;
}

-(unsigned long long)getSize {
    if (!self.mfile) return NO;
    
    fseek(self.mfile, 0, SEEK_END);
    return (uint32)ftell(self.mfile);
}

-(BOOL)writeBlock:(NSData*)data offset:(unsigned long long)offset {
    if (!self.mfile) return NO;
    
    NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:self.filePath];
    [fileHandle seekToEndOfFile];
    [fileHandle writeData:data];
    [fileHandle closeFile];
    
    return YES;
}

-(BOOL)flush {
    return YES;
}
@end

int main(int argc, const char *argv[]) {
    @autoreleasepool {
        if (argc > 1 && [[NSString stringWithUTF8String:argv[1]] isEqualToString:@"--help"]) {
        NSLog(@"Usage:");
      	NSLog(@"html2pdf_xxx <-html <The url or html path>> <-o <output pdf path>> <-engine <htmltopdf engine path>>");
      	NSLog(@" [-w <page width>] [-h <page height>]  [-r <page rotate degree>] [-mode <page mode>] [-scale <whether scale page>]");
      	NSLog(@" [-ml <margin left>] [-mr <margin right>] [-mt <margin top>] [-mb <margin bottom>] [-link <whether convert link>]");
      	NSLog(@" [-tag <whether generate tag>] [-bookmarks <whether generate bookmarks>] [-cookies <cookies file path>] [-timeout <timeout>]\r\n\r\n");
      	NSLog(@"-html The url or html file path. for examples '-html www.foxitsoftware.com'");
      	NSLog(@"-o The output pdf path." );
      	NSLog(@"-engine The html to pdf engine path.");
      	NSLog(@"-w The page width.");
      	NSLog(@"-h The page height.");
      	NSLog(@"-r The page roate degree.'0' means 0 degree, '1' means 90 degree, '2' means 180 degree, '3' means 270 degree.");
        NSLog(@"-ml The page margin distance of left.");
        NSLog(@"-mr The page margin distance of right.");
        NSLog(@"-mt The page margin distance of top.");
        NSLog(@"-mb The page margin distance of bottom.");
      	NSLog(@"-mode The page mode. 0 means single page mode and 1 means multiple mode");
      	NSLog(@"-scale The scaling mode. '0' means no scale, '1' means scale page, '2' means enlarge page.");
      	NSLog(@"-link Whether to covert link. 'yes' means to convert link, 'no' means no need to covert.");
      	NSLog(@"-tag Whether to generate tag. 'yes' means to generate tag, 'no' means no need to generate.");
      	NSLog(@"-bookmarks Whether to generate bookmarks. 'yes' means generate bookmarks, 'no' means no need to generate.");
        NSLog(@"-encoding The HTML encoding format. '0' means auto encoding and '1'-'73' means other encodings");
        NSLog(@"-render_images Whether to render images or not.'yes' means to render images, 'no' means no need to render.");
        NSLog(@"-remove_underline_for_link Whether to remove underline for link. 'yes' means to remove underline for link, 'no' means no need to remove.");
        NSLog(@"-headerfooter Whether to generate headerfooter. 'yes' means to generate headerfooter, 'no' means no need to generate.");
        NSLog(@"-headerfooter_title The headerfooter title.");
        NSLog(@"-headerfooter_url The headerfooter url.");
        NSLog(@"-bookmark_root_name The bookmark root name.");
        NSLog(@"-print_background Whether to print background. 'yes' means to print background, 'no' means no need to print background.");
        NSLog(@"-optimize_tag Whether to optimize tag tree. 'yes' means to optimize tag tree, 'no' means no need to optimize tag tree.");
        NSLog(@"-media The media style. '0' means screen media style, '1' means print media style.");
      	NSLog(@"-cookies The cookies file path.");
      	NSLog(@"-timeout The timeout of loading webpages.");
        return 0;
	}
        NSString *output_directory = [output_path stringByAppendingString:@"html2pdf/"];
        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;
            }
        }
        //If using a stream to load the html file, set isfilestreamload to true
        BOOL isfilestreamload = NO;
        // Initialize library
        FSErrorCode errorCode = [FSLibrary initialize:sn key:key];
        if (errorCode != FSErrSuccess) {
            NSLog(@"Library Initialize Error: %ld", errorCode);
            return -1;
        }
        NSString *url_or_html = [input_path stringByAppendingPathComponent:@"AboutFoxit.html"];
        // "engine_path" is the path of the engine file "fxhtml2pdf" which is used to convert html to pdf. Please refer to Developer Guide for more details.
	    NSString *engine_path = @"";
        // "cookies_path" is the path of the cookies file exported from the web pages that you want to convert. Please refer to Developer Guide for more details.
	    NSString *cookies_path = @"";
        NSString *output_file_path = [output_directory stringByAppendingString:@"html2pdf_result.pdf"];
	    int time_out = 15;


        @try {
            
            FSHTML2PDFSettingData *pdf_setting_data=[FSHTML2PDFSettingData new];
            pdf_setting_data.is_convert_link = true;
            pdf_setting_data.is_generate_tag = true;
            pdf_setting_data.to_generate_bookmarks = true;
            pdf_setting_data.rotate_degrees = 0;
            pdf_setting_data.page_height = 640;
            pdf_setting_data.page_width = 900;
            pdf_setting_data.page_mode = FSHTML2PDFSettingDataPageModeSinglePage;
            pdf_setting_data.scaling_mode = FSHTML2PDFSettingDataScalingModeScale;
            pdf_setting_data.to_print_background = true;
            pdf_setting_data.to_optimize_tag_tree = false;
            pdf_setting_data.media_style = FSHTML2PDFSettingDataMediaStyleScreen;

        	if (!AnalysisParameter(argc, argv, pdf_setting_data, url_or_html, engine_path, cookies_path, output_file_path, time_out)) return -1;

            [FSConvert fromHTML:url_or_html engine_path:engine_path cookies_path:cookies_path setting_data:pdf_setting_data saved_pdf_path:output_file_path timeout:time_out];
           
            NSLog(@"Convert HTML to PDF successfully!");
        }
        @catch (NSException *e) {
            NSLog(@"Unknown Exception, %@", e);
        }
        if(isfilestreamload){
          @try {
            
            FSHTML2PDFSettingData *pdf_setting_data=[FSHTML2PDFSettingData new];
              pdf_setting_data.page_height = 650;
              pdf_setting_data.page_width = 950;
              pdf_setting_data.is_to_page_scale = false;
              FSRectF* page_margin=[[FSRectF alloc]init];
              page_margin.left = 18;
              page_margin.bottom = 18;
              page_margin.right = 18;
              page_margin.top = 18;
              pdf_setting_data.page_margin = page_margin;
              pdf_setting_data.is_convert_link = true;
              pdf_setting_data.rotate_degrees = 0;
              pdf_setting_data.is_generate_tag = true;
              pdf_setting_data.page_mode = FSHTML2PDFSettingDataPageModeSinglePage;
              pdf_setting_data.scaling_mode = FSHTML2PDFSettingDataScalingModeScale;
              pdf_setting_data.to_generate_bookmarks = true;
              pdf_setting_data.encoding_format = 0;
              pdf_setting_data.to_render_images = true;
              pdf_setting_data.to_remove_underline_for_link = false;
              pdf_setting_data.to_set_headerfooter = false;
              pdf_setting_data.headerfooter_title = @"";
              pdf_setting_data.headerfooter_url = @"";
              pdf_setting_data.bookmark_root_name = @"abcde";
              pdf_setting_data.to_resize_objects = true;
              pdf_setting_data.to_print_background = false;
              pdf_setting_data.to_optimize_tag_tree = false;
              pdf_setting_data.media_style = 0;
              pdf_setting_data.to_load_active_content = false;
              NSString * cookies = @"";

              NSString *output_path = [output_directory stringByAppendingString:@"html2pdf_filestream_result.pdf"];
              FSFileWriterCallbackImpl *filewriter = [[FSFileWriterCallbackImpl alloc] init];
              [filewriter LoadFile:output_path];
              // "htmlfile" is the path of the html file to be loaded. For example: "C:/aaa.html". The method of "FromHTML" will load this file as a stream.              NSString *htmlfile = @"html2pdf_filestream.html";
              NSString *htmlfile = @"";
              FSFileReader *filereader = [[FSFileReader alloc] init];
              [filereader LoadFile:htmlfile];
              // "htmlfilepng" is the path of the png resource file to be loaded. For example: "C:/aaa.png". set "htmlfilepng" in the related_resource_file of HTML2PDFRelatedResource.
              NSString * htmlfilepng = @"";
              FSFileReader *filereader1 = [[FSFileReader alloc] init];
              [filereader1 LoadFile:htmlfilepng];
              //"relativefilepath" is  the resource file's relative path. For example: "./aaa.png".
              NSString *relativefilepath = @"";

              FSHTML2PDFRelatedResourceArray *html2PDFRelatedResourceArray = [[FSHTML2PDFRelatedResourceArray alloc] init];
              FSHTML2PDFRelatedResource *html2PDFRelatedResource = [[FSHTML2PDFRelatedResource alloc] init];
              html2PDFRelatedResource.related_resource_file = filereader1;
              html2PDFRelatedResource.resource_file_relative_path = relativefilepath;
              [html2PDFRelatedResourceArray add:html2PDFRelatedResource];

              [FSConvert fromHTMLWithReaderCallbackHTML:filereader  html2pdf_related_resource_array:html2PDFRelatedResourceArray engine_path:engine_path cookies_reader:nil setting_data:pdf_setting_data saved_pdf_filestream:filewriter timeout:30];

              NSLog(@"Convert HTML to PDF successfully by filestream!");
            }
          @catch (NSException *e) {
            NSLog(@"Unknown Exception, %@", e);
          }          
        }
        [FSLibrary destroy];
        return 0;
    }
}
