///////////////////////////////////////////////////////////////////////////
////                                                                   ////
////                           rtctimer.c                              ////
////                                                                   ////
//// Using the timer2 overflow interrupt, provides a time base and     ////
//// the functions needed for a time.h compatable library.  See time.h ////
//// for documentation of the time.h library.                          ////
////                                                                   ////
//// The Timer2 overflow rate must match the rate configured in        ////
//// CLOCKS_PER_SECOND!                                                ////
////                                                                   ////
///////////////////////////////////////////////////////////////////////////
////        (C) Copyright 1996,2007 Custom Computer Services           ////
//// This source code may only be used by licensed users of the CCS    ////
//// C compiler.  This source code may only be distributed to other    ////
//// licensed users of the CCS C compiler.  No other use,              ////
//// reproduction or distribution is permitted without written         ////
//// permission.  Derivative programs created using this software      ////
//// in object code form are not restricted in any way.                ////
///////////////////////////////////////////////////////////////////////////

#ifndef CLOCKS_PER_SECOND
#define CLOCKS_PER_SECOND 1000
#endif

#include <time.h>

#int_timer2
void updateClock()
{
 #if CLOCKS_PER_SECOND >= 0x10000
   static int32 t;
 #elif CLOCKS_PER_SECOND >= 0x100
   static int16 t;
 #else
   static int8 t;
 #endif
   
   t++;
   clock_ticks++;
   
   if(t >= CLOCKS_PER_SECOND)
   {
      t = 0;
      calendar_time++;  //seconds since Jan 1, 1970 00:00:00
   }
}

int DaysInMonth(int month, int1 IsLeapYear)
{
   switch(month)
   {
      case 0:
         return 31;
      
      case 1:
         if(IsLeapYear)
            return 29;            
         return 28;
      
      case 2:
         return 31;
      
      case 3:
         return 30;
      
      case 4:
         return 31;
      
      case 5:
         return 30;
      
      case 6:
         return 31;
      
      case 7:
         return 31;
      
      case 8:
         return 30;
      
      case 9:
         return 31;
      
      case 10:
         return 30;
      
      case 11:
         return 31;
      
      default:
         return 0;
   }
}

int1 LeapYear(int16 year)
{
   if((year + 1900) % 100 == 0)
   {
      if((year + 1900) % 400 == 0)
      {
         return TRUE;
      }
      return FALSE;
   }
   
   if((year + 1900) % 4 == 0)
   {
      return TRUE;
   }
   
   return FALSE;
}

void SetTime(struct_tm * nTime)
{   
   calendar_time = mktime(nTime);  
}
   
char * asctime ( struct_tm * timeptr, char * szTime)
{
   char szDay[8];
   char szMon[8];
   
   WeekdayAbbreviations(timeptr->tm_wday, szDay);
   MonthAbbreviations(timeptr->tm_mon, szMon);
   
   sprintf(szTime,"%s %s %d %02d:%02d:%02d %04Lu",
      szDay,
      szMon,
      timeptr->tm_mday + 1,
      timeptr->tm_hour,
      timeptr->tm_min,
      timeptr->tm_sec,
      (timeptr->tm_year + 1900));
      
   return szTime;
}

clock_t clock()
{
   return clock_ticks;
}

/* Times later and earlier are expressed in seconds */
double difftime(time_t later, time_t earlier)
{
   return (later - earlier);
}

time_t mktime(struct_tm * timeT)
{
   time_t unixTime = 0;
   int1 isLeapYear = FALSE;
   int i = 0;
   
   if(timeT != NULL)
   {
   
      unixTime += timeT->tm_sec;
      unixTime += (int32)(timeT->tm_min) * 60;
      unixTime += (int32)(timeT->tm_hour) * 3600;
      
      isLeapYear = LeapYear(timeT->tm_year);
       /* Clamp the month to [0,11) */
      timeT->tm_mon %= 12;
      for(i = 1;i <= timeT->tm_mon;i++)
      {
         unixTime += (DaysInMonth(i - 1,isLeapYear) * 86400);
      }
      
      /* Clamp the days in the month */
      timeT->tm_mday %= DaysInMonth(timeT->tm_mon,isLeapYear);
      unixTime += (timeT->tm_mday) * 86400;
      
      if(isLeapYear)
      {
         timeT->tm_yday = (unixTime / 86400) % 366;
      }
      else
      {
         timeT->tm_yday = (unixTime / 86400) % 365;
      }
      
      i = 70;
      if(timeT->tm_year - 70 >= 0)
      {
         while(i < (timeT->tm_year))
         {
            isLeapYear = LeapYear(i);
            if(isLeapYear)
            {
               unixTime += (366 * 24 * 3600);
            }
            else
            {
               unixTime += (365 * 24 * 3600);
            }
            i++;
         }
      }
      
      timeT->tm_wday = ((unixTime / 86400) + 4) % 7;
   }

   return unixTime;
}

time_t time(time_t * timer)
{
   if(timer != NULL)
   {
      *timer = calendar_time;
   }
   
   return calendar_time;
}

struct_tm g_lTime;

struct_tm * localtime(time_t * timer)
{
   time_t timeCounter;
   int1 done = FALSE;
   int1 isLeapYear = FALSE;//1970 is not a leap year

   if(timer != NULL)
   {
      timeCounter = *timer;
      g_lTime.tm_wday = ((timeCounter / 86400) + 4) % 7;//fill in the weekday
      g_lTime.tm_year = 70;//we are starting in 1970
      
      while(!done)
      {
         if(timeCounter < (366 * 86400) && isLeapYear)
         {
            g_lTime.tm_yday = (timeCounter / 86400);
            break;
         }
         else if(timeCounter < (365 * 86400))
         {
            g_lTime.tm_yday = (timeCounter / 86400);
            break;
         }
         
         if(isLeapYear)
         {
            timeCounter -= 366 * 24 * 3600;
         }
         else
         {
            timeCounter -= 365 * 24 * 3600;
         }
         
         g_lTime.tm_year++;
         isLeapYear = LeapYear(g_lTime.tm_year);
      }
      
      g_lTime.tm_mon = 0;
      while(!done)
      {         
         if(timeCounter < DaysInMonth(g_lTime.tm_mon,isLeapYear) * 86400)
         {
            break;
         }
         else if(timeCounter >= DaysInMonth(g_lTime.tm_mon,isLeapYear) * 86400)
         {
            timeCounter -= DaysInMonth(g_lTime.tm_mon,isLeapYear) * 86400;
            g_lTime.tm_mon++;
         }
      }  

      g_lTime.tm_mday = (timeCounter / (24 * 3600));
      timeCounter -= (g_lTime.tm_mday * (24 * 3600));
      
      g_lTime.tm_hour = (timeCounter / (3600));
      timeCounter -= ((int32)g_lTime.tm_hour) * 3600;
      
      g_lTime.tm_min = (timeCounter / 60);
      timeCounter -= (((int16)g_lTime.tm_min) * 60);
     
      g_lTime.tm_sec = timeCounter;
   }
   
   return &g_lTime;
}

char * ctime ( time_t * timer, char *szTime )
{
   char szDay[8];
   char szMon[8];
   struct_tm sTime;

   memcpy(&sTime, localtime(timer),sizeof(sTime));
   WeekdayAbbreviations(sTime.tm_wday,szDay);
   MonthAbbreviations(sTime.tm_mon,szMon);
   
   sprintf(szTime,"%s %s %d %02d:%02d:%02d %04Lu",
      (szDay),
      (szMon),
      sTime.tm_mday + 1,// you cant have jan 0
      sTime.tm_hour,
      sTime.tm_min,
      sTime.tm_sec,
      (sTime.tm_year + 1900));
      
   return szTime;
}

void WeekdayAbbreviations(int day, char* wString)
{
   switch(day)
   {
      case 0:
      memcpy(wString,"Sun\0",4);
      break;
      
      case 1:
      memcpy(wString,"Mon\0",4);
      break;
      
      case 2:
      memcpy(wString,"Tue\0",4);
      break;
      
      case 3:
      memcpy(wString,"Wed\0",4);
      break;
      
      case 4:
      memcpy(wString,"Thu\0",4);
      break;
      
      case 5:
      memcpy(wString,"Fri\0",4);
      break;
      
      case 6:
      memcpy(wString,"Sat\0",4);
      break;
      
      default:
      memcpy(wString,"Invalid\0",8);
      break;
   }
}

void MonthAbbreviations(int month, char* mString)
{
   switch(month)
   {
      case 0:
      memcpy(mString,"Jan\0",4);
      break;
      
      case 1:
      memcpy(mString,"Feb\0",4);
      break;
      
      case 2:
      memcpy(mString,"Mar\0",4);
      break;
      
      case 3:
      memcpy(mString,"Apr\0",4);
      break;
      
      case 4:
      memcpy(mString,"May\0",4);
      break;
      
      case 5:
      memcpy(mString,"Jun\0",4);
      break;
      
      case 6:
      memcpy(mString,"Jul\0",4);
      break;
      
      case 7:
      memcpy(mString,"Aug\0",4);
      break;
      
      case 8:
      memcpy(mString,"Sep\0",4);
      break;
      
      case 9:
      memcpy(mString,"Oct\0",4);
      break;
      
      case 10:
      memcpy(mString,"Nov\0",4);
      break;
      
      case 11:
      memcpy(mString,"Dec\0",4);
      break;
      
      default:
      memcpy(mString,"Invalid\0",8);
      break;
   }
}
