/*
 GerberConversion
 Copyright (C) 2010 Martin Štrympl

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public
 License as published by the Free Software Foundation; either
 version 3.0 of the License, or (at your option) any later version.

 This program 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
 General Public License for more details.

 You should have received a copy of the GNU General Public
 License along with this program.

 Martin Štrympl
 xstrym00@stud.feec.vutbr.cz
 */

#include "main.h"

#include "Gerber.h"
#include "Module.h"
#include "Dynamic.h"

#include "Code.h"
#include "Set.h"

int main (int argc, const char **argv)
{
  printf("GerberConversion version 1.2.\nThis program is written by Martin Strympl (mail: xstrym00@stud.feec.vutbr.cz) for convert gerber data format to data format for laser cuting.\n");
  printf("Compiled time: %s %s\n\n", __DATE__, __TIME__);
  if (argc<3)
  {
    printf("Please enter any params.\n\n");
    usage();
    return 1;
  }

  {
    uint32_t u4_n, u4_from = 0;
    bool b_gerberfile = true;

    struct sGerber_Gerber *ps_gerber;
    struct sGerber_Gerber_Actual *ps_actual;

    ps_gerber = Gerber_Gerber_Construct();

    if (ps_gerber==NULL)
    {
      printf("Allocation memory failed.\n");
      return 1;
    }

    if (Gerber_Gerber_AutoCodeRegister(ps_gerber)==false)
    {
      printf("Code registring failed.\n");
      return 1;
    }
    if (Gerber_Gerber_AutoSetsRegister(ps_gerber)==false)
    {
      printf("Sets registring failed.\n");
      return 1;
    }

    ps_actual=Gerber_Gerber_GetActual(ps_gerber);

    for (u4_n=2;u4_n<argc;u4_n++)
    {
      // first is source gerber file name
      if (argv[u4_n][0]!='-')
      {
        b_gerberfile=false;
      }
      if (b_gerberfile)
      {
        // gerber reading settings
        if (strcmp(argv[u4_n],"--ignore_badcodes")==0)
        {
          ps_actual->s_behavior.b_ignore_badcodes=true;
          printf("Ignoring bad codes is activated.\n");
        }
        else if (strcmp(argv[u4_n],"--ignore_badsets")==0)
        {
          ps_actual->s_behavior.b_ignore_badsets=true;
          printf("Ignoring bad sets is activated.\n");
        }
        else if (strcmp(argv[u4_n],"--inch")==0)
        {
          ps_actual->s_sets.b_millimeters=false;
          printf("Unit set to inch.\n");
        }
        else if (strcmp(argv[u4_n],"--transformsets")==0)
        {
          u4_n++;
          if (u4_n<argc)
          {
            uint32_t u4_len;

            u4_len=strlen(argv[u4_n])+1;

            if (u4_len>PRIORITY_LIMIT) u4_len=PRIORITY_LIMIT;

            memcpy(ps_actual->s_sets.at_pointnumeringpriority, argv[u4_n], u4_len);

            ps_actual->s_sets.at_pointnumeringpriority[PRIORITY_LIMIT-1]=0;

            printf("Transform settings is '%s'.\n", ps_actual->s_sets.at_pointnumeringpriority);
          }
          else
          {
            printf("Missing argument value.\n");
            return 1;
          }
        }
        else if (strcmp(argv[u4_n],"--debug")==0)
        {
          u4_n++;
          if (u4_n<argc)
          {
            ps_actual->s_sets.i4_debug=atoi(argv[u4_n]);
            printf("Debug mode is activated.\n");
          }
          else
          {
            printf("Missing argument value.\n");
            return 1;
          }
        }
        else
        {
          // bad argument
          printf("Argument '%s' is not valid. Sorry.\n", argv[u4_n]);
          return 1;
        }
      }
      else
      {
        // target module for use
        if (((argv[u4_n][0]!='-')&&(argv[u4_n][0]!='=')))
        {
          if (u4_from)
          {
            // load module
            if (!addmodule(ps_gerber, argv+u4_from, u4_n-u4_from)) return -1;

            u4_from = u4_n;
          }
          else
          {
            u4_from = u4_n;
          }

        }
      }
    }
    if (u4_from) if (!addmodule(ps_gerber, argv+u4_from, u4_n-u4_from)) return -1;

    // generate outputs
    while (true)
    {
      if (Gerber_Gerber_LoadFile(ps_gerber, argv[1])!=true)
      {
        printf("Gerber file %s opening failed.\n", argv[1]);
        break;
      }


      Gerber_Gerber_Destruct(ps_gerber);
      printf("Succesfull completed.\n");
      return 0;
    }

    Gerber_Gerber_Destruct(ps_gerber);
  }

  printf("Convreting failed.\n");
  return 1;
}

void usage(void)
{
  printf("Usage:\nGerberConversion sourcegerberfile targetfile target \n\nExample:\nGerberConversion file.gerber arguments outputsmodules.\n\n");
}

bool addmodule(struct sGerber_Gerber *ps_gerber, const char **at_argv, uint32_t u4_argc)
{
  void *v_memory;
  DLHANDLE v_lib;

  fGerber_Module_Start f_start;
  fGerber_Module_End f_end;
  fGerber_Draw_LineSegment f_linesegment;
  fGerber_Draw_OvalSegment f_ovalsegment;

  // -fnested-functions to re-enable
  v_lib = DLOPEN(at_argv[0]);

  if (v_lib==NULL)
  {
    printf("Module '%s' loading failed. Can not open library.\n", at_argv[0]);
    return false;
  }

  f_start=(fGerber_Module_Start)DLOBJECT(v_lib, "Start");
  f_end=(fGerber_Module_End)DLOBJECT(v_lib, "End");
  f_linesegment=(fGerber_Draw_LineSegment)DLOBJECT(v_lib, "LineSegment");
  f_ovalsegment=(fGerber_Draw_OvalSegment)DLOBJECT(v_lib, "OvalSegment");

  if ((f_start==NULL)||(f_linesegment==NULL)||(f_ovalsegment==NULL))
  {
    printf("Find module '%s' function failed.\n", at_argv[0]);
    return false;
  }

  if (f_start(at_argv+1, u4_argc-1, &v_memory)!=0)
  {
    printf("Start module '%s' failed.\n", at_argv[0]);
    return false;
  }

  if (Gerber_Gerber_RegisterOutput(ps_gerber, v_lib, v_memory, f_linesegment, f_ovalsegment)==false)
  {
    if (f_end) f_end(v_memory);

    printf("Register module '%s' failed.\n", at_argv[0]);
    return false;
  }

  printf("Module '%s' loaded and set to output.\n", at_argv[0]);

  return true;
}
