// ESL_SAMPLE.cpp : Defines the entry point for the application.
//

#include "ESL_SAMPLE.h"
#include "EslStub.h"
#include <iostream> // for std::cout log
#include <cctype> // use isdigit
#include <locale>

#define LICENSE_KEY	"EPSON"
//#define	DEVICE_NAME	"PX-M780F Series"
#define	DEVICE_NAME	"DS-C480W:534245393030303049"

// Save path
#define SAVE_PATH "."
// Save filename
#define SAVE_FILE_NAME "img"

/*///////////////////////////////////////////////////////////////////////
Connect USB
Individual identification is possible by entering the information 
obtained as a result of entering "epsonscan2 -l" in the device name. 
$ epsonscan2 -l
 === List of available devices ==
device ID :DS-730N:001:003
ModelID:ES021C
->#define	DEVICE_NAME	"DS-730N:001:003"

The following method connects to the first device found. 
#define	DEVICE_NAME	"DS-730N"
*////////////////////////////////////////////////////////////////////////
#define IP_ADDRESS "10.8.106.99"

BOOL isDigits(const char* str) {
	if (*str == '-'){
        ++str;
	}

    while (*str) {
        if (!isdigit(*str))
            return FALSE;
        ++str;
    }
    return TRUE;
}
int DumpToFile(uint16_t* utf16_string, int len);

BOOL CALLBACK eslCallback(EslCBDataHdr* pData, PVOID pPrivate)
{
	//std::cout << "[INFO]eslCallback" << std::endl;

	// Check if the parameter is valid
	if (pData == NULL) {
		std::cout << "[INFO]pData is NULL" << std::endl;
		return FALSE;
	}

	BOOL cancelReqfromApp = FALSE;
	switch (pData->type) {
		case CBDT_STATUS_SCAN:
		{
			EslCBDataScanStatus* pstatus = (EslCBDataScanStatus*)pData;
			switch (pstatus->status) {
			case STATUS_SCAN_UPDATE_PROGRESS:
				break;
			case STATUS_SCAN_PAGE_END:
				// std::cout << "[INFO]PageCount: " << pstatus->count << std::endl;
				// std::cout << "[INFO]Proguress: " << pstatus->progress << std::endl;
				break;
			default:
				std::cout << "[ERROR]Invalid CallbackData Status\n" << std::endl;
			}

			// If application wants to cancel scanning, return FALSE
			//cancelReqfromApp = TRUE;
			if (cancelReqfromApp) {
				return FALSE;
			}

			break;
		}
		case CBDT_IMAGE_FILE:
		{
			// Get saved image file information
			EslCBDImageFile* pstatus = (EslCBDImageFile*)pData;
			std::cout << "[INFO]FileName: " << pstatus->filename << std::endl;
			switch (pstatus->status) {
			case STATUS_IMAGE_FILE_INFO:
				break;
			default:
				std::cout << "[ERROR]Invalid CallbackData Status\n" << std::endl;
			}
			break;
		}
		case CBDT_DATA_OBR:
		{
			EslCBDataOBRData* pstatus = (EslCBDataOBRData*)pData;
			
			switch (pstatus->status) {
			case STATUS_DATA_OBR_RESULT:
                                std::cout << "[DISPLAY]-----------------------------------------------------" << std::endl;
                                std::cout << "[DISPLAY]page: " << pstatus->count << " index: " << pstatus->index << std::endl;
                                std::cout << "[DISPLAY]symbolType: " << pstatus->symbolType << " dataLength: " << pstatus->dataLength << " orientation: " << pstatus->orientation << std::endl;
                                std::cout << "[DISPLAY]dataString: " << pstatus->dataString << std::endl;
				break;
			default:
				std::cout << "[ERROR]Invalid CallbackData Status\n" << std::endl;
			}
			break;
		}

		case CBDT_DATA_OCR:
		{
			EslCBDataOCRData* pstatus = (EslCBDataOCRData*)pData;
			switch (pstatus->status) {
			 	case STATUS_DATA_OCR_RESULT:
				{
					std::cout << "[DISPLAY]-----------------------------------------------------" << std::endl;
					
					std::locale::global(std::locale(""));
					std::cout << "[DISPLAY]page: " << pstatus->count << std::endl;
					std::cout << "[DISPLAY]dataLength: " << pstatus->dataLength << std::endl;
					std::cout << "[DISPLAY]dataString: " << pstatus->dataString << std::endl;

					if (pstatus->dataLength > 0){
						DumpToFile(pstatus->dataString, pstatus->dataLength);
						std::cout << "[DISPLAY]OCR results were output to ocr_result.txt" << std::endl;
					}else{
						std::cout << "[DISPLAY]OCR did not detect any characters." << std::endl;
					}
				
					break;	
				}

			 	default:
					std::cout << "[ERROR]Invalid CallbackData Status\n" << std::endl;
			}
			break;
		}
		
		default:
			std::cout << "[ERROR]Invalid CallbackData Status\n" << std::endl;
	}

	return TRUE;
}

int DumpToFile(uint16_t* utf16_string, int len) {
    setlocale(LC_ALL, "");

    FILE *file = fopen("ocr_result.txt", "wb");
    if (file == NULL) {
        perror("fails to open file");
        return 1;
    }

    unsigned char bom[] = {0xFF, 0xFE};
    fwrite(bom, sizeof(bom), 1, file);	
    fwrite(utf16_string, 2, len, file);

    fclose(file);

    return 0;
}

BOOL Parameter_Check(const char* param, checkOption check_option, DWORD* pErrCode){
	

	*pErrCode = 0;

	// Argment check
	if (param == NULL){
		std::cout << "Parameter error." << std::endl;
		std::cout << "Option followed by a parameter." << std::endl;
		*pErrCode = 1;
		return FALSE;
	}

	// Parameter check
	switch (check_option) {
	case CO_DEVICEID:
		if (isDigits(param) == TRUE){
			std::cout << "Parameter error." << std::endl;
			std::cout << "Invaild parameter." << std::endl;
			*pErrCode = 1;
			return FALSE;
		}
		break;
	case CO_VALUE:
		if (isDigits(param) == FALSE){
			std::cout << "Parameter error." << std::endl;
			std::cout << "Invaild parameter." << std::endl;
			*pErrCode = 1;
			return FALSE;
		}
		break;
	default:
		std::cout << "Error. Invaild checkOption." << check_option << std::endl;
		*pErrCode = 2;
		return FALSE;
	}

	return TRUE;	

}

BOOL Setup_ConnectInfo (const char* device_name, const connectionMethod connection_method, ConnectInfo* scanner, DWORD* pErrCode){

		switch (connection_method) {
		case CM_USB:
			scanner->connectType = CT_DEFAULT;
			memcpy(scanner->deviceName, device_name, strlen(device_name)+1);
			break;
		case CM_NETWORK:
			scanner->connectType = CT_NET_IPV4;
			memcpy(scanner->networkAddress, device_name, strlen(device_name)+1);
			break;
		default:
			std::cout << "Error. Invaild connectionMethod." << connection_method << std::endl;
			*pErrCode = 1;
			return FALSE;
		}

		return TRUE;
}


BOOL SCAN_SAVE(const char* device_name, int argc, char *argv[], const connectionMethod connection_method , DWORD* pErrCode)
{

	DWORD instance = 0;
	CEslStub eslib(NULL);

	//
	// Initialize Library
	//
	BOOL ret = eslib.eslInit(&instance, LICENSE_KEY, pErrCode);
	if (ret) {

		ConnectInfo scanner = {};

		ret = Setup_ConnectInfo(device_name, connection_method, &scanner, pErrCode);

		//
		// Open Scanner
		//
		ret = eslib.eslOpenScanner(instance, &scanner, pErrCode);
		if (ret) {
			//
			// Update Scan Basic parameters
			//
			EslParamScanExV1 scan_params;
			scan_params.type = ESL_PARAM_SCAN_EX_V1;
			scan_params.size = sizeof(scan_params);

			//
			// Update Save Basic parameters
			//
			EslParamSaveBasic save_params;
			save_params.type = ESL_PARAM_SAVE_BASIC;
			save_params.size = sizeof(save_params);

			bool doOBR = false;
			bool doOCR  = false;

			// Get Scan current parameters
			ret = eslib.eslCtrlParameter(instance, POT_GET_CURRENT, (pEslParamHdr)&scan_params, pErrCode);
			if (ret){

				// Get Save current parameters
				ret = eslib.eslCtrlParameter(instance, POT_GET_CURRENT, (pEslParamHdr)&save_params, pErrCode);

				if (ret){
					// Change some parameters...
					strncpy((char *)save_params.filePath, SAVE_PATH, sizeof(save_params.filePath));
					strncpy((char *)save_params.fileNamePrefix, SAVE_FILE_NAME, sizeof(save_params.fileNamePrefix));
				
					int i = 1;

					while(i < argc){

						// Scan parameters
						if(strcmp(argv[i], OPTION_MODE) == 0){
							std::cout << "--mode option." << std::endl;

							if (Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
								i++;
								scan_params.imgType = (eImageType)atoi(argv[i]);
							}else{
								std::cout << "--mode option err: " << *pErrCode << std::endl;
								goto Exit;
							}
						
						}else if(strcmp(argv[i], OPTION_SOURCE) == 0){
							std::cout << "--source option." << std::endl;

							if (Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
								i++;
								scan_params.docSource = (eDocSource)atoi(argv[i]);
							}else{
								std::cout << "--source option err: " << *pErrCode << std::endl;
								goto Exit;
							}
							
						
						}else if(strcmp(argv[i], OPTION_DEFICIENCY_CORRECTION) == 0){
							std::cout << "--edge-correction option." << std::endl;

							if (Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
								i++;
								scan_params.deficiencyCorrection = (BOOL)atoi(argv[i]);
							}else{
								std::cout << "--edge-correction option err: " << *pErrCode << std::endl;
								goto Exit;
							}
							
						
						}
						else if(strcmp(argv[i], OPTION_SCAN_AREA) == 0){
							std::cout << "--scan-area option." << std::endl;

							if(Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
								i++;
								scan_params.docSize = (eDocSize)atoi(argv[i]);

								if(scan_params.docSize == DS_USER){

									BOOL x_area_flag = FALSE;
									BOOL y_area_flag = FALSE;

									scan_params.sizeUnit = SU_MILLIMETER;
									std::cout << "argv[i+1] = " << argv[i+1] << std::endl;
									
									while(argv[i+1] && (strcmp(argv[i+1],"-l") == 0 || strcmp(argv[i+1],"-t") == 0 || strcmp(argv[i+1],"-x") == 0 || strcmp(argv[i+1],"-y") == 0)){
										i++;
										std::cout << "while argv[i+1] = " << argv[i+1] << std::endl;
										if(Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
											if(strcmp(argv[i],"-l") == 0){
												scan_params.sizeUser.left = atoi(argv[i+1]);
												i++;
											}else if(strcmp(argv[i],"-t") == 0){
												scan_params.sizeUser.top = atoi(argv[i+1]);
												i++;
											}else if(strcmp(argv[i],"-x") == 0){
												scan_params.sizeUser.right = atoi(argv[i+1]);
												i++;
												x_area_flag = TRUE;
											}else if(strcmp(argv[i],"-y") == 0){
												scan_params.sizeUser.bottom = atoi(argv[i+1]);
												i++;
												y_area_flag = TRUE;
											}
										}else{
											std::cout << "user area parameter err: " << *pErrCode << std::endl;
											goto Exit;
										}
									}
									if (!x_area_flag || !y_area_flag){
										*pErrCode = 1;
										std::cout << "user area option err: " << *pErrCode << std::endl;
										std::cout << "When specifying user size, be sure to specify area with the -x and -y options, as shown below." << std::endl;
										std::cout << "sdksample --scan [Device ID] --scan-area 0 -x 21000 -y 29700" << std::endl;
										goto Exit;
									}
									
								}	

							}else{
								std::cout << "--scan-area option err: " << *pErrCode << std::endl;
								goto Exit;
							}							
						
						}else if(strcmp(argv[i], OPTION_EDGE_FILL) == 0){
							std::cout << "--edge-fill option." << std::endl;

							if(Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
								i++;
								scan_params.edgeFill = (eEdgeFill)atoi(argv[i]);

								if(scan_params.edgeFill == EF_WHITE || scan_params.edgeFill == EF_BLACK){
									
									while(argv[i+1] && (strcmp(argv[i+1],"-l") == 0 || strcmp(argv[i+1],"-t") == 0 || strcmp(argv[i+1],"-r") == 0 || strcmp(argv[i+1],"-b") == 0)){
										i++;
										std::cout << "while argv[i] = " << argv[i] << std::endl;
										std::cout << "while argv[i + 1] = " << argv[i+1] << std::endl;
										if(Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
											if(strcmp(argv[i],"-l") == 0){
												scan_params.edgeFillLeft = atoi(argv[i+1]);
												i++;
											}else if(strcmp(argv[i],"-t") == 0){
												scan_params.edgeFillTop = atoi(argv[i+1]);
												i++;
											}else if(strcmp(argv[i],"-r") == 0){
												scan_params.edgeFillRight = atoi(argv[i+1]);
												i++;
											}else if(strcmp(argv[i],"-b") == 0){
												scan_params.edgeFillBottom = atoi(argv[i+1]);
												i++;
											}
										}else{
											std::cout << "user area parameter err: " << *pErrCode << std::endl;
											goto Exit;
										}
									}
								}	
							}else{
								std::cout << "---edge-fill option err: " << *pErrCode << std::endl;
								goto Exit;
							}							
						
						}else if(strcmp(argv[i], OPTION_RESOLUTION) == 0){
							std::cout << "--resolution option." << std::endl;

							if (Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
								i++;
								scan_params.resolution = atoi(argv[i]);
							}else{
								std::cout << "--resolution option err: " << *pErrCode << std::endl;
								goto Exit;
							}

						}else if(strcmp(argv[i], OPTION_ROTATE) == 0){
							std::cout << "--rotate option." << std::endl;

							if (Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
								i++;
								scan_params.docRotate = (eDocRotate)atoi(argv[i]);
							}else{
								std::cout << "--rotate option err: " << *pErrCode << std::endl;
								goto Exit;
							}

						}else if(strcmp(argv[i], OPTION_BRIGHTNESS) == 0){
							std::cout << "--brightness option." << std::endl;

							if (Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
								i++;
								scan_params.brightness = atoi(argv[i]);
							}else{
								std::cout << "--brightness option err: " << *pErrCode << std::endl;
								goto Exit;
							}

						}else if(strcmp(argv[i], OPTION_CONTRAST) == 0){
							std::cout << "--contrast option." << std::endl;

							if (Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
								i++;
								scan_params.contrast = atoi(argv[i]);
							}else{
								std::cout << "--contrast option err: " << *pErrCode << std::endl;
								goto Exit;
							}						
						}else if(strcmp(argv[i], OPTION_THRESHOLD) == 0){
							std::cout << "--threshold option." << std::endl;

							if (Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
								i++;
								scan_params.threshold = atoi(argv[i]);
							}else{
								std::cout << "--threshold option err: " << *pErrCode << std::endl;
								goto Exit;
							}

						}else if(strcmp(argv[i], OPTION_DROPOUT) == 0){
							std::cout << "--dropout option." << std::endl;

							if (Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
								i++;
								scan_params.colorFilter = (eColorFilter)atoi(argv[i]);
							}else{
								std::cout << "--dropout option err: " << *pErrCode << std::endl;
								goto Exit;
							}		

						}else if(strcmp(argv[i], OPTION_BLANKPAGE_SKIP) == 0){
							std::cout << "--blankpage-skip option." << std::endl;

							if (Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
								i++;
								scan_params.optBlankPageSkip = (eBPSkip)atoi(argv[i]);
							}else{
								std::cout << "--blankpage-skip option err: " << *pErrCode << std::endl;
								goto Exit;
							}

						}else if(strcmp(argv[i], OPTION_DOUBLE_FEED_DETECTION) == 0){
							std::cout << "--double-feed-detection option." << std::endl;

							if (Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
								i++;
								scan_params.optDoubleFeedDetect = (eDFDetect)atoi(argv[i]);
							}else{
								std::cout << "--double-feed-detection option err: " << *pErrCode << std::endl;
								goto Exit;
							}

						}
						// Save parameters			
						else if(strcmp(argv[i], OPTION_IMAGE_FORMAT) == 0){
							std::cout << "--image-format option." << std::endl;

							if (Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
								i++;
								save_params.fileFormat = (eFileFormat)atoi(argv[i]);
							}else{
								std::cout << "--image-format option err: " << *pErrCode << std::endl;
								goto Exit;
							}
						}
						// PDF parameters			
						else if(strcmp(argv[i], OPTION_PDF_PARAM) == 0){
							std::cout << "--pdf-paramater option." << std::endl;
							if (argv[i+1]){
								EslParamSavePDF pdf_params;
								pdf_params.type = ESL_PARAM_SAVE_PDF;
								pdf_params.size = sizeof(EslParamSavePDF);
								ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&pdf_params, pErrCode);

								while(argv[i+1] && 
									(
										strcmp(argv[i+1],"-s") == 0 
									)
								){
									i++;
									//std::cout << "while argv[i+1] = " << argv[i+1] << std::endl;
									if(Parameter_Check(argv[i+1], CO_VALUE, pErrCode))
									{
										if(strcmp(argv[i],"-s") == 0)
										{
											std::cout << "searchable set:" << argv[i+1] << std::endl;
											pdf_params.addOcrText = atoi(argv[i+1]);
											i++;
										}
									}
									else
									{
										std::cout << "parameter err: " << *pErrCode << std::endl;
										goto Exit;
									}
								}

								ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&pdf_params, pErrCode);
							}
						}// OBR parameters			
						else if(strcmp(argv[i], OPTION_OBR) == 0){
                            std::cout << "--obr option." << std::endl;
							doOBR = true;
							if (argv[i+1]){
								EslParamOBRBasic obr_params;
								obr_params.type = ESL_PARAM_OBR_BASIC;
								obr_params.size = sizeof(EslParamOBRBasic);
								ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&obr_params, pErrCode);

								while(argv[i+1] && 
									(
										strcmp(argv[i+1],"-l") == 0 || 
										strcmp(argv[i+1],"-t") == 0 || 
										strcmp(argv[i+1],"-r") == 0 || 
										strcmp(argv[i+1],"-b") == 0 ||
										strcmp(argv[i+1],"-s") == 0 ||
										strcmp(argv[i+1],"-e") == 0 ||
										strcmp(argv[i+1],"-d") == 0 ||
										strcmp(argv[i+1],"-p") == 0 ||
										strcmp(argv[i+1],"-o") == 0 ||
										strcmp(argv[i+1],"-u") == 0
									)
								){
									i++;
									//std::cout << "while argv[i+1] = " << argv[i+1] << std::endl;
									if(Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
										if(strcmp(argv[i],"-l") == 0){
											std::cout << "detectRect.left set:" << argv[i+1] << std::endl;
											obr_params.detectRect.left = atoi(argv[i+1]);
											i++;
										}else if(strcmp(argv[i],"-t") == 0){
											std::cout << "detectRect.top set:" << argv[i+1] << std::endl;
											obr_params.detectRect.top = atoi(argv[i+1]);
											i++;
										}else if(strcmp(argv[i],"-r") == 0){
											std::cout << "detectRect.right set:" << argv[i+1] << std::endl;
											obr_params.detectRect.right = atoi(argv[i+1]);
											i++;
										}else if(strcmp(argv[i],"-b") == 0){
											std::cout << "detectRect.bottom set:" << argv[i+1] << std::endl;
											obr_params.detectRect.bottom = atoi(argv[i+1]);
											i++;
										}else if(strcmp(argv[i],"-s") == 0){
											std::cout << "numPageStart set:" << argv[i+1] << std::endl;
											obr_params.numPageStart = atoi(argv[i+1]);
											i++;
										}else if(strcmp(argv[i],"-e") == 0){
											std::cout << "numPageEnd set:" << argv[i+1] << std::endl;
											obr_params.numPageEnd = atoi(argv[i+1]);
											i++;
										}else if(strcmp(argv[i],"-d") == 0){
											std::cout << "numDecode set:" << argv[i+1] << std::endl;
											obr_params.numDecode = atoi(argv[i+1]);
											i++;
										}else if(strcmp(argv[i],"-p") == 0){
											std::cout << "symbolType set:" << argv[i+1] << std::endl;
											obr_params.symbolType = atoi(argv[i+1]);
											i++;
										}else if(strcmp(argv[i],"-o") == 0){
											std::cout << "orientation set:" << argv[i+1] << std::endl;
											obr_params.orientation = (eBCOrientation)atoi(argv[i+1]);
											i++;
										}else if(strcmp(argv[i],"-u") == 0){
											std::cout << "detectUnit set:" << argv[i+1] << std::endl;
											obr_params.detectUnit = (eSizeUnit)atoi(argv[i+1]);
											i++;
										}
									}else{
										std::cout << "user area parameter err: " << *pErrCode << std::endl;
										goto Exit;
									}
								}

								ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&obr_params, pErrCode);

							}
									
						}else if(strcmp(argv[i], OPTION_OCR) == 0){
                            std::cout << "--ocr option." << std::endl;
							doOCR = true;
							if (argv[i+1]){
								EslParamOCRBasic ocr_params;
								ocr_params.type = ESL_PARAM_OCR_BASIC;
								ocr_params.size = sizeof(EslParamOCRBasic);
								ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&ocr_params, pErrCode);
								while(argv[i+1] && 
									(
										strcmp(argv[i+1],"-g") == 0 || 
										strcmp(argv[i+1],"-l") == 0 || 
										strcmp(argv[i+1],"-t") == 0 || 
										strcmp(argv[i+1],"-r") == 0 ||
										strcmp(argv[i+1],"-b") == 0 ||
										strcmp(argv[i+1],"-s") == 0 ||
										strcmp(argv[i+1],"-e") == 0 ||
										strcmp(argv[i+1],"-u") == 0
									)
								){
									i++;
									//std::cout << "while argv[i+1] = " << argv[i+1] << std::endl;
									if(Parameter_Check(argv[i+1], CO_VALUE, pErrCode)){
										if(strcmp(argv[i],"-g") == 0){
											std::cout << "ocrLanguage set:" << argv[i+1] << std::endl;
											ocr_params.ocrLanguage = (eOCRLanguage)atoi(argv[i+1]);
											i++;
										}else if(strcmp(argv[i],"-l") == 0){
											std::cout << "detectRect.left set: " << argv[i+1] << std::endl;
											ocr_params.detectRect.left = atoi(argv[i+1]);
											i++;
										}else if(strcmp(argv[i],"-t") == 0){
											std::cout << "detectRect.top set: " << argv[i+1] << std::endl;
											ocr_params.detectRect.top = atoi(argv[i+1]);
											i++;
										}else if(strcmp(argv[i],"-r") == 0){
											std::cout << "detectRect.right set: " << argv[i+1] << std::endl;
											ocr_params.detectRect.right = atoi(argv[i+1]);
											i++;
										}else if(strcmp(argv[i],"-b") == 0){
											std::cout << "detectRect.bottom set: " << argv[i+1] << std::endl;
											ocr_params.detectRect.bottom = atoi(argv[i+1]);
											i++;
										}else if(strcmp(argv[i],"-s") == 0){
											std::cout << "numPageStart set: " << argv[i+1] << std::endl;
											ocr_params.numPageStart = atoi(argv[i+1]);
											i++;
										}else if(strcmp(argv[i],"-e") == 0){
											std::cout << "numPageEnd set: " << argv[i+1] << std::endl;
											ocr_params.numPageEnd = atoi(argv[i+1]);
											i++;
										}else if(strcmp(argv[i],"-u") == 0){
											std::cout << "detectUnit set: " << argv[i+1] << std::endl;
											ocr_params.detectUnit = (eSizeUnit)atoi(argv[i+1]);
											i++;
										}
									}else{
										std::cout << "user area parameter err: " << *pErrCode << std::endl;
										goto Exit;
									}
								}

								std::cout << "ocr lang " << ocr_params.ocrLanguage << std::endl;
								ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&ocr_params, pErrCode);
							}
									
						}

						i++;
					}

					// Set Scan parameters
					ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&scan_params, pErrCode);

					if (ret){
						// Set Save parameters
						ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&save_params, pErrCode);

					}else{
						std::cout << "[ERROR]scan_params eslCtrlParameter(POT_SET) err: " << *pErrCode << std::endl;
						goto Exit;
					}
				}else{
					std::cout << "[ERROR]save_params eslCtrlParameter(POT_GET_DEFAULT) err: " << *pErrCode << std::endl;
					goto Exit;					
				}
			}else{
				std::cout << "[ERROR]scan_params eslCtrlParameter(POT_GET_DEFAULT) err: " << *pErrCode << std::endl;
				goto Exit;
			}
			
			if (ret) {
				// Scan start(Scan and Store)
				ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, pErrCode);
				if (ret){

					if(doOBR){
						// OBR Recogunize Start
						if(!eslib.eslExecute(instance, ET_GET_OBR_DATA, eslCallback, NULL, pErrCode)){
							std::cout << "[ERROR]eslExecute(ET_GET_OBR_DATA) err: " << *pErrCode << std::endl;
							goto Exit;
						}
					}

					if (doOCR){
						if(!eslib.eslExecute(instance, ET_GET_OCR_DATA, eslCallback, NULL, pErrCode)){
							std::cout << "[ERROR]eslExecute(ET_GET_OCR_DATA) err: " << *pErrCode << std::endl;
							goto Exit;
						}
					}


					// Scan start(Save stored images)
					if (!eslib.eslExecute(instance, ET_SAVE_STORED_IMAGE, eslCallback, NULL, pErrCode)){
						std::cout << "[ERROR]eslExecute(ET_SAVE_STORED_IMAGE) err: " << *pErrCode << std::endl;
						goto Exit;
					}

									
				}else{
					std::cout << "[ERROR]eslExecute(ET_SCAN_AND_STORE) err: " << *pErrCode << std::endl;
					goto Exit;
				}
			}else{
				std::cout << "[ERROR]save_params eslCtrlParameter(POT_SET) err: " << *pErrCode << std::endl;
				goto Exit;
			}

		}else{
			std::cout << "[ERROR]eslOpenScanner err: " << *pErrCode << std::endl;
		}

	}else{
		std::cout << "[ERROR]eslInit err: " << *pErrCode << std::endl;
	}

Exit:

	if (*pErrCode != ESL_SUCCESS){
		return FALSE;
	}

	eslib.eslCloseScanner(instance, pErrCode);
	eslib.eslFree(instance, pErrCode);
	
	return TRUE;

}

DWORD SCAN_SAVE_Default(const char* device_name)
{
	std::cout << "[INFO]SCAN_SAVE_Default" << std::endl;
	DWORD instance = 0;
	DWORD err = 0;

	CEslStub eslib(NULL);

	//
	// Initialize Library
	//
	BOOL ret = eslib.eslInit(&instance, LICENSE_KEY, &err);
	if (ret) {

		//
		// Open Scanner
		//
		//// Connect to USB ////
		ConnectInfo scanner = {CT_DEFAULT}; // specify connection type and device name
		memcpy(scanner.deviceName, device_name, strlen(device_name)+1);
		//// Connect to Network ////
		//ConnectInfo scanner = {CT_NET_IPV4, "", IP_ADDRESS};
		//memcpy(scanner.deviceName, device_name, strlen(device_name)+1);

		ret = eslib.eslOpenScanner(instance, &scanner, &err);
		if (ret) {
			if (ret) {
				// Scan start(Scan and Save)
				ret = eslib.eslExecute(instance, ET_SCAN_AND_SAVE, eslCallback, NULL, &err);
			}

			// Close scanner
			ret = eslib.eslCloseScanner(instance, &err);
		}

		// Free Library
		eslib.eslFree(instance, &err);
	}

	return err;
}

DWORD SCN_Get_Setting_Parameter(const char* device_name, eSpecifiedParameter SpecifiedParameter, INT* select, const connectionMethod connection_method, DWORD* pErrCode){
	DWORD instance = 0;

	CEslStub eslib(NULL);
	//
	// Initialize Library
	//
	if (!eslib.eslInit(&instance, LICENSE_KEY, pErrCode)){
		std::cout << "[ERROR]SCN_Get_Setting_Parameter eslInit err: " << *pErrCode << std::endl;
		return FALSE;
	}

	//
	// Open Scanner
	//
	ConnectInfo scanner = {}; // specify connection type and device name

	if (!Setup_ConnectInfo(device_name, connection_method, &scanner, pErrCode)){
		std::cout << "[ERROR]SCN_Get_Setting_Parameter Setup_ConnectInfo err: " << *pErrCode << std::endl;
		return FALSE;
	}

	if (!eslib.eslOpenScanner(instance, &scanner, pErrCode)){
		std::cout << "[ERROR]SCN_Get_Setting_Parameter eslOpenScanner err: " << *pErrCode << std::endl;
		if(!eslib.eslFree(instance, pErrCode)){
			std::cout << "[ERROR]SCN_Get_Setting_Parameter eslFree err: " << *pErrCode << std::endl;
		}
		return FALSE;	
	}

	// Get Setting Parameter
	if (!eslib.eslGetSettingParameter(instance, SpecifiedParameter, pErrCode, select)){
		std::cout << "[ERROR]SCN_Get_Setting_Parameter eslGetSettingParameter err: " << *pErrCode << std::endl;
		if(!eslib.eslCloseScanner(instance, pErrCode)){
			std::cout << "[ERROR]SCN_Get_Setting_Parameter eslCloseScanner err: " << *pErrCode << std::endl;
		}
		if(!eslib.eslFree(instance, pErrCode)){
			std::cout << "[ERROR]SCN_Get_Setting_Parameter eslFree err: " << *pErrCode << std::endl;
		}
		return FALSE;
	}

	// Close scanner
	if(!eslib.eslCloseScanner(instance, pErrCode)){
		std::cout << "[ERROR]SCN_Get_Setting_Parameter eslCloseScanner err: " << *pErrCode << std::endl;
		return FALSE;
	}
	// Free Library
	if(!eslib.eslFree(instance, pErrCode)){
		std::cout << "[ERROR]SCN_Get_Setting_Parameter eslFree err: " << *pErrCode << std::endl;
		return FALSE;
	}

	return TRUE;

}


DWORD SCN_Set_Setting_Parameter(const char* device_name, eSpecifiedParameter SpecifiedParameter, const INT setparam, const connectionMethod connection_method, DWORD* pErrCode)
{

	DWORD instance = 0;
	CEslStub eslib(NULL);
	
	//
	// Initialize Library
	//

	if (!eslib.eslInit(&instance, LICENSE_KEY, pErrCode)){
		std::cout << "[ERROR]SCN_Set_Setting_Parameter eslInit err: " << *pErrCode << std::endl;
		return FALSE;
	}
	
	//
	// Open Scanner
	//	
	ConnectInfo scanner = {}; // specify connection type and device name

	if (!Setup_ConnectInfo(device_name, connection_method, &scanner, pErrCode)){
		std::cout << "[ERROR]SCN_Set_Setting_Parameter Setup_ConnectInfo err: " << *pErrCode << std::endl;
		return FALSE;
	}

	if (!eslib.eslOpenScanner(instance, &scanner, pErrCode)){
		std::cout << "[ERROR]SCN_Set_Setting_Parameter eslOpenScanner err: " << *pErrCode << std::endl;
		if(!eslib.eslFree(instance, pErrCode)){
			std::cout << "[ERROR]SCN_Set_Setting_Parameter eslFree err: " << *pErrCode << std::endl;
		}
		return FALSE;
		
	}

	// Set Setting Parameter
	if (!eslib.eslSetSettingParameter(instance, SpecifiedParameter, pErrCode, setparam)){
		std::cout << "[ERROR]SCN_Set_Setting_Parameter eslSetSettingParameter err: " << *pErrCode << std::endl;
		if(!eslib.eslCloseScanner(instance, pErrCode)){
			std::cout << "[ERROR]SCN_Set_Setting_Parameter eslCloseScanner err: " << *pErrCode << std::endl;
		}
		if(!eslib.eslFree(instance, pErrCode)){
			std::cout << "[ERROR]SCN_Set_Setting_Parameter eslFree err: " << *pErrCode << std::endl;
		}
		return FALSE;
	}

	// Close scanner
	if(!eslib.eslCloseScanner(instance, pErrCode)){
		std::cout << "[ERROR]SCN_Set_Setting_Parameter eslCloseScanner err: " << *pErrCode << std::endl;
		return FALSE;
	}
	// Free Library
	if(!eslib.eslFree(instance, pErrCode)){
		std::cout << "[ERROR]SCN_Set_Setting_Parameter eslFree err: " << *pErrCode << std::endl;
		return FALSE;
	}
	

	return TRUE;
}

BOOL SCN_Get_Device_Status(const char* device_name, const connectionMethod connection_method, DWORD* pErrCode){
	
	DWORD instance = 0;
	CEslStub eslib(NULL);

	//
	// Initialize Library
	//
	if (!eslib.eslInit(&instance, LICENSE_KEY, pErrCode)){
		std::cout << "[ERROR]SCN_Get_Device_Status eslInit err: " << *pErrCode << std::endl;
		return FALSE;
	}

	//
	// Open Scanner
	//
	ConnectInfo scanner = {}; // specify connection type and device name

	if (!Setup_ConnectInfo(device_name, connection_method, &scanner, pErrCode)){
		std::cout << "[ERROR]SCN_Set_Setting_Parameter Setup_ConnectInfo err: " << *pErrCode << std::endl;
		return FALSE;
	}

	if (!eslib.eslOpenScanner(instance, &scanner, pErrCode)){
		std::cout << "[ERROR]SCN_Get_Device_Status eslOpenScanner err: " << *pErrCode << std::endl;
		if(!eslib.eslFree(instance, pErrCode)){
			std::cout << "[ERROR]SCN_Get_Device_Status eslFree err: " << *pErrCode << std::endl;
		}
		return FALSE;
		
	}

	//status = Device status
	DWORD status = 0;
	if(!eslib.eslGetDeviceStatus(instance, &status, pErrCode)){
		std::cout << "[ERROR]SCN_Get_Device_Status eslGetDeviceStatus err: " << *pErrCode << std::endl;
		if(!eslib.eslCloseScanner(instance, pErrCode)){
			std::cout << "[ERROR]SCN_Get_Device_Status eslCloseScanner err: " << *pErrCode << std::endl;
		}
		if(!eslib.eslFree(instance, pErrCode)){
			std::cout << "[ERROR]SCN_Get_Device_Status eslFree err: " << *pErrCode << std::endl;
		}
		return FALSE;
	}
	DISPLAY_DEVICE_STATUS(status);

	// Close scanner
	if(!eslib.eslCloseScanner(instance, pErrCode)){
		std::cout << "[ERROR]SCN_Get_Device_Status eslCloseScanner err: " << *pErrCode << std::endl;
		return FALSE;
	}
	// Free Library
	if(!eslib.eslFree(instance, pErrCode)){
		std::cout << "[ERROR]SCN_Get_Device_Status eslFree err: " << *pErrCode << std::endl;
		return FALSE;
	}

	return TRUE;
}


DWORD SCAN_STORE_SAVE_Default(const char* device_name)
{
	DWORD instance = 0;
	DWORD err = 0;

	CEslStub eslib(NULL);

	//
	// Initialize Library
	//
	BOOL ret = eslib.eslInit(&instance, LICENSE_KEY, &err);
	if (ret) {

		//
		// Open Scanner
		//
		ConnectInfo scanner = {CT_DEFAULT}; // specify connection type and device name
		memcpy(scanner.deviceName, device_name, strlen(device_name)+1);	
		ret = eslib.eslOpenScanner(instance, &scanner, &err);
		if (ret) {

			EslParamInfoBasic info_params;
			info_params.type = ESL_PARAM_INFO_BASIC;
			info_params.size = sizeof(info_params);

			// Get default parameters
			ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&info_params, &err);
			std::cout << "[INFO]Serial No: " << info_params.serialNumber << std::endl;

			if (ret) {
				// Scan start(Scan and Store)
				ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
			}

			if (ret) {
				// Scan start(Save stored images)
				ret = eslib.eslExecute(instance, ET_SAVE_STORED_IMAGE, eslCallback, NULL, &err);
			}

			//status = Device status
			DWORD status = 0;
			ret = eslib.eslGetDeviceStatus(instance, &status, &err);
			DISPLAY_DEVICE_STATUS(status);

			// Close scanner
			ret = eslib.eslCloseScanner(instance, &err);
		}

		// Free Library
		eslib.eslFree(instance, &err);
	}

	return err;
}

DWORD SCAN_SAVE_JPEG(const char* device_name)
{
	DWORD instance = 0;
	DWORD err = 0;

	CEslStub eslib(NULL);

	//
	// Initialize Library
	//
	BOOL ret = eslib.eslInit(&instance, LICENSE_KEY, &err);
	if (ret) {

		//
		// Open Scanner
		//
		ConnectInfo scanner = {CT_DEFAULT}; // specify connection type and device name
		memcpy(scanner.deviceName, device_name, strlen(device_name)+1);
		ret = eslib.eslOpenScanner(instance, &scanner, &err);
		if (ret) {
			//
			// Update Scan Basic parameters
			//
			EslParamScanExV1 scan_params;
			scan_params.type = ESL_PARAM_SCAN_EX_V1;
			scan_params.size = sizeof(scan_params);

			// Get default parameters
			ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&scan_params, &err);

			// Change some parameters...
			if (ret) {
				scan_params.docSource = SRC_FLATBED;
				scan_params.imgType = IT_COLOR;
				scan_params.resolution = 300;
				scan_params.docSize = DS_A4;
				//scan_params.sizeUnit = SU_MILLIMETER;
				//scan_params.sizeUser.left = 0;
				//scan_params.sizeUser.top = 0;
				//scan_params.sizeUser.right = 21000;
				//scan_params.sizeUser.bottom = 29700;
				scan_params.docRotate = DR_NONE;
				scan_params.brightness = 0;
				scan_params.contrast = 0;
				scan_params.threshold = 128;
				scan_params.colorFilter = CF_NONE;
				scan_params.numScan = 0;

				scan_params.optDoubleFeedDetect = DFD_NONE;
				scan_params.optBlankPageSkip = BPS_NONE;
				scan_params.skewCorrect = SC_EDGE;

				// Set parameters
				ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&scan_params, &err);
			}

			//
			// Update Save Basic parameters
			//
			EslParamSaveBasic save_params;
			save_params.type = ESL_PARAM_SAVE_BASIC;
			save_params.size = sizeof(save_params);

			// Get default parameters
			if (ret) {
				ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&save_params, &err);
			}

			// Change some parameters...
			if (ret) {
				save_params.fileFormat = FF_JPEG;
				strncpy((char *)save_params.filePath, ".", sizeof(save_params.filePath));
				strncpy((char *)save_params.fileNamePrefix, "img", sizeof(save_params.fileNamePrefix));
				save_params.fileNumStartCount = 1;
				save_params.numPageStart = 0;
				save_params.numPageEnd = 0;

				// Set parameters
				ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&save_params, &err);
			}

			//
			// Update JPEG file parameters
			//
			EslParamSaveJPEG jpeg_params;
			jpeg_params.type = ESL_PARAM_SAVE_JPEG;
			jpeg_params.size = sizeof(jpeg_params);

			// Get default parameters
			if (ret) {
				ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&jpeg_params, &err);
			}

			// Change some parameters...
			if (ret) {
				jpeg_params.imgQuality = 90;
				jpeg_params.encProgressive = FALSE;

				// Set parameters
				ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&jpeg_params, &err);
			}

			//
			// Update TIFF file parameters
			//
			EslParamSaveTIFF tiff_params;
			tiff_params.type = ESL_PARAM_SAVE_TIFF;
			tiff_params.size = sizeof(tiff_params);

			// Get default parameters
			if (ret) {
				ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&tiff_params, &err);
			}

			// Change some parameters...
			if (ret) {
				tiff_params.compMono = TC_NONE;

				// Set parameters
				ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&tiff_params, &err);
			}

			if (ret) {
				// Scan start(Scan and Store)
				ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
				//ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
				//ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
				//ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
				//ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
			}

			if (ret) {
				// Scan start(Save stored images)
				ret = eslib.eslExecute(instance, ET_SAVE_STORED_IMAGE, eslCallback, NULL, &err);
			}

			// Close scanner
			ret = eslib.eslCloseScanner(instance, &err);
		}

		// Free Library
		eslib.eslFree(instance, &err);
	}

	return err;
}

DWORD SCAN_SAVE_PDF(const char* device_name)
{
	DWORD instance = 0;
	DWORD err = 0;

	CEslStub eslib(NULL);

	//
	// Initialize Library
	//
	BOOL ret = eslib.eslInit(&instance, LICENSE_KEY, &err);
	if (ret) {

		//
		// Open Scanner
		//
		ConnectInfo scanner = {CT_DEFAULT}; // specify connection type and device name
		memcpy(scanner.deviceName, device_name, strlen(device_name)+1);
		ret = eslib.eslOpenScanner(instance, &scanner, &err);
		if (ret) {
			//
			// Update Scan Basic parameters
			//
			EslParamScanExV1 scan_params;
			scan_params.type = ESL_PARAM_SCAN_BASIC;
			scan_params.size = sizeof(scan_params);

			// Get default parameters
			ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&scan_params, &err);

			// Change some parameters...
			if (ret) {
				scan_params.docSource = SRC_AUTO;
				scan_params.imgType = IT_COLOR;
				scan_params.resolution = 300;
				scan_params.docSize = DS_A4;
				//scan_params.sizeUnit = SU_INCH;
				//scan_params.sizeUser.left = 0;
				//scan_params.sizeUser.top = 0;
				//scan_params.sizeUser.right = 500;
				//scan_params.sizeUser.bottom = 500;
				scan_params.docRotate = DR_AUTO;
				scan_params.brightness = 0;
				scan_params.contrast = 0;
				scan_params.threshold = 110;
				scan_params.colorFilter = CF_NONE;
				scan_params.numScan = 5;

				// Set parameters
				ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&scan_params, &err);
			}

			//
			// Update Save Basic parameters
			//
			EslParamSaveBasic save_params;
			save_params.type = ESL_PARAM_SAVE_BASIC;
			save_params.size = sizeof(save_params);

			// Get default parameters
			if (ret) {
				ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&save_params, &err);
			}

			// Change some parameters...
			if (ret) {
				save_params.fileFormat = FF_PDF;
				strncpy((char *)save_params.filePath, ".", sizeof(save_params.filePath));
				strncpy((char *)save_params.fileNamePrefix, "img", sizeof(save_params.fileNamePrefix));
				save_params.fileNumStartCount = 1;
				//Saved : page2 - page4
				save_params.numPageStart = 0;
				save_params.numPageEnd = 0;

				// Set parameters
				ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&save_params, &err);
			}

						//
			// Update PDF file parameters
			//
			EslParamSavePDF pdf_params;
			pdf_params.type = ESL_PARAM_SAVE_PDF;
			pdf_params.size = sizeof(pdf_params);

						// Get default parameters
			if (ret) {
				ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&pdf_params, &err);
			}

			// Change some parameters...
			if (ret) {
				pdf_params.pdfType = PT_NORMAL;
				pdf_params.addOcrText = false;
				pdf_params.ocrLanguage = OL_NONE;

				// Set parameters
				ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&pdf_params, &err);
			}

			if (ret) {
				// Scan start(Scan and Save)
				ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
				//ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
				//ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
				//ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
				//ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
				ret = eslib.eslExecute(instance, ET_SAVE_STORED_IMAGE, eslCallback, NULL, &err);
			}

			// Close scanner
			ret = eslib.eslCloseScanner(instance, &err);
		}

		// Free Library
		eslib.eslFree(instance, &err);
	}

	return err;
}

DWORD SCAN_SAVE_OFD(const char* device_name)
{
	DWORD instance = 0;
	DWORD err = 0;

	
	CEslStub eslib(NULL);

	//
	// Initialize Library
	//
	BOOL ret = eslib.eslInit(&instance, LICENSE_KEY, &err);
	if (ret) {

		//
		// Open Scanner
		//
		std::cout << "[INFO]Open Scanner\n" << std::endl;
		ConnectInfo scanner = {CT_DEFAULT}; // specify connection type and device name
		memcpy(scanner.deviceName, device_name, strlen(device_name)+1);
		ret = eslib.eslOpenScanner(instance, &scanner, &err);
		if (ret) {
			//
			// Update Scan Basic parameters
			//
			std::cout << "[INFO]Update Scan Basic parameters\n" << std::endl;
			EslParamScanExV1 scan_params;
			scan_params.type = ESL_PARAM_SCAN_BASIC;
			scan_params.size = sizeof(scan_params);
			
			std::cout << "[INFO]Get default parameters\n" << std::endl;
			// Get default parameters
			ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&scan_params, &err);

			// Change some parameters...
			if (ret) {
				std::cout << "[INFO]Change some parameters...\n" << std::endl;

				scan_params.docSource = SRC_AUTO;
				scan_params.imgType = IT_COLOR;
				scan_params.resolution = 200;
				scan_params.docSize = DS_A4;
				//scan_params.sizeUnit = SU_INCH;
				//scan_params.sizeUser.left = 0;
				//scan_params.sizeUser.top = 0;
				//scan_params.sizeUser.right = 500;
				//scan_params.sizeUser.bottom = 500;
				scan_params.docRotate = DR_AUTO;
				scan_params.brightness = 0;
				scan_params.contrast = 0;
				scan_params.threshold = 110;
				scan_params.colorFilter = CF_NONE;
				scan_params.numScan = 5;

				std::cout << "[INFO]Set parameters\n" << std::endl;
				// Set parameters
				ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&scan_params, &err);
			}

			//
			// Update Save Basic parameters
			//
			std::cout << "[INFO]Update Save Basic parameters\n" << std::endl;
			EslParamSaveBasic save_params;
			save_params.type = ESL_PARAM_SAVE_BASIC;
			save_params.size = sizeof(save_params);

			// Get default parameters
			if (ret) {
				std::cout << "[INFO]Get default parameters\n" << std::endl;
				ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&save_params, &err);
			}

			std::cout << "[INFO]Get default parameters ret = " << ret << std::endl;
			// Change some parameters...
			if (ret) {
				std::cout << "[INFO]Change some parameters...\n" << std::endl;
				save_params.fileFormat = FF_OFD;
				//save_params.fileFormat = FF_JPEG;
				std::cout << "[INFO]save_params.fileFormat = " << save_params.fileFormat << std::endl;
				//strncpy((char *)save_params.filePath, "./", sizeof(save_params.filePath));
				
				strncpy((char *)save_params.filePath, ".", sizeof(save_params.filePath));
				std::cout << "[INFO]save_params.filePath = " << save_params.filePath << std::endl;
				std::cout << "[INFO]sizeof(save_params.filePath) = " << sizeof(save_params.filePath) << std::endl;

	
				strncpy((char *)save_params.fileNamePrefix, "ofd_output", sizeof(save_params.fileNamePrefix));
				save_params.fileNumStartCount = 1;


				//Saved : page2 - page4
				save_params.numPageStart = 0;
				save_params.numPageEnd = 0;

				// Set parameters
				ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&save_params, &err);
			}

			if (ret) {
				std::cout << "[INFO]Scan start(Scan and Save)\n" << std::endl;
				// Scan start(Scan and Save)
				ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
				//ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
				//ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
				//ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
				//ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
				ret = eslib.eslExecute(instance, ET_SAVE_STORED_IMAGE, eslCallback, NULL, &err);
			}

			// Close scanner
			ret = eslib.eslCloseScanner(instance, &err);
		}

		// Free Library
		eslib.eslFree(instance, &err);
	}

	return err;
}

int APIENTRY main(int argc, char *argv[])
{
	char * device_name  = NULL;
	DWORD err = 0;

	int i = 1;

	connectionMethod connection_method = CM_USB;

	if (argc > MIN_ARGUMENTS){
		
		if (Parameter_Check(argv[i+1], CO_DEVICEID, &err)){

			size_t ip_prefix_length = strlen("IP:");
			size_t adjust_length = 0;

			if (strncmp(argv[i+1], "IP:", ip_prefix_length) == 0){
				adjust_length = ip_prefix_length;
				connection_method = CM_NETWORK;
			}

			device_name = (char*)malloc(strlen(argv[i+1]) - adjust_length + 1);
			memcpy(device_name, argv[i+1] + adjust_length, strlen(argv[i+1]) - adjust_length + 1);

			if(strcmp(argv[i], OPTION_SCAN) == 0 || strcmp(argv[i], OPTION_SCAN_S) == 0){
				std::cout << "--scan option." << std::endl;
				if(!SCAN_SAVE(device_name, argc, argv, connection_method, &err)){
					std::cout << "Scan error." << std::endl;
				}

			}else if(strcmp(argv[i], OPTION_GET_STATUS) == 0 || strcmp(argv[i], OPTION_GET_STATUS_S) == 0){
				std::cout << "--get-status option." << std::endl;
				if(!SCN_Get_Device_Status(device_name, connection_method, &err)){
					std::cout << "Get device status error." << std::endl;
				}

			}else if(strcmp(argv[i], OPTION_GET_SLEEPTIMER) == 0){

				std::cout << "--get-sleeptimer option." << std::endl;

				INT select = 0;
				if (SCN_Get_Setting_Parameter(device_name, SP_SLEEP_TIMER, &select, connection_method, &err)){
					std::cout << "sleeptimer setting for " << select << std::endl;
				}else{
					std::cout << "sleeptimer setting error" << std::endl;
				}

			}else if(strcmp(argv[i], OPTION_SET_SLEEPTIMER) == 0){

				std::cout << "--set-sleeptimer option." << std::endl;

				if (Parameter_Check(argv[i+2], CO_VALUE, &err)){

					INT setparam = atoi(argv[i+2]);
					if(SCN_Set_Setting_Parameter(device_name, SP_SLEEP_TIMER, setparam, connection_method, &err)){
						std::cout << "sleeptimer set success param: " << setparam << std::endl;
					}else{
						std::cout << "sleeptimer set error: " << std::endl;
					}

				}else{
					std::cout << "Parameter error. The value to be set is not a number." << std::endl;
					std::cout << "example: ./sdksample --set-sleeptimer 30(minute)" << std::endl;
					err = 1;
				}

			}else if(strcmp(argv[i], OPTION_GET_AUTOPWOFF) == 0){

				std::cout << "--get-autopwoff option." << std::endl;

				INT select = 0;
				if (SCN_Get_Setting_Parameter(device_name, SP_POWER_OFF_TIME, &select, connection_method, &err)){
					std::cout << "auto power off setting for " << select << std::endl;
				}else{
					std::cout << "auto power off setting error." << std::endl;
				}

			}else if(strcmp(argv[i], OPTION_SET_AUTOPWOFF) == 0){

				std::cout << "--set-autopwoff option." << std::endl;

				if (Parameter_Check(argv[i+2], CO_VALUE, &err)){

					INT setparam = atoi(argv[i+2]);
					if(SCN_Set_Setting_Parameter(device_name, SP_POWER_OFF_TIME, setparam, connection_method, &err)){
						std::cout << "auto power off set success param: " << setparam << std::endl;
					}else{
						std::cout << "auto power off set error: " << std::endl;
					}

				}else{
					std::cout << "Parameter error. The value to be set is not a number." << std::endl;
					std::cout << "example: ./sdksample --set-sleeptimer 30(minute)" << std::endl;
					err = 1;
				}

			}else {
				std::cout << "ERROR : Option format invalid." << std::endl;
				std::cout << "Options begin with one of the following." << std::endl;
				std::cout << OPTION_SCAN << "(" << OPTION_SCAN_S << ")" << std::endl;
				std::cout << OPTION_GET_STATUS << "(" << OPTION_GET_STATUS_S << ")" << std::endl;
				std::cout << OPTION_GET_SLEEPTIMER << std::endl;
				std::cout << OPTION_SET_SLEEPTIMER << std::endl;
				std::cout << OPTION_GET_AUTOPWOFF << std::endl;
				std::cout << OPTION_SET_AUTOPWOFF << std::endl;
				err = 1;
			}

		}else{
			std::cout << "ERROR : DeviceID format invalid." << std::endl;
			err = 1;
		}
		
	}else{
		std::cout << "ERROR : Argument error." << std::endl;
		std::cout << "ERROR : Specify [option] and [DeviceID] as follows." << std::endl;
		std::cout << "./sdksample [option(--scan, etc.)] [DeviceID]" << std::endl;
		err = 1;
	}

	if (device_name)
	{
		free(device_name);
	}
	return err;
}

void DISPLAY_DEVICE_STATUS(DWORD Code)
{
	switch (Code) {
	case ESL_STAT_READY:
		std::cout << "[INFO]ESL_STAT_READY" << std::endl;
		break;
	case ESL_STAT_ERR_COVER_OPEN:
		std::cout << "[ERROR]ESL_STAT_ERR_COVER_OPEN" << std::endl;
		break;
	case ESL_STAT_ERR_PAPER_JAM:
		std::cout << "[ERROR]ESL_STAT_ERR_PAPER_JAM" << std::endl;
		break;
	case ESL_STAT_ERR_PAPER_EMPTY:
		std::cout << "[ERROR]ESL_STAT_ERR_PAPER_EMPTY" << std::endl;
		break;
	case ESL_STAT_ERR_FATAL:
		std::cout << "[ERROR]ESL_STAT_ERR_FATAL" << std::endl;
		break;
	case ESL_STAT_ERR_PESENSOR:
		std::cout << "[ERROR]ESL_STAT_ERR_PESENSOR" << std::endl;
		break;
	case ESL_STAT_ERR_LAMP_TIME_FATAL:
		std::cout << "[ERROR]ESL_STAT_ERR_LAMP_TIME_FATAL" << std::endl;
		break;
	case ESL_STAT_ERR_CR_LOCK:
		std::cout << "[ERROR]ESL_STAT_ERR_CR_LOCK" << std::endl;
		break;
	case ESL_STAT_ERR_DOUBLE_FEED:
		std::cout << "[ERROR]ESL_STAT_ERR_DOUBLE_FEED" << std::endl;
		break;
	case ESL_STAT_ERR_DOCUMENT_TRAY_CLOSE:
		std::cout << "[ERROR]ESL_STAT_ERR_DOCUMENT_TRAY_CLOSE" << std::endl;
		break;
	case ESL_STAT_ERR_LOW_BATTERY:
		std::cout << "[ERROR]ESL_STAT_ERR_LOW_BATTERY" << std::endl;
		break;
	case ESL_STAT_ERR_CARRIER_SHEET_SENSOR:
		std::cout << "[ERROR]ESL_STAT_ERR_CARRIER_SHEET_SENSOR" << std::endl;
		break;
	case ESL_STAT_ERR_EDGE_TRACKING_SENSOR:
		std::cout << "[ERROR]ESL_STAT_ERR_EDGE_TRACKING_SENSOR" << std::endl;
		break;
	case ESL_STAT_ERR_PAPER_PROTECTION:
		std::cout << "[ERROR]ESL_STAT_ERR_PAPER_PROTECTION" << std::endl;
		break;
	case ESL_STAT_ERR_SEPARATION_LEVER:
		std::cout << "[ERROR]ESL_STAT_ERR_SEPARATION_LEVER" << std::endl;
		break;
	case ESL_STAT_ERR_POSE:
		std::cout << "[ERROR]ESL_STAT_ERR_POSE" << std::endl;
		break;
	case ESL_STAT_ERR_GAP_SENSOR:
		std::cout << "[ERROR]ESL_STAT_ERR_GAP_SENSOR" << std::endl;
		break;
	case ESL_STAT_ERR_UNKNOWN:
		std::cout << "[ERROR]ESL_STAT_ERR_UNKNOWN" << std::endl;
		break;
	default:
		std::cout << "[ERROR]Unknown: " << Code << std::endl;
	}
}
