/**********************************************************************
 * File:        tessedit.cpp  (Formerly tessedit.c)
 * Description: Main program for merge of tess and editor.
 * Author:					Ray Smith
 * Created:					Tue Jan 07 15:21:46 GMT 1992
 *
 * (C) Copyright 1992, Hewlett-Packard Ltd.
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
 ** You may obtain a copy of the License at
 ** http://www.apache.org/licenses/LICENSE-2.0
 ** Unless required by applicable law or agreed to in writing, software
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 *
 **********************************************************************/

#include "mfcpch.h"
#include "applybox.h"
#include "control.h"
#include "tessvars.h"
#include "tessedit.h"
#include "baseapi.h"
#include "pageres.h"
#include "imgs.h"
#include "varabled.h"
#include "tprintf.h"
#include "tesseractmain.h"
#include "stderr.h"
#include "notdll.h"
#include "mainblk.h"
#include "output.h"
#include "globals.h"
#include "blread.h"
#include "tfacep.h"
#include "callnet.h"

#define VARDIR        "configs/" /*variables files */
                                 //config under api
#define API_CONFIG      "configs/api_config"
#define EXTERN

EXTERN BOOL_VAR (tessedit_create_boxfile, FALSE, "Output text with boxes");
EXTERN BOOL_VAR (tessedit_read_image, TRUE, "Ensure the image is read");
EXTERN INT_VAR (tessedit_serial_unlv, 0,
                "0->Whole page, 1->serial no adapt, 2->serial with adapt");
EXTERN BOOL_VAR (tessedit_write_images, FALSE,
"Capture the image from the IPE");
EXTERN BOOL_VAR (tessedit_debug_to_screen, FALSE, "Dont use debug file");

extern INT16 XOFFSET;
extern INT16 YOFFSET;
extern int NO_BLOCK;

const ERRCODE USAGE = "Usage";
char szAppName[] = "Tessedit";   //app name

/**********************************************************************
 *  main()
 *
 **********************************************************************/

#ifndef GRAPHICS_DISABLED
int main(int argc, char **argv) {
  STRING outfile;               //output file

  if (argc < 3) {
    USAGE.error (argv[0], EXIT,
      "%s imagename outputbase [-l lang] [configfile [[+|-]varfile]...]\n",
      argv[0]);
  }
  // Find the required language.
  const char* lang = "eng";
  int arg = 3;
  if (argc >= 5 && strcmp(argv[3], "-l") == 0) {
    lang = argv[4];
    arg = 5;
  }
  // Find the basename of the input file.
  STRING infile(argv[1]);
  const char* lastdot = strrchr(argv[1], '.');
  if (lastdot != NULL) {
    infile[lastdot - argv[1]] = '\0';
  }

  if (argc == arg)
    TessBaseAPI::InitWithLanguage(argv[0], infile.string(), lang,
                                  NULL, false, 0, argv + arg);
  else
    TessBaseAPI::InitWithLanguage(argv[0], infile.string(), lang,
                                  argv[arg], false,
                                  argc - arg - 1, argv + arg + 1);

  tprintf ("Tesseract Open Source OCR Engine\n");

  IMAGE image;
#ifdef _TIFFIO_
  TIFF* tif = TIFFOpen(argv[1], "r");
  if (tif) {
    read_tiff_image(tif, &image);
    TIFFClose(tif);
  } else {
    READFAILED.error (argv[0], EXIT, argv[1]);
  }
#else
  if (image.read_header(argv[1]) < 0)
    READFAILED.error (argv[0], EXIT, argv[1]);
  if (image.read(image.get_ysize ()) < 0) {
    MEMORY_OUT.error(argv[0], EXIT, "Read of image %s",
      argv[1]);
  }
#endif
  STRING text_out;
  int bytes_per_line = check_legal_image_size(image.get_xsize(),
                                              image.get_ysize(),
                                              image.get_bpp());
  if (tessedit_serial_unlv == 0) {
    TessBaseAPI::SetInputName(argv[1]);
    char* text;
    if (tessedit_create_boxfile)
      text = TessBaseAPI::TesseractRectBoxes(image.get_buffer(),
                                             image.get_bpp()/8,
                                             bytes_per_line, 0, 0,
                                             image.get_xsize(),
                                             image.get_ysize(),
                                             image.get_ysize());
    else if (tessedit_write_unlv)
      text = TessBaseAPI::TesseractRectUNLV(image.get_buffer(),
                                            image.get_bpp()/8,
                                            bytes_per_line, 0, 0,
                                            image.get_xsize(),
                                            image.get_ysize());
    else
      text = TessBaseAPI::TesseractRect(image.get_buffer(), image.get_bpp()/8,
                                        bytes_per_line, 0, 0,
                                        image.get_xsize(), image.get_ysize());
    text_out = text;
    delete [] text;
  } else {
    BLOCK_LIST blocks;
    STRING filename = argv[1];
    int len = filename.length();
    if (len > 4 && filename[len - 4] == '.') {
      filename[len - 4] = '\0';
    }
    if (!read_unlv_file(filename, image.get_xsize(), image.get_ysize(),
                        &blocks)) {
      fprintf(stderr, "Error: Must have a unlv zone file %s to read!\n",
              filename.string());
      return 1;
    }
    BLOCK_IT b_it = &blocks;
    for (b_it.mark_cycle_pt(); !b_it.cycled_list(); b_it.forward()) {
      BLOCK* block = b_it.data();
      BOX box = block->bounding_box();
      char* text = TessBaseAPI::TesseractRectUNLV(image.get_buffer(),
                                                  image.get_bpp()/8,
                                                  bytes_per_line,
                                                  box.left(),
                                                  image.get_ysize() - box.top(),
                                                  box.width(),
                                                  box.height());
      text_out += text;
      delete [] text;
      if (tessedit_serial_unlv == 1)
        TessBaseAPI::ClearAdaptiveClassifier();
    }
  }

  outfile = argv[2];
  outfile += ".txt";
  FILE* fp = fopen(outfile.string(), "w");
  if (fp != NULL) {
    fwrite(text_out.string(), 1, text_out.length(), fp);
    fclose(fp);
  }
  TessBaseAPI::End();

  return 0;                      //Normal exit
}
#else

int main(int argc, char **argv) {
  UINT16 lang;                   //language
  STRING pagefile;               //input file

  if (argc < 4) {
    USAGE.error (argv[0], EXIT,
      "%s imagename outputbase configfile [[+|-]varfile]...\n", argv[0]);
  }

  time_t t_start = time(NULL);

  init_tessembedded (argv[0], argv[2], argv[3], argc - 4, argv + 4);

  tprintf ("Tesseract Open Source OCR Engine (graphics disabled)\n");

  if (tessedit_read_image) {
#ifdef _TIFFIO_
    TIFF* tif = TIFFOpen(argv[1], "r");
    if (tif) {
      read_tiff_image(tif);
      TIFFClose(tif);
    } else
    READFAILED.error (argv[0], EXIT, argv[1]);

#else
    if (page_image.read_header (argv[1]) < 0)
      READFAILED.error (argv[0], EXIT, argv[1]);
    if (page_image.read (page_image.get_ysize ()) < 0) {
      MEMORY_OUT.error (argv[0], EXIT, "Read of image %s",
        argv[1]);
    }
#endif
  }

  pagefile = argv[1];

  BLOCK_LIST current_block_list;
  tessembedded_read_file(pagefile, &current_block_list);
  tprintf ("Done reading files.\n");

  PAGE_RES page_res(&current_block_list);

  recog_all_words(&page_res, NULL);

  current_block_list.clear();
  ResetAdaptiveClassifier();

  time_t t_end = time(NULL);
  double secs = difftime(t_end, t_start);
  tprintf ("Done. Number of seconds: %d\n", (int)secs);
  return 0;                      //Normal exit
}

#endif

int initialized = 0;

#ifdef __MSW32__
/**********************************************************************
 * WinMain
 *
 * Main function for a windows program.
 **********************************************************************/

int WINAPI WinMain(  //main for windows //command line
                   HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpszCmdLine,
                   int nCmdShow) {
  WNDCLASS wc;
  HWND hwnd;
  MSG msg;

  char **argv;
  char *argsin[2];
  int argc;
  int exit_code;

  wc.style = CS_NOCLOSE | CS_OWNDC;
  wc.lpfnWndProc = (WNDPROC) WndProc;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hInstance = hInstance;
  wc.hIcon = NULL;               //LoadIcon (NULL, IDI_APPLICATION);
  wc.hCursor = NULL;             //LoadCursor (NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  wc.lpszMenuName = NULL;
  wc.lpszClassName = szAppName;

  RegisterClass(&wc);

  hwnd = CreateWindow (szAppName, szAppName,
    WS_OVERLAPPEDWINDOW | WS_DISABLED,
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
    CW_USEDEFAULT, HWND_DESKTOP, NULL, hInstance, NULL);

  argsin[0] = strdup (szAppName);
  argsin[1] = strdup (lpszCmdLine);
  /*allocate memory for the args. There can never be more than half*/
  /*the total number of characters in the arguments.*/
  argv =
    (char **) malloc (((strlen (argsin[0]) + strlen (argsin[1])) / 2 + 1) *
    sizeof (char *));

  /*now construct argv as it should be for C.*/
  argc = parse_args (2, argsin, argv);

  //  ShowWindow (hwnd, nCmdShow);
  //  UpdateWindow (hwnd);

  if (initialized) {
    exit_code = main (argc, argv);
    free (argsin[0]);
    free (argsin[1]);
    free(argv);
    return exit_code;
  }
  while (GetMessage (&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    if (initialized) {
      exit_code = main (argc, argv);
      break;
    }
    else
      exit_code = msg.wParam;
  }
  free (argsin[0]);
  free (argsin[1]);
  free(argv);
  return exit_code;
}


/**********************************************************************
 * WndProc
 *
 * Function to respond to messages.
 **********************************************************************/

LONG WINAPI WndProc(            //message handler
                    HWND hwnd,  //window with message
                    UINT msg,   //message typ
                    WPARAM wParam,
                    LPARAM lParam) {
  HDC hdc;

  if (msg == WM_CREATE) {
    //
    // Create a rendering context.
    //
    hdc = GetDC (hwnd);
    ReleaseDC(hwnd, hdc);
    initialized = 1;
    return 0;
  }
  return DefWindowProc (hwnd, msg, wParam, lParam);
}


/**********************************************************************
 * parse_args
 *
 * Turn a list of args into a new list of args with each separate
 * whitespace spaced string being an arg.
 **********************************************************************/

int
parse_args (                     /*refine arg list */
int argc,                        /*no of input args */
char *argv[],                    /*input args */
char *arglist[]                  /*output args */
) {
  int argcount;                  /*converted argc */
  char *testchar;                /*char in option string */
  int arg;                       /*current argument */

  argcount = 0;                  /*no of options */
  for (arg = 0; arg < argc; arg++) {
    testchar = argv[arg];        /*start of arg */
    do {
      while (*testchar
        && (*testchar == ' ' || *testchar == '\n'
        || *testchar == '\t'))
        testchar++;              /*skip white space */
      if (*testchar) {
                                 /*new arg */
        arglist[argcount++] = testchar;
                                 /*skip to white space */
        for (testchar++; *testchar && *testchar != ' ' && *testchar != '\n' && *testchar != '\t'; testchar++);
        if (*testchar)
          *testchar++ = '\0';    /*turn to separate args */
      }
    }
    while (*testchar);
  }
  return argcount;               /*new number of args */
}
#endif
