/*
 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
 */

/*
 *  Number.c
 *  GerberConversion
 *
 *  Created by Martin Štrympl on 11/8/10.
 *  Copyright 2010 School. All rights reserved.
 *
 */

#include "Number.h"

#include "Gerber.h"

bool LoadNumber(struct sNumber_Number *ps_number, char **pt_text, struct sGerber_Gerber_Actual *ps_actual, char ch_type)
{
  bool b_use=true;
  bool b_negative;

  ps_number->i4_integer=ps_number->i4_decimal=0;
  ps_number->u1_integer=ps_number->u1_decimal=0;
  
  if (**pt_text=='-')
  {
    (*pt_text)++;
    b_negative=true;
  }
  else b_negative=false;
  
  while (((**pt_text)>='0')&&((**pt_text)<='9'))
  {
    ps_number->i4_integer*=10;
    ps_number->i4_integer+=((**pt_text)-'0');
    
    ps_number->u1_integer++;
    
    (*pt_text)++;
  }
  
  if ((**pt_text)=='.')
  {
    b_use = false;
    (*pt_text)++;
    // decimal section
    while (((**pt_text)>='0')&&((**pt_text)<='9'))
    {
      ps_number->i4_decimal*=10;
      ps_number->i4_decimal+=((**pt_text)-'0');
      
      ps_number->u1_decimal++;
      
      (*pt_text)++;
    }
  }
  
  if (b_use)
  {
    {
      if ((ch_type=='X')||(ch_type=='Y'))
      {
        uint8_t u1_integer, u1_decimal;
        
        if (ch_type=='X')
        {
          u1_integer=ps_actual->s_fs.u1_X_integer;
          u1_decimal=ps_actual->s_fs.u1_X_decimal;
        }
        else
        {
          u1_integer=ps_actual->s_fs.u1_Y_integer;
          u1_decimal=ps_actual->s_fs.u1_Y_decimal;
        }
        
        if ((u1_integer+u1_decimal)<(ps_number->u1_integer+ps_number->u1_decimal))
        {
          printf("Bad number range. Please check FS settings. Bad number of integer and decimal digits.\n");
          return false;
        }
                
        if (ps_actual->s_fs.b_LT)
        {
          uint32_t u4_multi = 1;
          
          for (;ps_number->u1_decimal<u1_decimal;ps_number->u1_decimal++)
          {
            ps_number->i4_decimal+=(ps_number->i4_integer%10)*u4_multi;
            
            ps_number->i4_integer/=10;
            u4_multi*=10;
            
            if (ps_number->u1_integer) ps_number->u1_integer--;
          }
        }
        else
        {
          if (u1_integer<ps_number->u1_integer)
          {
            printf("Bad number range. Please check FS settings. Can not interpret trailing zero omission.\n");
            return false;
          }
          
          for (;ps_number->u1_integer<u1_integer;ps_number->u1_integer++)
          {
            ps_number->i4_integer*=10;
          }
        }
      }
      // 'i' - integer number, 'd' - decimal number
      else if (ch_type!='i')
      {
        if (ps_number->u1_decimal!=0)
        {
          printf("Number with decimal places is not supported in this possition.\n");
          return false;
        }
      }
      else if (ch_type!='d') // 'I' or 'J' code ? 
      {
        {
          uint8_t u1_lim;
          
          if (ps_number->u1_decimal!=0)
          {
            printf("Number with decimal places is not supported in RS-274D codes.\n");
            return false;
          }
          
          switch (ch_type)
          {
            case 'N':
              u1_lim=ps_actual->s_fs.u1_N;
              break;
            case 'G':
              u1_lim=ps_actual->s_fs.u1_G;
              break;
            case 'D':
              u1_lim=ps_actual->s_fs.u1_D;
              break;
            case 'M':
              u1_lim=ps_actual->s_fs.u1_M;
              break;
            case 'i':
              u1_lim=ps_number->u1_integer;
              break;
            default:
              printf("Unkown RS-274D code.\n");
              return false;
          }
          
          if (ps_number->u1_integer!=u1_lim)
          {
            printf("Bad code number range. Please check FS settings.\n");
            return false;
          }
        }
      }
    }
  }
  
  if (b_negative)
  {
    ps_number->i4_integer=-ps_number->i4_integer;
    ps_number->i4_decimal=-ps_number->i4_decimal;
  }
  
  if ((ch_type=='X')||(ch_type=='Y')||(ch_type=='I')||(ch_type=='J')||(ch_type=='d'))
  {
    uint32_t u4_n, u4_div=1;
    
    for (u4_n=0;u4_n<ps_number->u1_decimal;u4_n++)
    {
      u4_div*=10;
    }
    
    ps_number->ld_number=ps_number->i4_integer+(ps_number->i4_decimal/((long double)u4_div));
    
  }
  
  return true;
}
