// DemoView.cpp : implementation of the CDemoView class
//

#include "stdafx.h"
#include "Demo.h"
#include "DemoDoc.h"
#include "DemoView.h"
#include "Serialport.h"
#include "iidk.h"


#pragma comment(lib, "iidk.lib")

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CDemoView

BOOL bStart = TRUE;
BOOL IsConnect  = FALSE; //for core

//**********************************
BOOL ExitComThread = FALSE;

CWinThread* pThread = NULL;

long CommandCount = 0;
CArray<Msg,Msg> m_Command;

CRITICAL_SECTION CritSec;
HANDLE CommandEvent;
HANDLE ExitThreadEvent;
//**********************************

void _stdcall func(LPCTSTR str)
{
	Msg msg;
	msg.StringToMsg(str);

	EnterCriticalSection(&CritSec);
	m_Command.Add(msg);
	LeaveCriticalSection(&CritSec);
	InterlockedIncrement(&CommandCount);
	SetEvent(CommandEvent);
}

IMPLEMENT_DYNCREATE(CDemoView, CEditView)

BEGIN_MESSAGE_MAP(CDemoView, CEditView)
	//{{AFX_MSG_MAP(CDemoView)
	ON_WM_DESTROY()
	ON_COMMAND(ID_CLEAR, OnClear)
	ON_WM_CHAR()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDemoView construction/destruction

CDemoView::CDemoView()
{
	m_bRestore = TRUE;

	m_Ip   = IP;
	m_Port = PORT;
	m_Id   = ID;

	m_ComPort = "COM1";

	m_pComPort = NULL;
}

CDemoView::~CDemoView()
{
}

BOOL CDemoView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	BOOL bPreCreated = CEditView::PreCreateWindow(cs);
	cs.style &= ~(ES_AUTOHSCROLL|WS_HSCROLL|WS_BORDER);	// Enable word-wrapping

	return bPreCreated;
}

/////////////////////////////////////////////////////////////////////////////
// CDemoView drawing

void CDemoView::OnDraw(CDC* pDC)
{
	CDemoDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
}

/////////////////////////////////////////////////////////////////////////////
// CDemoView diagnostics

#ifdef _DEBUG
void CDemoView::AssertValid() const
{
	CEditView::AssertValid();
}

void CDemoView::Dump(CDumpContext& dc) const
{
	CEditView::Dump(dc);
}

CDemoDoc* CDemoView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDemoDoc)));
	return (CDemoDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CDemoView message handlers

BOOL CDemoView::Connect()
{
    BOOL bOk = TRUE;
    int BaudRate, Parity, DataBits, StopBits, FlowControl;

	if(m_pComPort)
	  Disconnect();

    if(!m_pComPort)
	{
      m_pComPort = m_ComPort=="DEMO" ? NULL : new CSerialPort(m_ComPort);

	  if(!m_pComPort || !m_pComPort->IsValid())
	    bOk = FALSE;
	}

	if(!m_pComPort->IsValid())
		bOk = FALSE;

    if(bOk)
    {
		BaudRate	= 9600;
		DataBits	= 8;
		StopBits	= ONESTOPBIT;
		Parity		= NOPARITY;
		FlowControl = PCF_NOFLOWCTL;

        m_pComPort->SetBaudRate(BaudRate);
		m_pComPort->SetParityDataStop(Parity, DataBits, StopBits);
        m_pComPort->SetFlowControl(FlowControl);
    }

	if(bOk && m_pComPort)
	 DisplayText("Connecting to " + m_ComPort + " OK" + "\r\n");
	else
	 DisplayText("Connecting to " + m_ComPort + " FAILED" + "\r\n");

	return m_pComPort ? TRUE : FALSE;
}

void CDemoView::Disconnect()
{
	DisplayText("Disconnecting from " + m_ComPort + "..." + "\r\n");

	if(m_pComPort)
	{
     delete m_pComPort;
     m_pComPort = NULL;
	}
}

void CDemoView::Lost(LPCTSTR id)
{
 CString Id;

 Id = id;

 CString msg = "DEMO|"+Id+"|LOST";
 ::SendMsg(m_Id,msg);

 DisplayText(" Send: "+msg+"\r\n");

 m_bRestore = TRUE;
}

void CDemoView::Restore(LPCTSTR id)
{
 CString Id;

 Id = id;

 CString msg = "DEMO|"+Id+"|RESTORE";
 ::SendMsg(m_Id,msg);

 DisplayText(" Send: "+msg+"\r\n");

 m_bRestore = FALSE;
}

int CDemoView::GetDeviceAddress(LPCTSTR id)
{
	int i;
	DEVICE dev;
	int address;

	address = -1;
	for(i=0;i<m_Device.GetSize();i++)
	{
	 dev = m_Device.GetAt(i);

	 if(strcmp(dev.id,id)==0)
	 {
	  address = dev.address;
	  break;
	 }
	}

	return address;
}

void CDemoView::AddDevice(DEVICE device)
{
	int i;
	DEVICE dev;

	for(i=0;i<m_Device.GetSize();i++)
	{
	 dev = m_Device.GetAt(i);

	 if(strcmp(dev.id,device.id)==0)
	 {
	  m_Device.RemoveAt(i);
	  break;
	 }
	}

	m_Device.Add(device);
}

void CDemoView::DelDevice(DEVICE device)
{
	int i;
	DEVICE dev;

	for(i=0;i<m_Device.GetSize();i++)
	{
	 dev = m_Device.GetAt(i);

	 if(strcmp(dev.id,device.id)==0)
	 {
	  m_Device.RemoveAt(i);
	  break;
	 }
	}
}

void CDemoView::DeviceOn(DEVICE device)
{
 CString Id, Address;
 char buf[10];

 Id = device.id;
 itoa(device.address,buf,10);
 Address = buf;

 //CString msg = "DEMO_DEVICE|"+Id+"|ON|params<1>,param0_name<address>,param0_val<"+Address+">";
 CString msg = "DEMO_DEVICE|"+Id+"|ON|address<"+Address+">";
 ::SendMsg(m_Id,msg);

 DisplayText(" Send: "+msg+"\r\n");
}

void CDemoView::DeviceOff(DEVICE device)
{
 CString Id, Address;
 char buf[10];

 Id = device.id;
 itoa(device.address,buf,10);
 Address = buf;

 //CString msg = "DEMO_DEVICE|"+Id+"|OFF|params<1>,param0_name<address>,param0_val<"+Address+">";
 CString msg = "DEMO_DEVICE|"+Id+"|OFF|address<"+Address+">";
 ::SendMsg(m_Id,msg);

 DisplayText(" Send: "+msg+"\r\n");
}

void CDemoView::OnInitialUpdate() 
{
	CEditView::OnInitialUpdate();

    SetFont(CFont::FromHandle((HFONT)::GetStockObject(OEM_FIXED_FONT)),FALSE);

	if(bStart)
	{
	 bStart = FALSE;

     //Thread
	 ExitComThread = FALSE;

	 InitializeCriticalSection(&CritSec);
	 CommandEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
	 ExitThreadEvent = CreateEvent(NULL,FALSE,FALSE,NULL);

	 pThread = AfxBeginThread(DemoThread,this,0,0,0,NULL);

     if(!pThread)
	   AfxMessageBox("Starting thread error!");

	 Init();
	}
}

void CDemoView::Init()
{
	IsConnect = ::Connect(m_Ip,m_Port,m_Id, func);

	if (!IsConnect)
	  AfxMessageBox("Connecting core error!");

	if(!Connect())
	  AfxMessageBox("Connecting COM-port error!");
}

void CDemoView::Test()
{
	MessageBox("Test","Test");
}

void CDemoView::ClearText()
{
	GetEditCtrl().SetSel(0,-1);
	GetEditCtrl().Clear();
}

void CDemoView::DisplayText(LPCTSTR str)
{
	if (GetEditCtrl().GetLineCount()>500)
		GetEditCtrl().SetSel(0,-1);
	GetEditCtrl().ReplaceSel(str);
}

void CDemoView::DisplayMsg(Msg msg)
{
	DisplayText(msg.MsgToString()+"\r\n");
}

void CDemoView::OnDestroy()
{
	Disconnect();

	if(IsConnect)
	  ::Disconnect(m_Id);

	EnterCriticalSection(&CritSec);
	CommandCount = 0;
	m_Command.RemoveAll();
	LeaveCriticalSection(&CritSec);

	ExitComThread = TRUE;
	SetEvent(CommandEvent);
	::WaitForSingleObject(ExitThreadEvent, INFINITE);

	CEditView::OnDestroy();
}

UINT DemoThread(LPVOID pParam)
{
 CDemoView* pWnd = (CDemoView*)pParam;

 Msg msg;
 DEVICE device;

 while(!ExitComThread)
 {
  while(CommandCount)
  {
   InterlockedDecrement(&CommandCount);
   EnterCriticalSection(&CritSec);
   msg = m_Command.GetAt(0);
   m_Command.RemoveAt(0);
   LeaveCriticalSection(&CritSec);

   pWnd->DisplayMsg(msg);

   if(msg.GetAction() == "INIT")
   {
    pWnd->m_ComPort = msg.GetParam("port");

	pWnd->Connect();

	//if(pWnd->m_bRestore)
	  pWnd->Restore((LPCTSTR)msg.GetSourceId());
   }
   else if(msg.GetAction() == "EXIT")
   {
	pWnd->Lost((LPCTSTR)msg.GetSourceId());

	pWnd->Disconnect();
   }
   else if(msg.GetAction() == "SETUP_DEVICE")
   {
	strcpy(device.id,(LPCTSTR)msg.GetSourceId());
	device.address = msg.GetParamInt("address");

	pWnd->AddDevice(device);
   }
   else if(msg.GetAction() == "SETUP_DELDEVICE")
   {
	strcpy(device.id,(LPCTSTR)msg.GetSourceId());
	device.address = msg.GetParamInt("address");

	pWnd->DelDevice(device);
   }
   else if(msg.GetAction() == "ON")
   {
	strcpy(device.id,(LPCTSTR)msg.GetSourceId());
	device.address = pWnd->GetDeviceAddress((LPCTSTR)msg.GetSourceId());

	pWnd->DeviceOn(device);
   }
   else if(msg.GetAction() == "OFF")
   {
	strcpy(device.id,(LPCTSTR)msg.GetSourceId());
	device.address = pWnd->GetDeviceAddress((LPCTSTR)msg.GetSourceId());

	pWnd->DeviceOff(device);
   }
   else if(msg.GetAction() == "LOST")
   {
	pWnd->Lost((LPCTSTR)msg.GetSourceId());
   }
   else if(msg.GetAction() == "RESTORE")
   {
	pWnd->Restore((LPCTSTR)msg.GetSourceId());
   }
   if(msg.GetAction() == "TEST")
   {
	pWnd->Test();
   }
  }

  ::WaitForSingleObject(CommandEvent, INFINITE);
 }

 SetEvent(ExitThreadEvent);

 return 0;
}

BOOL CDemoView::PreTranslateMessage(MSG* pMsg) 
{	
	return CEditView::PreTranslateMessage(pMsg);
}

void CDemoView::OnClear() 
{
	ClearText();	
}

void CDemoView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
 //stub
}
