//  Copyright (C) 2018-2022  SEIKO EPSON CORPORATION
//
//  License: LGPL-2.1+
//  Author : SEIKO EPSON CORPORATION
//
//  This file is part of the 'Epson Scan 2' package.
//	 This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.

//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//  
//  ESL_SAMPLE.cpp -- template and derived ESC/I ESC/I-2 protocol commands

#include "ESL_SAMPLE.h"
#include "EslStub.h"
#include <iostream>
#define LICENSE_KEY "EPSON"
#define DEVICE_NAME "DS-535II"
#define IP_ADDRESS "192.168.xx.x"
BOOL CALLBACK eslCallback(EslCBDataHdr* pData, PVOID pPrivate)
{
 std::cout << "[INFO]eslCallback" << std::endl;
 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 (cancelReqfromApp) {
    return FALSE;
   }
   break;
  }
  case CBDT_IMAGE_FILE:
  {
   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;
  }
  default:
   std::cout << "[ERROR]Invalid CallbackData Status\n" << std::endl;
 }
 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);
 BOOL ret = eslib.eslInit(&instance, LICENSE_KEY, &err);
 if (ret) {
  ConnectInfo scanner = {CT_DEFAULT};
  memcpy(scanner.deviceName, device_name, strlen(device_name)+1);
  ret = eslib.eslOpenScanner(instance, &scanner, &err);
  if (ret) {
   if (ret) {
    ret = eslib.eslExecute(instance, ET_SCAN_AND_SAVE, eslCallback, NULL, &err);
   }
   ret = eslib.eslCloseScanner(instance, &err);
  }
  eslib.eslFree(instance, &err);
 }
 return err;
}
DWORD SCAN_STORE_SAVE_Default(const char* device_name)
{
 DWORD instance = 0;
 DWORD err = 0;
 CEslStub eslib(NULL);
 BOOL ret = eslib.eslInit(&instance, LICENSE_KEY, &err);
 if (ret) {
  ConnectInfo scanner = {CT_DEFAULT};
  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);
   ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&info_params, &err);
   std::cout << "[INFO]Serial No: " << info_params.serialNumber << std::endl;
   if (ret) {
    ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
   }
   if (ret) {
    ret = eslib.eslExecute(instance, ET_SAVE_STORED_IMAGE, eslCallback, NULL, &err);
   }
   DWORD status = 0;
   ret = eslib.eslGetDeviceStatus(instance, &status, &err);
   DISPLAY_DEVICE_STATUS(status);
   ret = eslib.eslCloseScanner(instance, &err);
  }
  eslib.eslFree(instance, &err);
 }
 return err;
}
DWORD SCAN_SAVE_JPEG(const char* device_name)
{
 DWORD instance = 0;
 DWORD err = 0;
 CEslStub eslib(NULL);
 BOOL ret = eslib.eslInit(&instance, LICENSE_KEY, &err);
 if (ret) {
  ConnectInfo scanner = {CT_DEFAULT};
  memcpy(scanner.deviceName, device_name, strlen(device_name)+1);
  ret = eslib.eslOpenScanner(instance, &scanner, &err);
  if (ret) {
   EslParamScanExV1 scan_params;
   scan_params.type = ESL_PARAM_SCAN_EX_V1;
   scan_params.size = sizeof(scan_params);
   ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&scan_params, &err);
   if (ret) {
    scan_params.docSource = SRC_FLATBED;
    scan_params.imgType = IT_COLOR;
    scan_params.resolution = 300;
    scan_params.docSize = DS_A4;
    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;
    ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&scan_params, &err);
   }
   EslParamSaveBasic save_params;
   save_params.type = ESL_PARAM_SAVE_BASIC;
   save_params.size = sizeof(save_params);
   if (ret) {
    ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&save_params, &err);
   }
   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;
    ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&save_params, &err);
   }
   EslParamSaveJPEG jpeg_params;
   jpeg_params.type = ESL_PARAM_SAVE_JPEG;
   jpeg_params.size = sizeof(jpeg_params);
   if (ret) {
    ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&jpeg_params, &err);
   }
   if (ret) {
    jpeg_params.imgQuality = 90;
    jpeg_params.encProgressive = FALSE;
    ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&jpeg_params, &err);
   }
   EslParamSaveTIFF tiff_params;
   tiff_params.type = ESL_PARAM_SAVE_TIFF;
   tiff_params.size = sizeof(tiff_params);
   if (ret) {
    ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&tiff_params, &err);
   }
   if (ret) {
    tiff_params.compMono = TC_NONE;
    ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&tiff_params, &err);
   }
   if (ret) {
    ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
   }
   if (ret) {
    ret = eslib.eslExecute(instance, ET_SAVE_STORED_IMAGE, eslCallback, NULL, &err);
   }
   ret = eslib.eslCloseScanner(instance, &err);
  }
  eslib.eslFree(instance, &err);
 }
 return err;
}
DWORD SCAN_SAVE_PDF(const char* device_name)
{
 DWORD instance = 0;
 DWORD err = 0;
 CEslStub eslib(NULL);
 BOOL ret = eslib.eslInit(&instance, LICENSE_KEY, &err);
 if (ret) {
  ConnectInfo scanner = {CT_DEFAULT};
  memcpy(scanner.deviceName, device_name, strlen(device_name)+1);
  ret = eslib.eslOpenScanner(instance, &scanner, &err);
  if (ret) {
   EslParamScanExV1 scan_params;
   scan_params.type = ESL_PARAM_SCAN_BASIC;
   scan_params.size = sizeof(scan_params);
   ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&scan_params, &err);
   if (ret) {
    scan_params.docSource = SRC_AUTO;
    scan_params.imgType = IT_COLOR;
    scan_params.resolution = 300;
    scan_params.docSize = DS_A4;
    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;
    ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&scan_params, &err);
   }
   EslParamSaveBasic save_params;
   save_params.type = ESL_PARAM_SAVE_BASIC;
   save_params.size = sizeof(save_params);
   if (ret) {
    ret = eslib.eslCtrlParameter(instance, POT_GET_DEFAULT, (pEslParamHdr)&save_params, &err);
   }
   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;
    save_params.numPageStart = 2;
    save_params.numPageEnd = 4;
    ret = eslib.eslCtrlParameter(instance, POT_SET, (pEslParamHdr)&save_params, &err);
   }
   if (ret) {
    ret = eslib.eslExecute(instance, ET_SCAN_AND_STORE, eslCallback, NULL, &err);
    ret = eslib.eslExecute(instance, ET_SAVE_STORED_IMAGE, eslCallback, NULL, &err);
   }
   ret = eslib.eslCloseScanner(instance, &err);
  }
  eslib.eslFree(instance, &err);
 }
 return err;
}
int APIENTRY main(int argc, char *argv[])
{
 char * device_name;
 if(argc > 1){
  device_name = (char*)malloc(strlen(argv[1]) + 1);
  memcpy(device_name, argv[1], strlen(argv[1])+1);
 }else {
  device_name = (char*)malloc(strlen(DEVICE_NAME) + 1);
  memcpy(device_name, DEVICE_NAME, strlen(DEVICE_NAME)+1);
 }
 SCAN_SAVE_Default(device_name);
 free(device_name);
 return 0;
}
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_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;
 }
}
