/*
 *   Windows Calendar
 *   Copyright (c) 1985 by Microsoft Corporation, all rights reserved.
 *   Written by Mark L. Chamberlin, consultant to Microsoft.
 *
 ****** cal2.c
 *
 */

#include "cal.h"
#include <time.h>


HDC vhDCTemp;            /* Save code by not having to pass the HDC on each
                            call to DrawArrow and DrawArrowBorder. */


/**** CalPaint ****/

VOID APIENTRY CalPaint (
     HWND hwnd,
     HDC  hDC)
     {
     register D3  *pd3;

     if (hwnd == vhwnd1)
	  PatBlt (hDC, 0, vycoNotesBox, vcxWnd2A , vcyBorder, PATCOPY);

     if (hwnd == vhwnd2A)
          {
          DispTime (hDC);

          /* Assume we are in month mode so we will display the
             current date.
           */
          pd3 = &vd3Cur;

	  /* Set up global for DrawArrow and DrawArrowBorder. */
	  vhDCTemp = hDC;

#ifdef BUG_8560
	  /* We want the arrows to have the border color. */
	  SetTextColor (hDC, GetSysColor (COLOR_WINDOWFRAME));

	  /* Draw left arrow. */
	  DrawArrow (vhbmLeftArrow, vxcoLeftArrowFirst);

	  /* Draw border at left end of left arrow. */
	  DrawArrowBorder (vxcoLeftArrowFirst);

	  /* Draw border between left and right arrows. */
	  DrawArrowBorder (vxcoLeftArrowMax);

	  /* Draw right arrow. */
	  DrawArrow (vhbmRightArrow, vxcoRightArrowFirst);

	  /* Draw border to right of right arrow. */
	  DrawArrowBorder (vxcoRightArrowMax - vcxBorder);
#endif

	  /* Set colors back to defaults. */
	  SetDefaultColors (hDC);

	  /* Want to display the page date, not the current date. */
	  pd3 = &vd3Sel;

          DispDate (hDC, pd3);
          return;
          }

     if (hwnd == vhwnd2B)
	  {
	  PatBlt (hDC, 0, 0, vcxWnd2B+ vcxVScrollBar, vcyBorder, PATCOPY);

          if (vfDayMode)
               DayPaint (hDC);
          else
               {
               PaintMonthGrid (hDC);
               PaintMonth (hDC);
               }
          }
     }



#ifdef  BUG_8560
******************* The following are no longer required ********************

/**** DrawArrow ****/

VOID APIENTRY DrawArrow (
     HBITMAP hbm,
     INT     xco)
     {
     SelectObject (vhDCMemory, hbm);
     BitBlt (vhDCTemp, xco, vcyBorder, vcxHScrollBar, vcyHScrollBar,
             vhDCMemory, 0, 0, SRCCOPY);
     }




/**** DrawArrowBorder ****/

VOID APIENTRY DrawArrowBorder (INT  xco)
     {
     PatBlt (vhDCTemp, xco, 0, vcxBorder, vcyWnd2A, PATCOPY);
     }
************************ No longer required ********************************
#endif




/**** DispTime - Display the current time. ****/

VOID APIENTRY FAR DispTime (HDC  hDC)
     {
     CHAR sz [CCHTIMESZ + 2];   /* added 2 for spaces.  19 Sep 89 Clark Cyr */

     /* Convert the time into an ASCII string. */
     GetTimeSz (vftCur.tm, sz);
     lstrcat((LPSTR)sz, (LPSTR)"  ");

     /* Output the time. */
     TextOut (hDC, vcxFont, vcyExtLead, (LPSTR)sz,  lstrlen((LPSTR)sz));
     }




/**** GetTimeSz - convert the time into a zero terminated ASCII string. ****/
INT APIENTRY GetTimeSz (
     TM   tm,            /* The time to convert. */
     CHAR *sz)           /* pointer to the buffer to receive the string -
                            the caller should allocate CCHTIMESZ chars. */
     {
#ifndef NOCOMMON
    DOSTIME dt;

    dt.minutes = tm % 60;
    dt.hour = tm / 60;
    return(GetTimeString(&dt, sz, GTS_LEADINGZEROS | GTS_LEADINGSPACE));
#else
     WORD wHour;

     /* Put in the boiler plate. */
     lstrcpy (sz + 2, ":    ");

     wHour = tm / 60;

     if (!vfHour24)
          {
          lstrcpy (sz + 5, "am");
          if (wHour > 11)
               {
               /* Change to pm, and adjust down the hour. */
               *(sz + 5) = 'p';
               wHour -= 12;
               }
          /* Convert the 0 hour (midnight) to 12 (am is already selected). */
          if (wHour == 0)
               wHour = 12;
          }

     /* Convert the hours to ASCII. */
     ByteTo2Digs ((BYTE)wHour, sz);

     /* Change leading 0 to space if in 12 hour mode. */
     if (!vfHour24 && *sz == '0')
          *sz = ' ';

     /* Convert the minutes to ASCII. */
     ByteTo2Digs ((BYTE)(tm % 60), sz + 3);
#endif
     }



/****  ByteTo2Digs - convert byte to 2 decimal ASCII digits. ****/

VOID APIENTRY ByteTo2Digs (
     BYTE b,             /* The byte to convert from binary to ASCII. */
     CHAR *pch)          /* Pointer to output buffer (must be at least 2
                            chars long.
                          */
     {
     *pch++ = b / 10 + '0';
     *pch = b % 10 + '0';
     }



/**** DispDate - Display date in Wnd2A. */
VOID APIENTRY FAR DispDate (
     HDC  hDC,
     D3   *pd3)
     {
     RECT   rc;
     HBRUSH hbr;

     CHAR sz [CCHDATEDISP];

     /* Convert the current date into an ASCII string. */
     GetDateDisp (pd3, sz);

     /* Erase the background */
     GetClientRect(vhwnd2A, (LPRECT)&rc);
     rc.left = vxcoDate;
     if (hbr = CreateSolidBrush(GetSysColor(COLOR_WINDOW)))
         {
         FillRect(hDC, (LPRECT)&rc, hbr);
         DeleteObject(hbr);
         }
     else
         FillRect(hDC, (LPRECT)&rc, GetStockObject(WHITE_BRUSH));

     SetBkMode(hDC,TRANSPARENT);
     /*	Output the date. Use transparent mode so we don't erase the background
      * color.
      */
     TextOut (hDC, vxcoDate+2, vcyExtLead, (LPSTR)sz, lstrlen ((LPSTR)sz));
     SetBkMode(hDC,OPAQUE);
     }




/**** GetDateDisp - convert the date to an ASCII string of the form:
      weekday, month, day, year.  For example, "Sunday, March 30, 1985".
****/

VOID APIENTRY GetDateDisp (
    D3   *pd3,
    CHAR *sz)
    {
    DOSDATE dd;

    dd.dayofweek = 0xff;        /* so it'll calculate day of week */
    dd.year = pd3->wYear + 1980;
    dd.month = pd3->wMonth + 1;
    dd.day = pd3->wDay + 1;

    GetLongDateString(&dd, sz, GDS_LONG | GDS_DAYOFWEEK);
    }


/**** FillBuf - fill buffer with specified count of specified byte.
      Return a pointer to the buffer position following the filled bytes.
****/

BYTE * APIENTRY FillBuf (
     BYTE *pb,
     INT  cb,
     BYTE b)
     {
     while (cb--)
          *pb++ = b;

     return (pb);
     }


#ifndef NOCOMMON
/**** WordToASCII - convert word to ASCII digits - return a pointer
      to the first character following the generated digits.
****/

CHAR * APIENTRY WordToASCII (
     WORD  w,                      /* Word to convert. */
     CHAR *pch,                    /* Pointer to output buffer. */
     BOOL  fLeadZero)              /* TRUE for leading zeroes,
                                      FALSE to suppress leading zeroes.
                                    */
     {
     WORD wPlace;
     WORD wDig;

     for (wPlace = 10000; wPlace > 0; wPlace /= 10)
          {
          wDig = w / wPlace;
          w %= wPlace;
          if (wDig != 0 || fLeadZero || wPlace == 1)
               {
               *pch++ = wDig + '0';

               /* After the first digit gets put down, we're no longer
                  going to see leading zeros.  Prevent additional zeroes
                  from being suppressed by setting fLeadZero to TRUE.
               */
               fLeadZero = TRUE;
               }
          }

     return (pch);
     }

#endif




/**** GetDashDateSel - convert the selected date to an ASCII string
      of the form: mm-dd-yyyy.  For example, "4-21-1985".
****/

VOID APIENTRY GetDashDateSel (CHAR *sz)
     {
#ifndef NOCOMMON
    DOSDATE dd;

    dd.month = vd3Sel.wMonth + 1;
    dd.day = vd3Sel.wDay + 1;
    dd.year = vd3Sel.wYear + 1980;
    GetDateString(&dd, sz, GDS_SHORT);
#else
     sz = WordToASCII ((WORD)(vd3Sel.wMonth + 1), sz, FALSE);
     *sz++ = '-';
     sz = WordToASCII ((WORD)(vd3Sel.wDay + 1), sz, FALSE);
     *sz++ = '-';
     *(WordToASCII ((WORD)(vd3Sel.wYear + 1980), sz, FALSE)) = '\0';
#endif
     }



/**** FGetTmFromTimeSz
      The format for inputting the time is: [h]h[:mm][a|am|p|pm]
      In other words:
      - at least one digit must be used to specify the hour (even if it's 0)
      - the minutes are optional but if specified must be two digits preceded
        by a colon
      - the am/pm designation is optional and can be abbreviated by just a or p
      - The am/pm designation can use any combination of upper and lower case
      - If hours > 12 then OK if pm specified, but error if am specified.
      - if hours == 0 then OK if am specified, but error if pm specified.
      - If 1 <= hour <= 12 then default to am if no am/pm specification.
****/

INT  APIENTRY FGetTmFromTimeSz (
    CHAR *sz,           /* INPUT - ASCII time string. */
    TM   *ptm)          /* OUTPUT - converted time - unchanged if we
                           return FALSE.
                         */
    {
    DOSTIME dt;
    INT     iErr;

    if ((iErr = ParseTimeString(&dt, sz)) == 0)
    {
        *ptm = dt.hour * 60 + dt.minutes;
        return(TRUE);
    }

    return(iErr);
    }



/**** SkipSpace - skip spaces in a sz. ****/

VOID APIENTRY SkipSpace (CHAR **psz)
     {
     while (**psz == ' ')
          (*psz)++;
     }

#ifdef NOCOMMON

/**** FGetWord - convert ASCII digits into a word
      in the range 0 to 65535 inclusive.
****/

BOOL APIENTRY FGetWord (
     CHAR **ppch,
     WORD *pw)
     {
     LONG l;
     CHAR ch;

     l = 0;

     /* Must see at least one digit. */
     if (!isdigit (**ppch))
          return (FALSE);

     while (isdigit (ch = **ppch))
          {
          l = l * 10 + (ch - '0');
          (*ppch)++;
          if (l > 65535)
               return (FALSE);
          }

     *pw = (WORD)l;
     return (TRUE);
     }

#endif



/**** ChUpperCase - convert from lower to upper case. ****/

#ifdef DISABLE
CHAR APIENTRY ChUpperCase (CHAR ch)
     {
     return (ch >= 'a' && ch <= 'z' ? ch - 'a' + 'A' : ch);
     }
#endif



/**** FD3FromDateSz
      Format supported: mm-dd-yyyy
      (Slashes (/) may be used instead of dashes.)
      If the year is in the range 0 through 99, it is assumed that the
      low order digits of 19yy have been specified.
****/

BOOL APIENTRY FD3FromDateSz (
    CHAR *sz,           /* INPUT - ASCII date string. */
    D3   *pd3)          /* OUTPUT - converted date.  Unchanged if
                           we return FALSE.
                         */
    {
    DOSDATE dd;
    INT     iErr;

    if ((iErr = ParseDateString(&dd, sz)) == 0)
        {
        pd3->wMonth = dd.month - 1;
        pd3->wDay = dd.day - 1;
        pd3->wYear = dd.year - 1980;
        }

    return(iErr);
    }




/**** GetD3FromDt ****/

VOID APIENTRY GetD3FromDt (
     DT   dt,
     D3   *pd3)
     {
     register INT  cDaysYear;
     register INT  i;
     INT  cDaysMonth;

     /* See how many 4 year periods are in it (366 for leap year, 3 * 365
        for the next 3 years.
     */
     pd3 -> wYear = 4 * (dt / 1461);
     dt = dt % 1461;

     /* Account for the individual years.  Again, the first year is
       a leap year, the next two are normal (only two since we already
       divided by groups of 4 years).
     */
     cDaysYear = 366;
     while ((INT)dt >= cDaysYear)
          {
          dt -= (DT)cDaysYear;
          pd3 -> wYear++;
          cDaysYear = 365;
          }

     /* Subtract out days of each month.  Note that we add one
        to the count of days in the month for February in a leap year.
     */
     for (i = MONTHJAN; (INT)dt >= (cDaysMonth = vrgcDaysMonth [i] +
      (cDaysYear == 366 && i == MONTHFEB ? 1 : 0)); i++)
          dt -= (DT)cDaysMonth;

     pd3 -> wMonth = (WORD)i;

     /* Whatever's left is the offset into the month. */
     pd3 -> wDay = (WORD)dt;
     }



/**** Set text of an edit ctl and then place selection at end. */
VOID APIENTRY SetEcText(
     HWND    hwnd,
     CHAR *  sz)
     {
     WPARAM        iSelFirst;
     WPARAM        iSelLast;

     SetWindowText(hwnd, sz);
     iSelFirst = iSelLast = -1;
     SendMessage(hwnd, EM_SETSEL, iSelFirst, iSelLast);
     }
