// CClock.cpp : implementation file
//

#include "stdafx.h"
#include "resource.h"
#include "CClock.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
// One second timer, we need this one only onceCClock
//UINT CClock::

/////////////////////////////////////////////////////////////////////////////
// CClock

/////////////////////////////////////////////////////////////////////////////
// CClock::CClock()
// 
// 
/////////////////////////////////////////////////////////////////////////////
CClock::CClock()
{
  // Bitmap for clock
  m_bmClock.LoadBitmap(IDB_CLOCK);
  m_bmClock.GetObject(sizeof(m_bmInfoClock), &m_bmInfoClock);

  // Bitmap for small digits
  m_bmSmall.LoadBitmap(IDB_SMALL);
  m_bmSmall.GetObject(sizeof(m_bmInfoSmall), &m_bmInfoSmall);

  // Bitmap for big digits
  m_bmBig.LoadBitmap(IDB_BIG);
  m_bmBig.GetObject(sizeof(m_bmInfoBig), &m_bmInfoBig);

  // First time must draw entire clock
  m_iOneSecTimerId = 0;
  m_DontPutClock = FALSE;

  // Preset some variables
  ResetClock();
} // End of constructor


/////////////////////////////////////////////////////////////////////////////
// CClock::~CClock()
// 
// 
/////////////////////////////////////////////////////////////////////////////
CClock::~CClock()
{
} // End of destructor


BEGIN_MESSAGE_MAP(CClock, CStatic)
	//{{AFX_MSG_MAP(CClock)
	ON_WM_PAINT()
	ON_WM_TIMER()
	ON_WM_DESTROY()
	ON_WM_ERASEBKGND()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CClock message handlers

/////////////////////////////////////////////////////////////////////////////
// void CClock::OnPaint() 
// 
// 
/////////////////////////////////////////////////////////////////////////////
void CClock::OnPaint() 
{
  CPaintDC dc(this);

  DrawDateTime( &dc);

  // Do not call CStatic::OnPaint() for painting messages
} // End of OnPaint

/////////////////////////////////////////////////////////////////////////////
// void CClock::OnTimer(UINT nIDEvent) 
// 
// 
/////////////////////////////////////////////////////////////////////////////
void CClock::OnTimer(UINT nIDEvent) 
{
  // Our timer
  if (nIDEvent == TMR_SEC)
    CheckDateTime();

  CStatic::OnTimer(nIDEvent);
} // End of OnTimer

/////////////////////////////////////////////////////////////////////////////
// void CClock::CheckDateTime(BOOL AvoidRepaint)
// 
// 
/////////////////////////////////////////////////////////////////////////////
void CClock::CheckDateTime(BOOL AvoidRepaint)
{
  time_t tempTime;
  tm* P_t;
  char str[80];
  char data[40],ora[40];
  BOOL AskInvalidate;

	AskInvalidate = FALSE;

	time(&tempTime);
	if (tempTime != m_time)
	{
    m_time = tempTime;
    P_t = localtime(&m_time);
          
    strcpy(str, asctime(P_t));

	  memset(data,0,40);
    memset(ora,0,40);

	  sprintf(data,"%02d %02d ",P_t->tm_mday, P_t->tm_mon+1);
    // Year 2000 problem
    memcpy(&data[strlen(data)],&str[strlen(str)-5],4);

		sprintf(ora, "%02d:%02d:%02d", P_t->tm_hour, P_t->tm_min, P_t->tm_sec);

		// Day changed?
    if (P_t->tm_mday != m_old_mday)
		{
      m_idxDigit[6] = data[0] - 48;
      m_idxDigit[7] = data[1] - 48;
      m_old_mday = P_t->tm_mday;
      // Ask an invalidate
			AskInvalidate = TRUE;
		}

    // Month changed?
    if (P_t->tm_mon != m_old_mon)
	  {
      m_idxDigit[8] = data[3] - 48;
      m_idxDigit[9] = data[4] - 48;
      m_old_mon = P_t->tm_mon;
			AskInvalidate = TRUE;
	  }

    // Year changed? (Happy new year!)
    if (P_t->tm_year != m_old_year)
	  {
      m_idxDigit[10] = data[6] - 48;
      m_idxDigit[11] = data[7] - 48;
      m_idxDigit[12] = data[8] - 48;
      m_idxDigit[13] = data[9] - 48;
      m_old_year = P_t->tm_year;
			AskInvalidate = TRUE;
	  }

    // Hour changed?
    if (P_t->tm_hour != m_old_hour)
	  {
      m_idxDigit[0] = ora[0] - 48;
      m_idxDigit[1] = ora[1] - 48;
      m_old_hour = P_t->tm_hour;
	    AskInvalidate = TRUE;
	  }

    // Minutes changed?
    if (P_t->tm_min != m_old_min)
	  {
      m_idxDigit[2] = ora[3] - 48;
      m_idxDigit[3] = ora[4] - 48;
      m_old_min = P_t->tm_min;
	    AskInvalidate = TRUE;
	  }

    // Seconds changed?
    if (P_t->tm_sec != m_old_sec)
	  {
      m_idxDigit[4] = ora[6] - 48;
      m_idxDigit[5] = ora[7] - 48;
      m_old_sec = P_t->tm_sec;
	    AskInvalidate = TRUE;
	  }

	  if (AvoidRepaint == TRUE) AskInvalidate = FALSE;

	  if (AskInvalidate == TRUE)
	  {
		  // just for debug...
      //GetOwner()->SetWindowText(ora); 
      
      m_DontPutClock = TRUE;

      Invalidate( FALSE);
			UpdateWindow();
		 }
	}
} // End of CheckDateTime

/////////////////////////////////////////////////////////////////////////////
// void CClock::DrawDateTime(CDC* pDC)
// 
// 
/////////////////////////////////////////////////////////////////////////////
void CClock::DrawDateTime(CDC* pDC)
{
  CDC dcCompatible;
  dcCompatible.CreateCompatibleDC(pDC);


  // Start timer (1 second), only the first time
  if (!m_iOneSecTimerId) 
    m_iOneSecTimerId = SetTimer(TMR_SEC, 1000, NULL);

  // First time the application runs and each time we gota WM_PAINT from
  // Windows we have to draw the entire clock
  if (m_DontPutClock == FALSE)
  {

    dcCompatible.SelectObject(&m_bmClock);
    pDC->BitBlt(1, 1, m_bmInfoClock.bmWidth, m_bmInfoClock.bmHeight, &dcCompatible, 0, 0, SRCCOPY);
    ResetClock();
    CheckDateTime(TRUE);
  }
    
  dcCompatible.SelectObject(&m_bmBig);

	// Update hour?
  if (m_idxDigit[0] != -1)
  {

    pDC->BitBlt(0+OFSX_H1, 0+OFSY_H1, WIDTH_BIG, m_bmInfoBig.bmHeight, &dcCompatible, WIDTH_BIG*m_idxDigit[0], 0, SRCCOPY);
    pDC->BitBlt(0+OFSX_H2, 0+OFSY_H2, WIDTH_BIG, m_bmInfoBig.bmHeight, &dcCompatible, WIDTH_BIG*m_idxDigit[1], 0, SRCCOPY);
	  // Mark updated
	  m_idxDigit[0] = -1;
	  m_idxDigit[1] = -1;
  }
    
  // Update minutes?
  if (m_idxDigit[2] != -1)
  {
    pDC->BitBlt(0+OFSX_M1, 0+OFSY_M1, WIDTH_BIG, m_bmInfoBig.bmHeight, &dcCompatible, WIDTH_BIG*m_idxDigit[2], 0, SRCCOPY);
    pDC->BitBlt(0+OFSX_M2, 0+OFSY_M2, WIDTH_BIG, m_bmInfoBig.bmHeight, &dcCompatible, WIDTH_BIG*m_idxDigit[3], 0, SRCCOPY);
	  // Mark updated
	  m_idxDigit[2] = -1;
	  m_idxDigit[3] = -1;
  }
    
  dcCompatible.SelectObject(&m_bmSmall);

  // Update seconds?
  if (m_idxDigit[4]!= -1)
  {
    pDC->BitBlt(0+OFSX_S1, 0+OFSY_S1, WIDTH_SMALL, m_bmInfoSmall.bmHeight, &dcCompatible, WIDTH_SMALL*m_idxDigit[4], 0, SRCCOPY);
    pDC->BitBlt(0+OFSX_S2, 0+OFSY_S2, WIDTH_SMALL, m_bmInfoSmall.bmHeight, &dcCompatible, WIDTH_SMALL*m_idxDigit[5], 0, SRCCOPY);
	  // Mark updated
	  m_idxDigit[4] = -1;
	  m_idxDigit[5] = -1;
  }
    
  // Updated day?
  if (m_idxDigit[6]!= -1)
  {
    pDC->BitBlt(0+OFSX_MDAY1, 0+OFSY_MDAY1, WIDTH_SMALL, m_bmInfoSmall.bmHeight, &dcCompatible, WIDTH_SMALL*m_idxDigit[6], 0, SRCCOPY);
    pDC->BitBlt(0+OFSX_MDAY2, 0+OFSY_MDAY2, WIDTH_SMALL, m_bmInfoSmall.bmHeight, &dcCompatible, WIDTH_SMALL*m_idxDigit[7], 0, SRCCOPY);
	  // Mark updated
	  m_idxDigit[6] = -1;
	  m_idxDigit[7] = -1;
  }
    
  // Update month?
  if (m_idxDigit[8]!= -1)
  {
    pDC->BitBlt(0+OFSX_MON1, 0+OFSY_MON1, WIDTH_SMALL, m_bmInfoSmall.bmHeight, &dcCompatible, WIDTH_SMALL*m_idxDigit[8], 0, SRCCOPY);
    pDC->BitBlt(0+OFSX_MON2, 0+OFSY_MON2, WIDTH_SMALL, m_bmInfoSmall.bmHeight, &dcCompatible, WIDTH_SMALL*m_idxDigit[9], 0, SRCCOPY);
	  // Mark updated
	  m_idxDigit[8] = -1;
	  m_idxDigit[9] = -1;
  }
    
  // Update year?
  if (m_idxDigit[10]!= -1)
  {
    pDC->BitBlt(0+OFSX_YEAR1, 0+OFSY_YEAR1, WIDTH_SMALL, m_bmInfoSmall.bmHeight, &dcCompatible, WIDTH_SMALL*m_idxDigit[10], 0, SRCCOPY);
    pDC->BitBlt(0+OFSX_YEAR2, 0+OFSY_YEAR2, WIDTH_SMALL, m_bmInfoSmall.bmHeight, &dcCompatible, WIDTH_SMALL*m_idxDigit[11], 0, SRCCOPY);
    pDC->BitBlt(0+OFSX_YEAR3, 0+OFSY_YEAR3, WIDTH_SMALL, m_bmInfoSmall.bmHeight, &dcCompatible, WIDTH_SMALL*m_idxDigit[12], 0, SRCCOPY);
    pDC->BitBlt(0+OFSX_YEAR4, 0+OFSY_YEAR4, WIDTH_SMALL, m_bmInfoSmall.bmHeight, &dcCompatible, WIDTH_SMALL*m_idxDigit[13], 0, SRCCOPY);
	// Aggiornato
	  m_idxDigit[10] = -1;
	  m_idxDigit[11] = -1;
	  m_idxDigit[12] = -1;
	  m_idxDigit[13] = -1;
  }
} // End of DrawDateTime

/////////////////////////////////////////////////////////////////////////////
// void CClock::ResetClock()
// 
// 
/////////////////////////////////////////////////////////////////////////////
void CClock::ResetClock()
{
  int loop;
  // Preset some variables...
  m_old_hour = -1;
  m_old_min = -1;
  m_old_sec = -1;
  m_old_mday = -1;
  m_old_mon = -1;
  m_old_year = -1;
  m_time = -1;
  for(loop = 0; loop < 14; loop++) m_idxDigit[loop] = -1;
  // m_idxDigit positions
  //  0 hour-left
  //  1 hour-right
  //  2 min-left
  //  3 min-right
  //  4 sec-left
  //  5 sec-right
  //  6 day-left
  //  7 day-right
  //  8 month-left
  //  9 month-right
  // 10 century-left
  // 11 century-right
  // 12 year-left
  // 13 year-right
} // End of ResetClock

/////////////////////////////////////////////////////////////////////////////
// void CClock::OnDestroy() 
// 
// 
/////////////////////////////////////////////////////////////////////////////
void CClock::OnDestroy() 
{
  // I'm not sure this has to be done. 
  // When the control is destroyed just kill our timer
  CStatic::OnDestroy();
	
  // TODO: Add your message handler code here
  if (m_iOneSecTimerId)
  {

    KillTimer( m_iOneSecTimerId);

    m_iOneSecTimerId = 0; //mark timer as inactive
  }
} // End of OnDestroy

/////////////////////////////////////////////////////////////////////////////
// BOOL CClock::SubclassDlgItem(UINT nID, CWnd * pParent)
// 
// 
/////////////////////////////////////////////////////////////////////////////
BOOL CClock::SubclassDlgItem(UINT nID, CWnd * pParent)
{
  CRect lpParentRect;
  CRect lpRect;
  int nDeltaX, nDeltaY;

  BOOL retValue = CStatic::SubclassDlgItem(nID, pParent);
  // If something wrong then do nothing
  if (retValue == 0) return 0;

  // Get parent window size
  pParent->GetClientRect(lpParentRect);
  pParent->ClientToScreen(lpParentRect);
  
  // Get CStatic size
  GetClientRect(lpRect);
  ClientToScreen(lpRect);

  // Modify control rect to exact clock size
  nDeltaX = lpRect.left - lpParentRect.left;
  nDeltaY = lpRect.top - lpParentRect.top;
  lpRect.left += nDeltaX;
  lpRect.top += nDeltaY;

  lpRect.right = lpRect.left + m_bmInfoClock.bmWidth + 2;
  lpRect.bottom = lpRect.top + m_bmInfoClock.bmHeight + 2;

  ScreenToClient(lpRect);
  MoveWindow(lpRect);
  return retValue;
}

/////////////////////////////////////////////////////////////////////////////
// BOOL CClock::OnEraseBkgnd(CDC* pDC) 
// 
// 
/////////////////////////////////////////////////////////////////////////////
BOOL CClock::OnEraseBkgnd(CDC* pDC) 
{
	// TODO: Add your message handler code here and/or call default
	
  m_DontPutClock = FALSE;
  //return TRUE;
  return CStatic::OnEraseBkgnd(pDC);
}
