// MaskEdit.cpp : implementation file
//

#include "stdafx.h"
//#include "CTMS.h"
#include "MaskEdit.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CMaskEdit

IMPLEMENT_DYNAMIC(CMaskEdit, CEdit)

CMaskEdit::CMaskEdit()
{
  m_bUseMask = FALSE;
  m_strMask = _T("");
  m_strLiteral = _T("");
  m_strValid = _T("");
  m_strHours = _T("24");
  m_strMins = _T("59");
  m_bMaskKeyInProgress = FALSE;
  m_strMaskLiteral = _T("");
}

CMaskEdit::~CMaskEdit()
{
}


BEGIN_MESSAGE_MAP(CMaskEdit, CEdit)
	//{{AFX_MSG_MAP(CMaskEdit)
	ON_WM_CHAR()
	ON_WM_KEYDOWN()
	ON_CONTROL_REFLECT(EN_UPDATE, OnUpdate)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMaskEdit message handlers

/////////////////////////////////////////////////////////////////////////////
// void CMaskEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
// 
// 
/////////////////////////////////////////////////////////////////////////////
void CMaskEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
	if (!m_bMaskKeyInProgress)
	if (!CheckChar(nChar)) return;

	if (m_bUseMask)
	{
		if (isprint(nChar))
		{
			// si un masque existe, on est en insert mode
			int startPos, endPos;
			GetSel(startPos, endPos);
			SetSel(startPos, endPos+1);
			Clear();
			m_str.SetAt(endPos, (char)nChar); // added this
		}
		else if (nChar == VK_BACK)
		{
			int startPos, endPos;
			GetSel(startPos, endPos);
			// sanity range check
			if ((startPos == endPos) && (startPos >= 1) && (startPos <= m_str.GetLength()))
			{
				char c = 0;
		        // get the masked literal representation
			    if (!m_strMaskLiteral.IsEmpty())
					c = m_strMaskLiteral[startPos-1];
				TRACE("m_strMaskLiteral = [%s](%s)\n", m_strMaskLiteral, m_str);
				// back space the cursor
				SendMessage(WM_KEYDOWN, VK_LEFT, 0);
				if (!m_strMaskLiteral.IsEmpty())
				{
					// update the char backspacing over
					SendChar(c);

					// back space the cursor again
					SendMessage(WM_KEYDOWN, VK_LEFT, 0);
				}
			}
			else // out of range or have more than one char selected
				MessageBeep((UINT)-1);
			return;
		}
	}

	CEdit::OnChar(nChar, nRepCnt, nFlags);

	if (!m_bMaskKeyInProgress && m_bUseMask && !m_strLiteral.IsEmpty())
	{
		int startPos, endPos;
		GetSel(startPos, endPos);
		// make sure the string is not longer than the mask
		if (endPos < m_strLiteral.GetLength())
		{
			UINT c = m_strLiteral.GetAt(endPos);
			if (c != '_') SendChar(c);
		}
	}
}

/////////////////////////////////////////////////////////////////////////////
// void CMaskEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
// 
// 
/////////////////////////////////////////////////////////////////////////////
void CMaskEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
  // si un masque existe, tester les touches spéciales
  if (m_bUseMask)
  {
    switch (nChar)
    {
      case VK_DELETE:
      case VK_INSERT: return;
    }
  }
	
	CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
}

/////////////////////////////////////////////////////////////////////////////
// void CMaskEdit::OnUpdate() 
// 
// 
/////////////////////////////////////////////////////////////////////////////
void CMaskEdit::OnUpdate() 
{
	// TODO: If this is a RICHEDIT control, the control will not
	// send this notification unless you override the CEdit::OnInitDialog()
	// function to send the EM_SETEVENTMASK message to the control
	// with the ENM_UPDATE flag ORed into the lParam mask.
	
	// TODO: Add your control notification handler code here
  CString t;
  GetWindowText( t);
}

/////////////////////////////////////////////////////////////////////////////
// void CMaskEdit::SetMask(LPCSTR lpMask, LPCSTR lpLiteral, LPCSTR lpValid)
// 
// 
/////////////////////////////////////////////////////////////////////////////
void CMaskEdit::SetMask(LPCSTR lpMask, LPCSTR lpLiteral, LPCSTR lpValid)
{
  m_bUseMask = FALSE;
  if (lpMask == NULL) return;
  m_strMask = lpMask;
  if (m_strMask.IsEmpty()) return;
  if (lpLiteral != NULL)
  {
    m_strLiteral = lpLiteral;
    if (m_strLiteral.GetLength() != m_strMask.GetLength())
      m_strLiteral.Empty();
  }
  else
    m_strLiteral.Empty();
  if (lpValid != NULL)
    m_strValid = lpValid;
  else
    m_strValid.Empty();
  m_bUseMask = TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// void CMaskEdit::SendChar(UINT nChar)
// 
// 
/////////////////////////////////////////////////////////////////////////////
void CMaskEdit::SendChar(UINT nChar)
{
  m_bMaskKeyInProgress = TRUE;
  #ifdef WIN32
    AfxCallWndProc(this, m_hWnd, WM_CHAR, nChar, 1);
  #else
    SendMessage(WM_CHAR, nChar, 1);
  #endif
  m_bMaskKeyInProgress = FALSE;
}

/////////////////////////////////////////////////////////////////////////////
// BOOL CMaskEdit::CheckChar(UINT nChar)
// 
// 
/////////////////////////////////////////////////////////////////////////////
BOOL CMaskEdit::CheckChar(UINT nChar)
{
  UINT c;

  // do not use mask
  if (!m_bUseMask) return TRUE;

  // control character, OK
  if (!isprint(nChar)) return TRUE;
	
  // unselect all selections, if any
  int startPos, endPos;
  GetSel(startPos, endPos);
  SetSel(-1, 0);
  SetSel(startPos, startPos);

  // check the key against the mask
  GetSel(startPos, endPos);

  // make sure the string is not longer than the mask
  if (endPos >= m_strMask.GetLength())
  {
    MessageBeep((UINT)-1);
    return FALSE;
  }

  // check to see if a literal is in this position
  c = '_';
  if (!m_strLiteral.IsEmpty())
    c = m_strLiteral.GetAt(endPos);

  if (c != '_')
  {
    SendChar(c);
    GetSel(startPos, endPos);
  }

  // check the valid string character
  if (m_strValid.Find((char)nChar) != -1) return TRUE;

  // check the key against the mask
  c = m_strMask.GetAt(endPos);
  //BOOL doit = TRUE;
  switch (c)
  {
    case '0':		// digit only //completely changed this
    {
		BOOL doit = TRUE;
		if(isdigit(nChar))
		{
			if(m_isdate)
			{
				if(endPos == 0)
				{
					if(nChar > '3')
						doit = FALSE;
				}
				if(endPos == 1)
				{
					if(m_str.GetAt(0) == '3')
					{
						if(nChar > '1')
							doit = FALSE;
					}
				}
				if(endPos == 3)
				{
					if(nChar > '1')
						doit = FALSE;
				}
				if(endPos == 4)
				{
					if(m_str.GetAt(3) == '1')
					{
						if(nChar > '2')
							doit = FALSE;
					}
				}
			}
			else
			{
				if(endPos == 0)
				{
					if(nChar > (UINT)m_strHours[0])
						doit = FALSE;
				}
				if(endPos == 1)
				{
					if(m_str.GetAt(0) == m_strHours[0])
					{
						if(nChar > (UINT)m_strHours[1])
							doit = FALSE;
					}
				}
				if(endPos == 3)
				{
					if(nChar > (UINT)m_strMins[0])
						doit = FALSE;
				}
				if(endPos == 4)
				{
					if(m_str.GetAt(3) == m_strMins[0])
					{
						if(nChar > (UINT)m_strMins[1])
							doit = FALSE;
					}
				}
			}
	        return doit;
		}
      break;
    }
    case '9':		// digit or space
    {
      if (isdigit(nChar)) return TRUE;
      if (nChar != VK_SPACE) return TRUE;
      break;
    }
    case '#':		// digit or space or '+' or '-'
    {
      if (isdigit(nChar)) return TRUE;
      if (nChar == VK_SPACE || nChar == VK_ADD || nChar == VK_SUBTRACT) return TRUE;
      break;
    }
    case 'L':		// alpha only
    {
      if (isalpha(nChar)) return TRUE;
      break;
    }
    case '?':		// alpha or space
    {
      if (isalpha(nChar)) return TRUE;
      if (nChar == VK_SPACE) return TRUE;
      break;
    }
    case 'A':		// alpha numeric only
    {
      if (isalnum(nChar)) return TRUE;
      break;
    }
    case 'a':		// alpha numeric or space
    {
      if (isalnum(nChar)) return TRUE;
      if (nChar == VK_SPACE) return TRUE;
      break;
    }
    case '&':		// all print character only
    {
      if (isprint(nChar)) return TRUE;
      break;
    }
  }
  MessageBeep((UINT)-1);
  return FALSE;
}


/////////////////////////////////////////////////////////////////////////////
// COleDateTime read /write

/////////////////////////////////////////////////////////////////////////////
// COleDateTime ReadCOleDateTime(LPCSTR lpszData)
// 
// 
/////////////////////////////////////////////////////////////////////////////
static COleDateTime ReadCOleDateTime(LPCSTR lpszData)
{
  COleDateTime DateTime;
  DateTime.ParseDateTime(lpszData);
  return DateTime;
}

/////////////////////////////////////////////////////////////////////////////
// void FormatCOleDateTime(CString& strData, COleDateTime DateTime, int len)
// 
// 
/////////////////////////////////////////////////////////////////////////////
static void FormatCOleDateTime(CString& strData, COleDateTime DateTime, int len)
{
  strData = "";
  if (DateTime.m_dt == 0) return;
  if (len == 8)
    strData = DateTime.Format("%d/%m/%y");
  else if(len == 5) // added these two
	strData = DateTime.Format("%H:%M");
  else
    strData = DateTime.Format("%d/%m/%Y");
}

/////////////////////////////////////////////////////////////////////////////
// CTimeEdit

IMPLEMENT_DYNAMIC(CTimeEdit, CMaskEdit)

CTimeEdit::CTimeEdit()
{

  m_bUseMask = TRUE;
  m_isdate = FALSE; 
  m_strMask = _T("00:00");
  m_strLiteral = _T("__:__");
}

CTimeEdit::~CTimeEdit()
{
}


BEGIN_MESSAGE_MAP(CTimeEdit, CMaskEdit)
	//{{AFX_MSG_MAP(CTimeEdit)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTimeEdit message handlers


/////////////////////////////////////////////////////////////////////////////
// void CTimeEdit::SetTime(COleDateTime& Date)
// 
// 
/////////////////////////////////////////////////////////////////////////////
void CTimeEdit::SetTime(COleDateTime& Date)
{
  CString strText;
  FormatCOleDateTime(strText, Date, 5);
  m_str = m_strMaskLiteral = strText;
  SetWindowText(strText);
}

/////////////////////////////////////////////////////////////////////////////
// void CTimeEdit::SetTime(CString Time)
// 
// 
/////////////////////////////////////////////////////////////////////////////
void CTimeEdit::SetTime(CString Time)
{
	m_str = m_strMaskLiteral = Time;
	SetWindowText( Time);
}

/////////////////////////////////////////////////////////////////////////////
// COleDateTime CTimeEdit::GetTime()
// 
// 
/////////////////////////////////////////////////////////////////////////////
COleDateTime CTimeEdit::GetTime()
{
  CString strText;
  GetWindowText(strText);
  return ReadCOleDateTime(strText);
}

/////////////////////////////////////////////////////////////////////////////
// CString CTimeEdit::GetTimeStr()
// 
// 
/////////////////////////////////////////////////////////////////////////////
CString CTimeEdit::GetTimeStr()
{
	CString strText;
	GetWindowText(strText);
	return strText;
}

/////////////////////////////////////////////////////////////////////////////
// void CTimeEdit::SetHours(int hrs)
// 
// 
/////////////////////////////////////////////////////////////////////////////
void CTimeEdit::SetHours(int hrs)
{
	m_strHours.Format("%d", hrs);
}

/////////////////////////////////////////////////////////////////////////////
// void CTimeEdit::SetMins(int hrs)
// 
// 
/////////////////////////////////////////////////////////////////////////////
void CTimeEdit::SetMins(int hrs)
{
	m_strMins.Format("%d", hrs);
}

/////////////////////////////////////////////////////////////////////////////
// int CTimeEdit::GetHours()
// 
// 
/////////////////////////////////////////////////////////////////////////////
int CTimeEdit::GetHour()
{

  //get the displayed time
  CString strText;
  GetWindowText(strText);

  //return the actual hour part
  return atoi( strText.Left( 2));
}

/////////////////////////////////////////////////////////////////////////////
// int CTimeEdit::GetMins()
// 
// 
/////////////////////////////////////////////////////////////////////////////
int CTimeEdit::GetMinute()
{

  //get the displayed time
  CString strText;
  GetWindowText(strText);

  //return the actual minute part
  return atoi( strText.Right( 2));
}
