// mainview.cpp : implementation file
//

#include "stdafx.h"
#include "declient.h"
#include "mainview.h"
#include "servdlg.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CMainView

IMPLEMENT_DYNCREATE(CMainView, CFormView)

CMainView::CMainView()
  : CFormView(CMainView::IDD)
{
  m_s = INVALID_SOCKET;  // initialize socket to invalid handle
  
  //{{AFX_DATA_INIT(CMainView)
    // NOTE: the ClassWizard will add member initialization here
  //}}AFX_DATA_INIT
}

CMainView::~CMainView()
{
  // if the socket was opened successfully, close it

  if (m_s != INVALID_SOCKET)
  {
    closesocket(m_s);
    m_s = INVALID_SOCKET;
  }
}

void CMainView::DoDataExchange(CDataExchange* pDX)
{
  CFormView::DoDataExchange(pDX);
  //{{AFX_DATA_MAP(CMainView)
    // NOTE: the ClassWizard will add DDX and DDV calls here
  //}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CMainView, CFormView)
  //{{AFX_MSG_MAP(CMainView)
  ON_MESSAGE(WM_USER_ASYNC_SELECT, OnAsyncSelect)
  ON_WM_TIMER()
  //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMainView message handlers

void CMainView::OnInitialUpdate()
{
  // get pointer to list box used for status messages
  CListBox *plb = (CListBox *)GetDlgItem(IDC_LIST_STATUS);

  // prompt for server information (IP and port)
  CServerDlg dlg;
  if (dlg.DoModal() == IDCANCEL)
    return;

  plb->InsertString(0, "Initializing...");

  // create the socket
  m_s = socket(AF_INET, SOCK_DGRAM, 0);
  if (m_s == INVALID_SOCKET)
    plb->InsertString(0, "Datagram echo client could not create socket");
  else
  {
    // fill out the server's address
    m_addr.sin_family = AF_INET;
    m_addr.sin_port = htons(atoi(dlg.m_stringPort));
    m_addr.sin_addr.s_addr = inet_addr(dlg.m_stringIP);

    // save sending client's IP address
    memcpy(&m_in, &m_addr.sin_addr.s_addr, 4);

    // do the asynchronous select to wait for data
    if (WSAAsyncSelect(m_s, m_hWnd, WM_USER_ASYNC_SELECT,
     FD_READ | FD_WRITE) == SOCKET_ERROR)
      plb->InsertString(0, "Datagram echo client could not do async select");
    else
      SetTimer(1, 5000, NULL);
  }
}

/////////////////////////////////////////////////////////////////////////////
// CMainView::OnAsyncSelect()
//
LONG CMainView::OnAsyncSelect(WPARAM wParam, LPARAM lParam)
{
  char pszMessage[100];        // informational message
  static char pBuf[101];       // send/recv buffer
  int nBytesRecv;              // number of bytes received
  int nBytesSent;              // number of bytes sent
  int nError;                  // WinSock error

  // get pointer to list box used for status messages
  CListBox *plb = (CListBox *)GetDlgItem(IDC_LIST_STATUS);
 
  // check for an error
  if (WSAGETSELECTERROR(lParam) != 0)
  {
    wsprintf(pszMessage, "Datagrem echo client async select got error %d",
     WSAGETSELECTERROR(lParam));
    plb->InsertString(0, pszMessage);
    return 0L;
  }

  // what event are we being notified of?
  switch (WSAGETSELECTEVENT(lParam))
  {
    case FD_WRITE:
      plb->InsertString(0, "FD_WRITE");

      // is there any data to send?
      if (m_nBytesToSend != 0)
      {
        // send the data
        nBytesSent = sendto(m_s, m_pBuf, m_nBytesToSend, 0,
         (LPSOCKADDR)&m_addr, sizeof(m_addr));

        // check for send error
        if (nBytesSent == SOCKET_ERROR)
        {
          // if the error is just that the send would block,
          // don't do anything...we'll get another FD_WRITE soon
          nError = WSAGetLastError();
          if (nError != WSAEWOULDBLOCK);
          {
            wsprintf(pszMessage, "Error %d sending data to %s, %d",
             nError, inet_ntoa(m_in), ntohs(m_addr.sin_port));
            plb->InsertString(0, pszMessage);

            m_nBytesToSend = 0;
          }
        }
        else
        {
          wsprintf(pszMessage, "Data sent (%s) to %s, %d",
           m_pBuf, inet_ntoa(m_in), ntohs(m_addr.sin_port));
          plb->InsertString(0, pszMessage);

          m_nBytesToSend = 0;
        }
      }
      break;

    case FD_READ:
      plb->InsertString(0, "FD_READ");

      // receive data
      nBytesRecv = recvfrom(m_s, pBuf, 100, 0, NULL, NULL);

      // check for receive error
      if (nBytesRecv == SOCKET_ERROR)
      {
        // if the error is just that the receive would block,
        // don't do anything...we'll get another FD_READ soon
        nError = WSAGetLastError();
        if (nError != WSAEWOULDBLOCK)
        {
          wsprintf(pszMessage, "Error %d receiving data", nError);
          plb->InsertString(0, pszMessage);
        }
      }
      else
      {
        pBuf[nBytesRecv] = '\0';
        wsprintf(pszMessage, "Data received (%s) from %s, %d",
         pBuf, inet_ntoa(m_in), ntohs(m_addr.sin_port));
        plb->InsertString(0, pszMessage);
      }
      break;

    default:
      break;
  }

  return 0L;
}

/////////////////////////////////////////////////////////////////////////////
// CMainView::OnTimer()
//
// Timer to generate a string to send. Won't send
// unless the previous string is completely sent.
//
void CMainView::OnTimer(UINT nIDEvent)
{
  static int nSendCount = 1;   // 

  if (m_nBytesToSend == 0)
  {
    wsprintf(m_pBuf, "Hello %d", nSendCount);
    ++nSendCount;
    m_nBytesToSend = lstrlen(m_pBuf);
    PostMessage(WM_USER_ASYNC_SELECT, m_s, WSAMAKESELECTREPLY(FD_WRITE, 0));
  }
  
  CFormView::OnTimer(nIDEvent);
}
