//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2025 by Apryse Software Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------
#include <PDF/PDFNet.h>
#include <PDF/PDFDoc.h>
#include <PDF/BarcodeModule.h>
#include <PDF/BarcodeOptions.h>
#include <iostream>
#include <fstream>
#include "../../LicenseKey/CPP/LicenseKey.h"

using namespace std;
using namespace pdftron;
using namespace PDF;
using namespace SDF;

//---------------------------------------------------------------------------------------
// The Barcode Module is an optional PDFNet add-on that can be used to extract
// various types of barcodes from PDF documents.
//
// The Apryse SDK Barcode Module can be downloaded from https://dev.apryse.com/
//---------------------------------------------------------------------------------------

void WriteTextToFile(const std::string& filename, const UString& text)
{
	ofstream out_file(filename.c_str(), ofstream::binary);
	string out_buf = text.ConvertToUtf8();
	out_file.write(out_buf.c_str(), out_buf.size());
	out_file.close();
}


int main(int argc, char *argv[])
{
	try 
	{
		// The first step in every application using PDFNet is to initialize the 
		// library and set the path to common PDF resources. The library is usually 
		// initialized only once, but calling Initialize() multiple times is also fine.
		PDFNet::Initialize(LicenseKey);

		// The location of the Barcode Module
		PDFNet::AddResourceSearchPath("../../../Lib/");

		// Test if the add-on is installed
		if (!BarcodeModule::IsModuleAvailable())
		{
			cout << endl;
			cout << "Unable to run BarcodeTest: Apryse SDK Barcode Module not available." << endl;
			cout << "---------------------------------------------------------------" << endl;
			cout << "The Barcode Module is an optional add-on, available for download" << endl;
			cout << "at https://dev.apryse.com/. If you have already downloaded this" << endl;
			cout << "module, ensure that the SDK is able to find the required files" << endl;
			cout << "using the PDFNet::AddResourceSearchPath() function." << endl << endl;
			return 0;
		}

		// Relative path to the folder containing test files.
		string input_path =  "../../TestFiles/Barcode/";
		string output_path = "../../TestFiles/Output/";


		//--------------------------------------------------------------------------------
		// Example 1) Detect and extract all barcodes from a PDF document into a JSON file
		try
		{

			cout << "Example 1: extracting barcodes from barcodes.pdf to barcodes.json" << endl;

			// A) Open the .pdf document
			PDFDoc doc(input_path + "barcodes.pdf");

			// B) Detect PDF barcodes with the default options
			BarcodeModule::ExtractBarcodes(doc, output_path + "barcodes.json");

		}
		catch (Common::Exception& e)
		{
			cout << e << endl;
		}
		catch (...)
		{
			cout << "Unknown Exception" << endl;
		}


		//--------------------------------------------------------------------------------
		// Example 2) Limit barcode extraction to a range of pages, and retrieve the JSON into a
		// local string variable, which is then written to a file in a separate function call
		try
		{

			cout << "Example 2: extracting barcodes from pages 1-2 to barcodes_from_pages_1-2.json" << endl;

			// A) Open the .pdf document
			PDFDoc doc(input_path + "barcodes.pdf");

			// B) Detect PDF barcodes with custom options
			BarcodeOptions options;

			// Convert only the first two pages
			options.SetPages("1-2");

			UString json = BarcodeModule::ExtractBarcodesAsString(doc, options);

			// C) Save JSON to file
			WriteTextToFile(output_path + "barcodes_from_pages_1-2.json", json);

		}
		catch (Common::Exception& e)
		{
			cout << e << endl;
		}
		catch (...)
		{
			cout << "Unknown Exception" << endl;
		}


		//--------------------------------------------------------------------------------
		// Example 3) Narrow down barcode types and allow the detection of both horizontal
		// and vertical barcodes
		try
		{

			cout << "Example 3: extracting basic horizontal and vertical barcodes" << endl;

			// A) Open the .pdf document
			PDFDoc doc(input_path + "barcodes.pdf");

			// B) Detect only basic 1D barcodes, both horizontal and vertical
			BarcodeOptions options;

			// Limit extraction to basic 1D barcode types, such as EAN 13, EAN 8, UPCA, UPCE,
			// Code 3 of 9, Code 128, Code 2 of 5, Code 93, Code 11 and GS1 Databar.
			options.SetBarcodeSearchTypes(BarcodeOptions::e_linear);

			// Search for barcodes oriented horizontally and vertically
			options.SetBarcodeOrientations(
				BarcodeOptions::e_horizontal | BarcodeOptions::e_vertical);

			BarcodeModule::ExtractBarcodes(doc, output_path + "barcodes_1D.json", options);

		}
		catch (Common::Exception& e)
		{
			cout << e << endl;
		}
		catch (...)
		{
			cout << "Unknown Exception" << endl;
		}


		cout << "Done." << endl;

		PDFNet::Terminate();
	}
	catch (Common::Exception& e)	
	{
		cout << e << endl;
	}
	catch (...)
	{
		cout << "Unknown Exception" << endl;
	}

	return 0;	
}
