// Test.cpp : Defines the entry point for the console application.
//

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

#include <time.h>

#include "L_Types.h"
#include "DMPro_Types.h"
#include "QRPro_Types.h"
#include "PDF417Pro_Types.h"
#include "Az_Types.h"

#include "All_Types.h"
#include "twodtg_license.h"

#include "LoadBMP.c"

#define MAX_PATH 1024

 const int maxoptcount = 10;
 struct TList
 { char symbology; // 'L' || 'D' || 'Q' || 'P' || 'A'
   int  next;
 };

 const char* dir1="Samples/";
 const char* files[]={
"UPCE_Addon.bmp"
,"20MIL_5.BMP"
,"cb_2.bmp"
,"4-1.bmp"
,"QR_v3.bmp"
,"nzp-n.BMP"
,"PDF1.bmp"
,"PDF2.bmp"
,"R_A_2_.BMP"
,"R_B_7_.BMP"
,"Aztec sample.bmp"
,NULL   // last member of array must be NULL
 };

 void printLINEAR_QUALITY(LINEAR_QUALITY lq)
 {
  printf("\nGrades for the scan reflectance profile\n");
  printf("Parameter    Value   Grade          Average Grade on ten scannings\n");
  printf("Decode                 %d                     %6.2f\n",(int)lq.decode_grad,lq.decode_grad_av);
  printf("Rmax         %6.2f%%                           \n",lq.max_reflectance  );
  printf("Rmin         %6.2f%%   %d                     %6.2f\n",lq.min_reflectance  ,(int)lq.min_reflectance_grad,lq.min_reflectance_grad_av);
  printf("SC           %6.2f%%   %d                     %6.2f\n",lq.symbol_contrast  ,(int)lq.symbol_contrast_grad,lq.symbol_contrast_grad_av);
  printf("ECmin        %6.2f%%   %d                     %6.2f\n",lq.min_edge_contrast,(int)lq.min_edge_contrast_grad,lq.min_edge_contrast_grad_av);
//  printf("Rs_ECmin     %6.2f%%                         \n",lq.Rs_ECmin);
//  printf("Rb_ECmin     %6.2f%%                         \n",lq.Rb_ECmin);
  printf("MOD          %6.2f    %d                     %6.2f\n",lq.modulation       ,(int)lq.modulation_grad,lq.modulation_grad_av);
  printf("Defects      %6.2f    %d                     %6.2f\n",lq.defects          ,(int)lq.defects_grad,lq.defects_grad_av);
//  printf("ERNmax       %6.2f%%                       \n",lq.ERNmax);
  printf("Decodability %6.2f    %d                     %6.2f\n",lq.decodability     ,(int)lq.decodability_grad,lq.decodability_grad_av);
  printf("Overall Grade          %d                     %6.2f\n",                     (int)lq.overall_grade_grad,lq.overall_grade_grad_av);
  }

  void printLINEAR_SCAN_LINE(int idx_scan_line, LINEAR_SCAN_LINE* sl) {

  printf("\nResult for the ten scan reflectance profile\n");
  printf(" N start_x  start_y  end_x  end_y  q_zone  c_sum  length  data\n");
  for(int i=0; i<10; i++) {
    if(i != idx_scan_line)
      printf(" %d %6d  %7d  %5d  %5d  %6d  %5d  %5d   %s\n",i,
                                            sl[i].scan_line_start_x,
                                            sl[i].scan_line_start_y,
                                            sl[i].scan_line_end_x,
                                            sl[i].scan_line_end_y,
                                            sl[i].quietzone,
                                            sl[i].checksum,
                                            sl[i].length,
                                            sl[i].dataRes);
    else
      printf(" %d * %4d * %6d * %4d * %4d * %5d * %4d * %4d * %s\n",i,
                                            sl[i].scan_line_start_x,
                                            sl[i].scan_line_start_y,
                                            sl[i].scan_line_end_x,
                                            sl[i].scan_line_end_y,
                                            sl[i].quietzone,
                                            sl[i].checksum,
                                            sl[i].length,
                                            sl[i].dataRes);
  }
 }

//----------------------------------
void initlist(TList *listarray)
{
  memset(listarray,0,maxoptcount*sizeof(TList));
}

void reorderlist(TList *listarray, int &start, int pos, int count)
// assign start of list to currant pos
{
  int i;
  int curpos=start;

  if (count<=1 || pos==start)
    return;

  for (i=0;i<count;i++){
    if(listarray[curpos].next==pos){
      listarray[curpos].next = listarray[pos].next;
      listarray[pos].next = start;
      start = pos;
      break;
    }else{
      curpos = listarray[curpos].next;
    }
  }

}

void MainTask_Fn(void)
{

  int result;   int  row;
  int rowcount, colcount;
  int maxR = 4000; int maxC = 4000;
  TRow*    pdupbits;
  TRow     pdupmembits;  // Image in Memory
  TRow*    pbits;
  TRow     pmembits;  // Image in Memory
  int ResLoadBMP;
  int lq,i,j;

  int   count = 0;
  int   csumErr=0, confErr=0, qzErr=0;
  int   countOK=0;     // count of 1D codes
  int   countDMOK=0;
  int   countQROK=0;
  int   countPDFOK=0;
  int   countAZOK = 0;
  char  dir [MAX_PATH];
  char  path[MAX_PATH];

  int optcount;
  int k;         // index of current Option
  int start = 0; // index of start Option
  int lcnt;      // counter of list position
  void*         pDecOpts[maxoptcount]; // list of pointers
  TList         optlist[maxoptcount];

  PL_Decoder    pLDecoder;
  TL_ImageInfo* pl_imageinfo;
  TL_Info*      pl_info;

  PDM_Decoder    pDMDecoder;
  TDM_ImageInfo* pdm_imageinfo;
  TDM_Info*      pdm_info;

  PQR_Decoder    pQRDecoder;
  TQR_ImageInfo* pqr_imageinfo;
  TQR_Info*      pqr_info;

  PPDF417_Decoder    pPDFDecoder;
  TPDF417_ImageInfo* ppdf_imageinfo;
  TPDF417_Info*      ppdf_info;

  PAZ_Decoder    pAZDecoder = NULL;
  PAZ_ImageInfo  pAZimageinfo;
  PAZ_Info       pAZinfo;

  bool          SymbolOK;
  int symq;
  int stat[20][5];

   strcpy(dir,"./");
   strcat(dir, dir1);

  
   // Check License
   if(IsActivated())
   {
       printf("License status: Fully licensed.\n");
   }else if(EvaluationDayCount() > 0)
   {
       printf("License status: Evaluation expires in %d days.\n.", EvaluationDayCount());
   }else if(RequredRootAcess())
   {
       printf("ATTENTION: ROOT rights are required to initialize a license!\nUse 'sudo' for first run.\n");
       return;
   }else
   {
       printf("License status: Evaluation expired!\n");
       return;
   }
   
   
  Connect_Total_Decoder();

  pLDecoder = Connect_L_Decoder(maxR,maxC);
  if(pLDecoder==NULL) return ;

  pDMDecoder = Connect_DM_Decoder(maxR,maxC);
  if(pDMDecoder==NULL) return ;

  pQRDecoder = Connect_QR_Decoder(maxR, maxC);
  if(pQRDecoder==NULL) return ;

  pPDFDecoder = Connect_PDF417_Decoder(maxR, maxC);
  if(pPDFDecoder==NULL) return ;

  pAZDecoder = Connect_AZ_Decoder(maxR, maxC);
  if(pAZDecoder == NULL) return;

  pmembits = (TRow) malloc(maxR*maxC);       //  Image in Memory
  pbits    = (TRow*) malloc(maxR*sizeof(TRow)); // pointers to ScanLines

  for (row = 0; row < maxR; row++){
      pbits[row] = &pmembits[maxC*row];
  }


  TDM_OptMode opt_DM={
                      1, // maxDMCount
                      3, // cellColor=any
                      3, // mirrorMode=any
                      DMSP_ULTIMATEPLUS, // speedMode
                      DM_QM_ALL,    // qualityMask
                      LM_ST_DOT,    // labelMode
                      0, // timeOut
                      0, // filterMode
                      0   // qzMode = normal
                     };

  TQR_OptMode opt_QR={
                      1, // maxQRCount
                      3, // cellColor=any
                      3, // mirrorMode=any
                      0, // speedMode
                      1, // quality
                      0, // labelMode
                      0, // timeOut
                      0, // filterMode
                      2, // symbology = normal + micro
                      0  // qzMode = standard
                     };

  TL_OptMode opt_L_All =
                    { 1,//10,  // int maxLcount;
                     -1,  // int typecode any;
                     // TCM_TCODE39 | TCM_TUPCEEX,
                     // TC_TNZP,
                     // TC_TSuissPost,

                      0,  // int timeout;
                      1,  // int paramq;
                      0,  // int checksum_I25;
                      0,  // int checksum_C39;
                     -1,  // int quietzone;
                       0,//1, // int smartmode
                       0, // int EC_Factor
                       0, // int pharmacodedir
                       2, //int scandir = vertical+horizontal;
                       8, //int scanstep;
                       0, // checksum_CB;
                       0, // int FullASCII_C39;
                      -1, // 250,  //int colbeg
                      -1, // 440,  //int colend      //200, 50, 440, 430
                      -1, //  50,  //int rowbeg
                      -1, // 430,  //int rowend
                      99,  // TADF_num
                      L_DEFAULT // L_WHITE
                     };
  TL_OptMode opt_RSS_All =
                    { 1,//10,  // int maxLcount;
                     //-1,  // int typecode any;
                      TCM_TRSS_ALL,
                     // TC_TNZP,
                     // TC_TSuissPost,

                      0,  // int timeout;
                      1,  // int paramq;
                      0,  // int checksum_I25;
                      0,  // int checksum_C39;
                     -1,  // int quietzone;
                       0,//1, // int smartmode
                       0, // int EC_Factor
                       0, // int pharmacodedir
                       2, //int scandir = vertical+horizontal;
                       8, //int scanstep;
                       0, // checksum_CB;
                       0, // int FullASCII_C39;
                      -1, // 250,  //int colbeg
                      -1, // 440,  //int colend      //200, 50, 440, 430
                      -1, //  50,  //int rowbeg
                      -1, // 430,  //int rowend
                      99,  // TADF_num
                      L_DEFAULT // L_WHITE
                     };

  TL_OptMode opt_NZP_W =
                    { 1,//10,  // int maxLcount;
                     //-1,  // int typecode any;
                     // TCM_TRSS_ALL,
                      TC_TNZP,
                     // TC_TSuissPost,

                      0,  // int timeout;
                      1,  // int paramq;
                      0,  // int checksum_I25;
                      0,  // int checksum_C39;
                     -1,  // int quietzone;
                       0,//1, // int smartmode
                       0, // int EC_Factor
                       0, // int pharmacodedir
                       2, //int scandir = vertical+horizontal;
                       8, //int scanstep;
                       0, // checksum_CB;
                       0, // int FullASCII_C39;
                      -1, // 250,  //int colbeg
                      -1, // 440,  //int colend      //200, 50, 440, 430
                      -1, //  50,  //int rowbeg
                      -1, // 430,  //int rowend
                      99,  // TADF_num
                      L_WHITE // L_DEFAULT
                     };

  TPDF417_OptMode opt_PDF =
  {
	1,         //  int MaxSymbolCount;            // maximum number of decoded PDF417 labels
	SP_Robust, //  TPDF417_SpeedMode  SpeedMode;  //  SP_Fast,  SP_Robust, SP_Smart
	CG_No,     //  TPDF417_CalcGrade  CalcGrade;  //  CG_No, CG_Yes ;
	DM_All,    //  TPDF417_DirectMode DirectMode; //  DM_LeftRight, DM_Horizontal, DM_All, DM_Vertical
	0,         //  int BWFilter;                  // 0: none, +1 => BW+1,  -1 => BW-1
	0,         //  int TimeOut;                   // in milliseconds, zero - not timeout
	4          //  int ScanStep;
  };

  TAZ_OptMode    AZ_optmode;
  AZ_optmode.maxAZCount = 1;
  AZ_optmode.timeOut    = 0; // 0 ms => don't check time-out
  AZ_optmode.speedMode  = 0;
  AZ_optmode.qualityMask= 0;
  AZ_optmode.symbology  = AZ_S_NORMAL;
  AZ_optmode.filterMode = 0;
  AZ_optmode.labelMode  = 0;
  AZ_optmode.qzMode     = AZ_QZ_STANDARD;

  initlist(optlist);
  start = 0;
  pDecOpts[0] = Create_L_Options (pLDecoder ,opt_L_All);
  optlist [0].symbology= 'L'; optlist [0].next = 3;
  pDecOpts[1] = Create_L_Options (pLDecoder ,opt_RSS_All);
  optlist [1].symbology= 'L'; optlist [1].next = 2;
  pDecOpts[2] = Create_L_Options (pLDecoder ,opt_NZP_W);
  optlist [2].symbology= 'L'; optlist [2].next = 5;
  pDecOpts[3] = Create_DM_Options (pDMDecoder ,opt_DM);
  optlist [3].symbology= 'D'; optlist [3].next = 4;
  pDecOpts[4] = Create_QR_Options (pQRDecoder ,opt_QR);
  optlist [4].symbology= 'Q'; optlist [4].next = 1;
  pDecOpts[5] = Create_PDF417_Options (pPDFDecoder ,opt_PDF);
  optlist [5].symbology= 'P'; optlist [5].next = 6;
  pDecOpts[6] = Create_AZ_Options (pAZDecoder, AZ_optmode);
  optlist [6].symbology= 'A'; optlist [6].next = maxoptcount; // start;
  optcount = 7;

  double TotalTime = 0.0;

  for (i=0;i<20;i++){
   	memset(stat[i],0,sizeof stat[0]);
  }
  for(j=0; files[j]!=NULL; j++)
  {
   strcpy(path, dir);
   strcat(path, files[j]);

   printf("\n");
   printf("%s ", path);
   rowcount = maxR;
   colcount = maxC;
   ResLoadBMP = LoadBMP (path , pbits ,&rowcount, &colcount);

   if(ResLoadBMP != 0) {
     printf("ResLoadBMP == %d \n",ResLoadBMP);  continue;
   }//return 1;

   count++;

// 20161104
   pdupmembits = (TRow) malloc(rowcount*colcount);   //  Image in Memory
   pdupbits    = (TRow*) malloc(rowcount*sizeof(TRow)); // pointers to ScanLines

   for (row = 0; row < rowcount; row++){
     pdupbits[row] = &pdupmembits[colcount*row];
     memcpy(pdupbits[row],pbits[row],colcount);  // store original image
   }
// 20161104

   clock_t beg, end;
   beg = clock(); // Do your processing

   k = start;
   SymbolOK = false;
   for (lcnt=0; lcnt<optcount; lcnt++){
    if (optlist[k].symbology=='L'){
     result =  Decode_L_Bits(pDecOpts[k], rowcount,colcount,pbits);
     if (result>=0){
       pl_imageinfo = GetL_ImageInfo(pDecOpts[k]);
       lq = pl_imageinfo->LCount;
       printf(" %d",lq);
       if (lq > 0) {
         for (i=0; i<=lq-1; i++) {
           pl_info = GetL_Info(pDecOpts[k],i);
           printf("\n      ");
           switch (pl_info->type){
             case TC_TCODE128     : printf(" C128:   "); break;
             case TC_TCODE39      : printf(" C39:    "); break;
             case TC_TCODABAR     : printf(" Cbar:   "); break;
             case TC_TINTERLEAVED : printf(" Il 2/5: "); break;
             case TC_TEAN13       : printf(" EAN13:  "); break;
             case TC_TEAN8        : printf(" EAN8:   "); break;
             case TC_TUPCE        : printf(" UPCE:   "); break;
             case TC_TEAN13EX     : printf(" EAN13_ADDON:  "); break;
             case TC_TUPCEEX      : printf(" UPCE_ADDON:   "); break;
             case TC_TPHARMACODE  : printf(" Pharma: "); break;
             case TC_TADF  : printf(" TADF, barcount=%d   ",pl_info->add_lq->actTADFnum);break;
             default: printf(" Unknown:");
           };

           if (pl_info->pch[-3] == ']'){
             printf(" %c%c%c :", pl_info->pch[-3],pl_info->pch[-2],pl_info->pch[-1]);
           }
           printf(" %d * %s ", pl_info->pchlen,pl_info->pch);

           if( pl_imageinfo->BreakReason==L_TIMEOUT)
             printf("== TIMEOUT! ");

           if ((pl_info->type)>0){
             int bt, rr
            ,n = 0;
             bt = pl_info->type;
             if (bt<1 && bt>19)
               bt = 16; // Other
             rr = pl_info->RejectionReason;
             if (rr == L_SUCCESSFUL) n=1;
             else if (rr == L_CHECKSUM_FAILED) n=2;
             else if (rr == L_NOT_CONFIRMED  ) n=3;
             else if (rr == L_NOT_QUIET_ZONE ) n=4;
             stat[bt][n]+=1;
           }
           if( pl_info->RejectionReason==L_CHECKSUM_FAILED){
             csumErr++;
   	         printf("=CS!");
           }
           if( pl_info->RejectionReason==L_NOT_CONFIRMED ){
      	     confErr++;
   	         printf("=Nc!");
           }
           if( pl_info->RejectionReason==L_NOT_QUIET_ZONE){
             qzErr++;
   	         printf("=QZ!");
           }
           if( pl_info->RejectionReason==L_SUCCESSFUL){
             reorderlist(optlist,start,k,optcount);
             countOK++;
             printf("=OK!");
             SymbolOK = true;
             break;
           }
           k = optlist[k].next;
         };
         if (SymbolOK){
           break;
         }
      }else {  // lq==0
         k = optlist[k].next;
      }
     }else{//result<0
       k = optlist[k].next;
     }
    }else if(optlist[k].symbology=='D'){
     result =  DecodeDM_Bits(pDecOpts[k], rowcount,colcount,pbits);
     if (result>=0){
      pdm_imageinfo = GetDM_ImageInfo(pDecOpts[k]);
      if (pdm_imageinfo->RejectionReason == DM_RR_OK){
        reorderlist(optlist,start,k,optcount);
        symq = pdm_imageinfo->DMCount;
        printf(" ,DM count = %d",symq);
        if (symq > 0) {
          for (i=0; i<=symq-1; i++) {
            pdm_info = GetDM_Info(pDecOpts[k],i);
            printf("\n      ");
            printf("%d * %s", pdm_info->pchlen, pdm_info->pch);
            countDMOK++;
        	printf("\nDM=OK!\n");
          }
        }
        SymbolOK = true;
        break;
       }
     }
     k = optlist[k].next;
    }else if (optlist[k].symbology=='Q'){
     result =  DecodeQR_Bits(pDecOpts[k], rowcount,colcount,pbits);
     if (result>=0){
      pqr_imageinfo = GetQR_ImageInfo(pDecOpts[k]);
      if (pqr_imageinfo->RejectionReason == QR_SUCCESSFUL){
        reorderlist(optlist,start,k,optcount);
        symq = pqr_imageinfo->QRCount;
        printf(" ,QR count = %d",symq);
        if (symq > 0) {
          for (i=0; i<=symq-1; i++) {
            pqr_info = GetQR_Info(pDecOpts[k],i);
            printf("\n      ");
            printf("%d * ", pqr_info->pchlen);
            for(int m=0; m<pqr_info->pchlen; m++)
              printf("%c", char((pqr_info->pch2)[m]));

            countQROK++;
        	printf("\nQR=OK!\n");
          }
        }
        SymbolOK = true;
        break;
      }
     }
     k = optlist[k].next;
    }else if(optlist[k].symbology=='P'){
     result =  DecodePDF417_Bits(pDecOpts[k], rowcount,colcount,pbits);
     if (result>=0){
      ppdf_imageinfo = GetPDF417_ImageInfo(pDecOpts[k]);
      if (ppdf_imageinfo->RejectionReason == PDF417_OK){
        reorderlist(optlist,start,k,optcount);
        symq = ppdf_imageinfo->SymbolCount;
        printf(" ,PDF count = %d",symq);
        if (symq > 0) {
          for (i=0; i<=symq-1; i++) {
            ppdf_info = GetPDF417_Info(pDecOpts[k],i);
            printf("\n      ");
            printf("%d * %s", ppdf_info->pchlen, ppdf_info->pch);
            countPDFOK++;
        	printf("\nPDF=OK!\n");
          }
        }
        SymbolOK = true;
        break;
       }
      }
      k = optlist[k].next;
     }else if(optlist[k].symbology=='A'){
     result =  Decode_AZ_Bits(pDecOpts[k], rowcount,colcount,pbits);
     if (result>=0){
      pAZimageinfo = Get_AZ_ImageInfo(pDecOpts[k]);
      if (pAZimageinfo->RejectionReason == 0){
        reorderlist(optlist,start,k,optcount);
        symq = pAZimageinfo->AZCount;
        printf(" ,AZ count = %d",symq);
        if (symq > 0) {
          for (i=0; i<=symq-1; i++) {
            pAZinfo = Get_AZ_Info(pDecOpts[k],i);
            printf("\n      ");
            printf("%d * %s", pAZinfo->pchlen, pAZinfo->pch);
            countAZOK++;
        	printf("\nAZ=OK!\n");
          }
        }
        SymbolOK = true;
        break;
       }
      }
      k = optlist[k].next;
     }
    if (k>=maxoptcount)
      break;
// 20161104
    for (row = 0; row < rowcount; row++){ // restore original image
      memcpy(pbits[row],pdupbits[row],colcount);
    }
// 20161104
   }
   end = clock();
   int m_DecodeTime = (int)((end - beg)*1000 / CLOCKS_PER_SEC);
   printf(",  time=%5d", m_DecodeTime);
   TotalTime += m_DecodeTime; // /1000

   if(result<0){
     printf(" decoder == NULL!!!!!!"); return ;
   }

// 20151104
   free(pdupbits);
   free(pdupmembits);
// 20151104

  }  // for j
  if (files[j]==NULL){
    Disconnect_L_Decoder(pLDecoder); // and delete all Options
    Disconnect_DM_Decoder(pDMDecoder); // and delete all Options
    Disconnect_QR_Decoder(pQRDecoder); // and delete all Options
	Disconnect_PDF417_Decoder(pPDFDecoder); //  -- // -- // --
  }

  char ct[13];
  printf("\n\n");
  printf("1D Symbology !  OK ,  CS , Conf,  QZ \n");
  printf("-------------------------------------\n");
  for (i=1;i<=19;i++){
    switch (i){
     case 1: strcpy(ct,"CODE128     "); break;
     case 2: strcpy(ct,"CODE39      "); break;
     case 3: strcpy(ct,"CODABAR     "); break;
     case 4: strcpy(ct,"INTERLEAVED "); break;
     case 5: strcpy(ct,"EAN13       "); break;
     case 6: strcpy(ct,"EAN8        "); break;
     case 7: strcpy(ct,"UPCE        "); break;
     case 8: strcpy(ct,"POSTNET     "); break;
     case 9: strcpy(ct,"IMB         "); break;
     case 10: strcpy(ct,"PHARMACODE  "); break;
     case 11: strcpy(ct,"RSS         "); break;
     case 12: strcpy(ct,"RSS_L       "); break;
     case 13: strcpy(ct,"RSS_E       "); break;
     case 14: strcpy(ct,"EAN13 addon "); break;
     case 15: strcpy(ct,"UPCE addon  "); break;
     case 17: strcpy(ct,"TADF        "); break;
     case 18: strcpy(ct,"NZP         "); break;
     case 19: strcpy(ct,"SUISSPOST   "); break;
     default: strcpy(ct,"            "); break;
    }
    printf("%s !%4d ,%4d ,%4d ,%4d \n"
           ,ct,stat[i][1],stat[i][2],stat[i][3],stat[i][4]);
  }
  printf("\n count=%d,  1D decoded=%d  \n", count, countOK);
  printf("\n SUCCESSFUL=%d, NOT_QUIET_ZONE=%d, CHECKSUM_FAILED=%d, NOT_CONFIRMED=%d \n",
		          countOK,          qzErr,                csumErr,              confErr
		);
  printf("\n=========================================\n");
  printf("Data Matrix decoded=%d \n", countDMOK);
  printf("=========================================\n");
  printf("QR Code decoded=%d \n", countQROK);
  printf("=========================================\n");
  printf("PDF417 decoded=%d \n", countPDFOK);
  printf("=========================================\n");
  printf("Aztec decoded=%d \n", countAZOK);
  printf("=========================================\n");


  if (count>0)
    printf(",  avr. time = %8.2f\n",TotalTime/count);

  free(pbits);
  free(pmembits);
  return;
}

int main(int argc, char **argv)
{
   MainTask_Fn();
   return 0;
}



