#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>

#define __DATE_CPP
#include <date.h>

#include <extcdecl.h>
#include <strings.h>
#include <utility.h>

#define DAYBIAS  36525L
#define NULLDATE -99999L

const TDate nodate, botime, eotime(31,12,2050);
HIDDEN TDate __tmp_date;
HIDDEN char __date_tmp_string[20];

TDate::TDate(const TDate &d) : _val(d._val) {}


TDate::TDate(long l) : _val(l)

{
  if (_val == TODAY)
  {
    char s[10];
    cgetdata(&_val, s);
  }
}


TDate::TDate(const char* s)

{
  _val = NULLDATE;
  if (!isdate(s)) return;
  
  if (strlen(s) == 10)
  {
    int day = atoi(s), month = atoi(&s[3]), year = atoi(&s[6]);
    long  off = 0L;
    
    if (year > 1000)
    {
      if (year < 1951) off -= DAYBIAS;
      if (year < 1851) off -= DAYBIAS;
      if (year < 1751) off -= DAYBIAS;
      year %= 100; // modify
    }
    _val = makedata(day, month, year) + off;
  }
  else
    if (strchr(s, '-') == NULL)
    {
      strcpy(__date_tmp_string, s);
      
      int day = atoi(__date_tmp_string + 6); __date_tmp_string[6] = '\0';
      int month = atoi(__date_tmp_string + 4); __date_tmp_string[4] = '\0';
      int year = atoi(__date_tmp_string);
      long  off = 0L;
      
      if (year > 1000)
      {
        if (year < 1951) off -= DAYBIAS;
        if (year < 1851) off -= DAYBIAS;
        if (year < 1751) off -= DAYBIAS;
        year %= 100; // modify
      }
      _val = makedata(day, month, year) + off;
    }
    else _val = cpackdata((char*)s);
}


TDate::TDate(int day, int month, int year)

{
  if (day == TODAY)
  {
    char s[10];
    cgetdata(&_val, s);
  }
  else
    if ((day == 0) || (month == 0) || (year == 0)) _val = NULLDATE;
    else
    {
      long  off = 0L;
      
      if (year > 1000)
      {
        if (year < 1951) off -= DAYBIAS;
        if (year < 1851) off -= DAYBIAS;
        if (year < 1751) off -= DAYBIAS;
        year %= 100; // modify
      }
      _val = makedata(day, month, year) + off;
      if (!ok()) _val = NULLDATE;
    }
}

int TDate::last_day(int month, int year)
  // parse_filastrok(
  //    "trenta giorni case novembre
  //    con april, giugno e settembre
  //    case ventotto ce n'e' uno
  //    per default ce n'ha trentuno");
{
  int d;
  switch(month)
  {
  case 4:
  case 6:
  case 9:
  case 11:
    d = 30;
    break;
  case 2:
    d = year % 4 ? 28 : 29;
    break;
  default:
    d = 31;
    break;
  }
  return d;
}

void TDate::set_end_month()             
{
  _val = makedata(last_day(month(),year()),month(),year());                    
}

bool TDate::is_end_month()
{
  return day() == last_day(month(),year());
}

void  TDate::set_day(int n)   { _val = makedata(n, month(), year()); }  
void  TDate::set_month(int n) { _val = makedata(day(), n, year());   }  
void  TDate::set_year(int n)  { _val = makedata(day(), month(), n);  }  

TDate::operator const char*() const
{
  return string(4);
}


TDate& TDate::operator =(const char* s)
{
  return *this = TDate(s);
}


void TDate::print_on(ostream& out) const
{ 
  out << string();
}


void TDate::read_from(istream& in)
{
  char s[256];
  
  in >> s;
  if (isdate(s)) _val = cpackdata(s);
  else _val = NULLDATE;
}


char* TDate::string(int yeardgts, char sep) const

{
  if (!ok()) return "";
  long wv = _val;
  int cnt = wv >= DAYBIAS ? 2000 : 1900;
  
  while (wv < 0)
  {
    cnt -= 100;
    wv += DAYBIAS;
  }
  ceditdata(wv, __date_tmp_string);
  if (strcmp(__date_tmp_string, "  -  -  ") == 0) return "";
  if (sep != '-')
    for (char* s = __date_tmp_string; *s; s++)
      if (*s == '-') *s = sep;
  if (yeardgts > 2)
  {
    char s[8];
    int year = cnt + atoi(__date_tmp_string + 6);
    
    if (yeardgts == 3) sprintf(s, "%03d", year % 1000);
    else sprintf(s, "%04d", year);
    __date_tmp_string[6] = '\0';
    strcat(__date_tmp_string, s);
  }
  else
    if (yeardgts == ANSI)
    {
      char* s = __date_tmp_string; s[2] = '\0'; s[5] = '\0';
      const int day = atoi(s);
      const int month = atoi(s + 3);
      const int year = atoi(s + 6);
      
      sprintf(__date_tmp_string, "%04d%02d%02d", year, month, day);
    }
  return __date_tmp_string;
}


int TDate::day() const

{
  return ::day(_val);
}


int TDate::month() const

{
  return ::month(_val);
}


int TDate::year() const

{
  return ::year(_val);
}


void TDate::addmonth(int nmonth)

{
  _val = ::addmonth(_val, nmonth);
}


void TDate::addyear(int nyear)

{
  _val =  ::addyear(_val, nyear);
}


bool TDate::isdate(const char* s)
{
  if (!*s) return FALSE;
  if (strlen(s) == 10)
  {
    int day = atoi(s),
    month = atoi(&s[3]),
    year = atoi(&s[6]);
    if (day < 1 || day > 31 ||
        month < 1 || month > 12 ||
        year < 1700 || year > 2100)
      return FALSE;

    char s1[16];
    sprintf(s1, "%02d-%02d-%02d", day, month, year%100);
    return (bool)cverdata(s1);
  }

  return (bool)cverdata((char*)s);
}


bool TDate::ok() const
{
  return _val <= 2 * DAYBIAS && _val >= -2 * DAYBIAS;
}


TDate& operator +(const TDate& a, long nday)

{
  __tmp_date = long(a) + nday;
  return __tmp_date;
}


TDate& operator +(const long nday, const TDate& b)

{
  __tmp_date = long(b) + nday;
  return __tmp_date;
}


TDate& operator -(const TDate& a, long nday)

{
  __tmp_date = long(a)- nday;
  return __tmp_date;
}


void swap(TDate& a, TDate& b)

{
  __tmp_date = b;
  b = a;
  a = __tmp_date;
}


const TDate& fnc_min(const TDate& a, const TDate& b)

{
  if (a < b) return a;
  else return b;
}


const TDate& fnc_max(const TDate& a, const TDate& b)

{
  if (a > b) return a;
  else return b;
}


// Converte un numero da 1 a 12 nel corrispondente mese
const char* itom(byte m)
{
  const char* nomi[12] =
  {
    "Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno",
    "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"
    };

  return nomi[(m-1) % 12];
}

const char* itow(byte d)
{
  const char* nomi[7] =
  { "Lunedi", "Martedi", "Mercoledi",   "Giovedi", "Venerdi",
    "Sabato", "Domenica" };
  return nomi[(d-1) % 7];
}
