// MissionControlSettingsDlg.cpp : implementation file
//

#include "stdafx.h"
#include <afxwin.h>
#include "Dashboard.h"
#include "DashboardRecipient.h"
#include "MissionControlSettingsDlg.h"
#include <remote/MMAhrs.h>
#include <remote/MMAlarm.h>
#include <remote/MMDepthSensor.h>
#include <remote/MMDeviceInfo.h>
#include <remote/MMDropWeight.h>
#include <remote/MMDvl.h>
#include <remote/MMDynamicControl.h>
#include <remote/MMGps.h>
#include <remote/MMHoming.h>
#include <remote/MMNavigation.h>
#include <remote/MMPower.h>
#include <remote/MMTailcone.h>
#include <remote/MMNmea.h>

#include "Attributes.h"
#include "AttributeParser.h"
#include "MessageList.h"
#include "MessageItem.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define DEFAULT_MSG_PERIOD 30 //seconds

/////////////////////////////////////////////////////////////////////////////
// CMissionControlSettingsDlg dialog

CMissionControlSettingsDlg::CMissionControlSettingsDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CMissionControlSettingsDlg::IDD, pParent)
{
	memset(m_messageRxCount, 0, ((ModemMessage::tEND + 1) * sizeof(int)));
	memset(m_messageTxCount, 0, ((ModemMessage::tEND + 1) * sizeof(int)));
	
	m_active = false;

	//{{AFX_DATA_INIT(CMissionControlSettingsDlg)
	m_freq1Str = _T("");
	m_onUpdateIndicator = 0.0f;
	m_baudRateIndicator = 0.0f;
	m_RequestBlockVal = FALSE;
	m_MessageConfigString = _T("");
	//}}AFX_DATA_INIT
}

CMissionControlSettingsDlg::~CMissionControlSettingsDlg()
{
	delete m_attributes;
	delete m_messageList;
}

void CMissionControlSettingsDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CMissionControlSettingsDlg)
	DDX_Control(pDX, IDC_LIST2, m_list2);
	DDX_Control(pDX, IDC_FREQ1, m_freq1);
	DDX_Control(pDX, IDC_LIST1, m_list1);
	DDX_Text(pDX, IDC_FREQ1, m_freq1Str);
	DDV_MaxChars(pDX, m_freq1Str, 8);
	DDX_Check(pDX, IDC_REQUESTBLOCK, m_RequestBlockVal);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CMissionControlSettingsDlg, CDialog)
	//{{AFX_MSG_MAP(CMissionControlSettingsDlg)
	ON_LBN_SELCHANGE(IDC_LIST1, OnSelchangeList1)
	ON_EN_CHANGE(IDC_FREQ1, OnChangeFreq1)
	ON_BN_CLICKED(IDUPDATE, OnUpdate)
	ON_BN_CLICKED(IDSTOP, OnStop)
	ON_BN_CLICKED(IDC_REQUESTBLOCK, OnRequestblock)
	ON_BN_CLICKED(IDC_ONCEBUTTON, OnOncebutton)
	ON_BN_CLICKED(IDC_ONUPDATEBUTTON, OnOnupdatebutton)
	ON_BN_CLICKED(IDC_WITHNAVBUTTON, OnWithnavbutton)
	ON_BN_CLICKED(IDC_PERIODICBUTTON, OnPeriodicbutton)
	ON_BN_CLICKED(IDC_STOPBUTTON, OnStopbutton)
	ON_WM_CLOSE()
	ON_LBN_SELCHANGE(IDC_LIST2, OnSelchangeList2)
	ON_BN_CLICKED(IDC_LOADBUTTON, OnLoadbutton)
	ON_BN_CLICKED(IDC_SAVEBUTTON, OnSavebutton)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BEGIN_EVENTSINK_MAP(CMissionControlSettingsDlg, CDialog)
    //{{AFX_EVENTSINK_MAP(CMissionControlSettingsDlg)
	//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMissionControlSettingsDlg message handlers

BOOL CMissionControlSettingsDlg::OnInitDialog()
{
	BOOL val = CDialog::OnInitDialog();
	
	m_attributes = new Attributes( "MessageControlSettings" );
	m_messageList = new MessageList( True );
	char fullConfigFile[256];
	strcpy( fullConfigFile, "MessageConfig/MessageControl.base");

	
     try {
         AttributeParser::parse(fullConfigFile, 
                                m_attributes,
                                m_messageList );
     }
	 catch(...)
     {
         // return;
     }
	
	CFont myFont;
	myFont.CreateFont(12,0,0,0,400,0,0,0,0,0,0,0,FIXED_PITCH | FF_MODERN,"Courier");
	m_list1.SetFont(&myFont, true);
	m_list2.SetFont(&myFont, true);
	myFont.Detach();

	m_active = true;

	OnSelchangeList1();
	return val;

}

void CMissionControlSettingsDlg::UpdateList1()
{
	int topIndex = m_list1.GetTopIndex();
	int sels[100];
	int selcount = m_list1.GetSelItems(100,sels);
	m_list1.SetRedraw(false);
	m_list1.ResetContent();
	m_list1.InitStorage(64,128);
	char str[128];
  	short count = m_messageList->MessageCount();
	for( int i=0; i<count; i++ ) {
		MessageItem * item = (MessageItem *) m_messageList->findItem(i);
		if (strcmp(item->request(),"Stop") != 0) {
			sprintf(str,"%29s (%02d) %8s -- %02d Rx:%03d Tx:%03d",item->name(),item->id(),item->request(),item->period(), m_messageRxCount[i], m_messageTxCount[i]);
			m_list1.AddString(str);
			m_list1.SetItemDataPtr(m_list1.GetCount()-1,item);
		}
	}
	for (int j=0; j<selcount; j++) {
		m_list1.SetSel(sels[j],true);
	}
	m_list1.SetTopIndex(topIndex);
	m_list1.SetRedraw(true);
}

void CMissionControlSettingsDlg::UpdateList2()
{
	int topIndex = m_list2.GetTopIndex();
	int sels[100];
	int selcount = m_list2.GetSelItems(100,sels);
	m_list2.SetRedraw(false);
	m_list2.ResetContent();
	m_list2.InitStorage(64,128);
	char str[128];
  	short count = m_messageList->MessageCount();
	for( int i=0; i<count; i++ ) {
		MessageItem * item = (MessageItem *) m_messageList->findItem(i);
		if (strcmp(item->request(),"Stop") == 0) {
			sprintf(str,"%29s (%02d)",item->name(),item->id());
			m_list2.AddString(str);
			m_list2.SetItemDataPtr(m_list2.GetCount()-1,item);
		}
	}
	for (int j=0; j<selcount; j++) {
		m_list2.SetSel(sels[j],true);
	}
	m_list2.SetTopIndex(topIndex);
	m_list2.SetRedraw(true);
}

void CMissionControlSettingsDlg::runCycle()
{
	if (!m_active) return;
	static int xXcounter = 0;
	if (xXcounter++ > 100){
		xXcounter = 0;
		UpdateList1();
		UpdateList2();
	}
	//UpdateData(False);
}

void CMissionControlSettingsDlg::getBytes(double *baudRate, double *onUpdate)
{
	/*
	*baudRate = 0.;
	*onUpdate = 0.;
	for (short i=0; i<256; i++) {
		switch (settings[i].frequency) {
		case (OnUpdateOnly):
			*onUpdate += settings[i].bytes;
			break;
		case (SendEvery):
			if (settings[i].seconds > 0) {
				*baudRate += 8. * (double) settings[i].bytes / 
					(double) settings[i].seconds;
			}
			break;
		}
	}
	
	// Account for blob overhead
	// 8 bits/byte * 8 bytes/blob every 10 seconds
	if (*baudRate > 0.) *baudRate += 8. * 8. / 10.;
	*/
}

void CMissionControlSettingsDlg::OnSelchangeList1() 
{
	m_list2.SetSel(-1, false);
}

void CMissionControlSettingsDlg::OnSelchangeList2() 
{
	m_list1.SetSel(-1, false);
}

void CMissionControlSettingsDlg::OnChangeFreq1() 
{
	UpdateData(TRUE);
}

void CMissionControlSettingsDlg::requestUpdate()
{
	Assert(m_recipient);
	for (short i=ModemMessage::tUNKNOWN; i<ModemMessage::tEND; i++) {
		MessageItem * item = (MessageItem *) m_messageList->findItem(i);
		if (lookupRequestNum(item->request()) == MMAgentRequest::OnUpdate)  {
			m_recipient->requestData(MMAgentRequest::Single, (ModemMessage::Type)i,-1,true);
			item->setRequest("OnUpdate");
		}
	}
}

int CMissionControlSettingsDlg::lookupRequestNum(const char * request) 
{
	if (strcmp("Stop",request) == 0) return MMAgentRequest::Stop;
	if (strcmp("Start", request) == 0) return MMAgentRequest::Start;
	if (strcmp("Single", request) == 0) return MMAgentRequest::Single;
	if (strcmp("OnUpdate", request) == 0) return MMAgentRequest::OnUpdate;
	if (strcmp("WithNav", request) == 0) return MMAgentRequest::WithNav;
	return 0; // stop
}

void CMissionControlSettingsDlg::lookupRequestName(MMAgentRequest::Request request, char * name) 
{
	switch (request) {
		case (MMAgentRequest::Stop): strcpy(name,"Stop"); break;
		case (MMAgentRequest::Start): strcpy(name,"Start"); break;
		case (MMAgentRequest::Single): strcpy(name,"Single"); break;
		case (MMAgentRequest::OnUpdate): strcpy(name,"OnUpdate"); break;
		case (MMAgentRequest::WithNav): strcpy(name,"WithNav"); break;
	}
}



void CMissionControlSettingsDlg::stopRequests()
{
	Assert(m_recipient);
	for (short i=ModemMessage::tUNKNOWN; i<ModemMessage::tEND; i++) {
		MessageItem * item = (MessageItem *) m_messageList->findItem(i);
		if (strcmp(item->request(),"Stop") != 0) {
			m_recipient->requestData(MMAgentRequest::Stop,(ModemMessage::Type)i,-1,true);
		}
	}
}

void CMissionControlSettingsDlg::OnUpdate() 
{
	// TODO: Add your control notification handler code here
	Assert(m_recipient);
	requestUpdate();
}

void CMissionControlSettingsDlg::OnStop() 
{
	// TODO: Add your control notification handler code here
	Assert(m_recipient);
	stopRequests();
}

void CMissionControlSettingsDlg::OnRequestblock() 
{
	// TODO: Add your control notification handler code here
	UpdateData(true);
	m_recipient->setRequestBlock(m_RequestBlockVal);
}

void CMissionControlSettingsDlg::OnStopbutton() 
{
	// TODO: Add your control notification handler code here
	ApplyToSelection(MMAgentRequest::Stop,0);
}


void CMissionControlSettingsDlg::OnOncebutton() 
{
	// TODO: Add your control notification handler code here
	ApplyToSelection(MMAgentRequest::Single,0);
}

void CMissionControlSettingsDlg::OnOnupdatebutton() 
{
	// TODO: Add your control notification handler code here
	UpdateData(true);
	int sels1[100], sels2[100];
	int selcount1 = m_list1.GetSelItems(100,sels1);
	int selcount2 = m_list2.GetSelItems(100,sels2);
	int j;
	for (j=0; j<selcount1; j++) {
		((MessageItem *) m_list1.GetItemDataPtr(sels1[j]))->setRequest("OnUpdate");
	}
	for (j=0; j<selcount2; j++) {
		((MessageItem *) m_list2.GetItemDataPtr(sels2[j]))->setRequest("OnUpdate");
	}
}

void CMissionControlSettingsDlg::OnWithnavbutton() 
{
	// TODO: Add your control notification handler code here
	ApplyToSelection(MMAgentRequest::WithNav,0);
}

void CMissionControlSettingsDlg::OnPeriodicbutton() 
{
	// TODO: Add your control notification handler code here
	ApplyToSelection(MMAgentRequest::Start, atoi(m_freq1Str));
}


void CMissionControlSettingsDlg::ApplyToSelection(MMAgentRequest::Request request, int period)
{
	UpdateData(true);
	int sels1[100], sels2[100];
	int selcount1 = m_list1.GetSelItems(100,sels1);
	int selcount2 = m_list2.GetSelItems(100,sels2);
	int j;
	for (j=0; j<selcount1; j++) {
		m_recipient->requestData(request, (ModemMessage::Type)(((MessageItem *) m_list1.GetItemDataPtr(sels1[j]))->id()), period, true);
	}
	for (j=0; j<selcount2; j++) {
		m_recipient->requestData(request, (ModemMessage::Type)(((MessageItem *) m_list2.GetItemDataPtr(sels2[j]))->id()), period, true);
	}
	// UpdateList1();
	// UpdateList2();
	// UpdateData(false);
}


////////////////////////////////////////////////////



bool CMissionControlSettingsDlg::checkRequest(MMAgentRequest::Request * request, ModemMessage::Type type, int * period, bool blockOverride) 
{
	MessageItem * item = (MessageItem *) m_messageList->findItem((int) type);
	char reqbuf[32];
	lookupRequestName(*request,reqbuf);
	
	if (m_RequestBlockVal && !blockOverride) {
		char msgbuf[256];
		sprintf(msgbuf,"Request %s for message %s every %d seconds:  Yes=Allow, No=Single, Cancel=Ignore",reqbuf,item->name(),*period);
		switch(MessageBox(msgbuf,"Request",MB_YESNOCANCEL)){
		case IDYES:
			break;
		case IDNO:
			*request = MMAgentRequest::Single;
			*period = 0;
			lookupRequestName(*request,reqbuf);
			break;
		case IDCANCEL:
			return false;
		}
	} 
	
	item->setRequest(reqbuf);
	item->setPeriod(*period);
	return true;
}

void CMissionControlSettingsDlg::gotMessage(const ModemMessage* mm)
{
	MessageItem * item = (MessageItem *) m_messageList->findItem((int) mm->getType());
	if (strcmp(item->request(),"Stop") == 0) { // _not_!!!
		item->setRequest("RECEIVED"); // at least
	}
	m_messageRxCount[mm->getType()] += 1;
//	UpdateList1();
}	

void CMissionControlSettingsDlg::sentMessage(const ModemMessage* mm)
{
	m_messageTxCount[mm->getType()] += 1;
//	UpdateList1();
}	


void CMissionControlSettingsDlg::OnClose() 
{
	CDialog::OnOK();
}



void CMissionControlSettingsDlg::OnLoadbutton() 
{
	// find the file
	CFileDialog dlg(TRUE,"cfg","*.cfg");
	if (dlg.DoModal() != IDOK) return;

	// parse the file
	Attributes * attributes = new Attributes( "MessageControlConfig" );
	MessageList * messageList = new MessageList( True );

    try {
         AttributeParser::parse(dlg.GetPathName().GetBuffer(0), 
                                attributes,
                                messageList );
     }
	 catch(...)
     {
         // return;
     }
	
	// apply its diff to the current state
	short count = messageList->MessageCount();
	for( int i=0; i<count; i++ ) {
		MessageItem * item1 = (MessageItem *)messageList->findItem(i);
		MessageItem * item2 = (MessageItem *)m_messageList->findItem(item1->id());
		if (strcmp(item1->request(),item2->request()) != 0) {
				m_recipient->requestData((MMAgentRequest::Request) lookupRequestNum(item1->request()), (ModemMessage::Type)(item1->id()), item1->period(), true);
		}
	}
}

void CMissionControlSettingsDlg::OnSavebutton() 
{
	// find the file
	CFileDialog dlg(FALSE,"cfg","*.cfg");
	if (dlg.DoModal() != IDOK) return;

	// unparse the file
	try {
         AttributeParser::unparse(dlg.GetPathName().GetBuffer(0), 
                                m_attributes,
                                m_messageList );
     }
	 catch(...)
     {
         // return;
     }

}

void CMissionControlSettingsDlg::sendNavMessages() 
{
	Assert(m_recipient);
	for (short i=ModemMessage::tUNKNOWN; i<ModemMessage::tEND; i++) {
		MessageItem * item = (MessageItem *) m_messageList->findItem(i);
		if (lookupRequestNum(item->request()) == MMAgentRequest::WithNav)  {
			m_recipient->requestData(MMAgentRequest::Single, (ModemMessage::Type)i,-1,true);
			item->setRequest("WithNav");
		}
	}
}