// AttribEditDlg.cpp : implementation file
//

#include "stdafx.h"
#include <map>
#include <vector>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <afxtempl.h>
#include <afxwin.h>
#include <fstream>
#include <time.h>
#include "dashboard.h"
#include "AttribEditDlg.h"
#include "EditAttribData.h"
#include "AddAttDlg.h"
#include "DashboardRecipient.h"
#include "DataRecipient.h"
#include "CommsDlg.h"
#include "FileManagerDlg.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


static bool m_missionRunning;

const int AttTimerPeriod = 3;

/////////////////////////////////////////////////////////////////////////////
// CAttribEditDlg dialog


CAttribEditDlg::CAttribEditDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CAttribEditDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CAttribEditDlg)
	//}}AFX_DATA_INIT
}


void CAttribEditDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAttribEditDlg)
	DDX_Control(pDX, IDC_STATUS, m_Status);
	DDX_Control(pDX, IDC_TREE2, m_ChangeTree);
	DDX_Control(pDX, IDC_TREE1, m_MyTree);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CAttribEditDlg, CDialog)
	//{{AFX_MSG_MAP(CAttribEditDlg)
	ON_NOTIFY(TVN_ITEMEXPANDING, IDC_TREE1, OnItemexpandingTree1)
	ON_BN_CLICKED(IDC_SAVESEND, OnSavesend)
	ON_BN_CLICKED(IDC_JUSTSAVE, OnJustsave)
	ON_BN_CLICKED(IDC_KILLCHANGE, OnKillchange)
	ON_WM_TIMER()
	ON_BN_CLICKED(IDC_ADDATT, OnAddatt)
	ON_BN_CLICKED(IDC_SINGLEUPDATE, OnSingleupdate)
	ON_BN_CLICKED(IDC_STARTUPDATE, OnStartupdate)
	ON_BN_CLICKED(IDC_STOPUPDATE, OnStopupdate)
	ON_WM_SHOWWINDOW()
	ON_WM_CLOSE()
	ON_BN_CLICKED(IDC_JUMP_BEHAVIOR, OnJumpBehavior)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CAttribEditDlg message handlers

void CAttribEditDlg::setFileName(CString filename)
{
	m_normalName = filename;
	m_normalShort = getShortName(m_normalName);
}

void CAttribEditDlg::setAbortName(CString abortName)
{
	m_abortName = abortName;
	m_abortShort = getShortName(m_abortName); 
}

CString CAttribEditDlg::getCurrentNormal()
{
	return m_normalShort;
}

CString CAttribEditDlg::getCurrentAbort()
{
	return m_abortShort;
}

void CAttribEditDlg::setRecipient(CDashboardRecipient *recipient)
{
	m_recipient = recipient;
}

bool CAttribEditDlg::getMissionRunning(void)
{
	 return m_missionRunning;
}

CString CAttribEditDlg::myIdent(void)
{
	CString mid = "attrib";
	return mid;
}

void CAttribEditDlg::beforeDestroy()
{
	OnStopupdate();
	Cleanup();
}

void CAttribEditDlg::setCurrentBehavior(int curS, int curB, int missionRunning)
{

	//need to get that item in tree

	//first we get root item

	//TRACE("We getting good state shit: %d %d\n", curS, curB);

	if(this == NULL) return;

	if(!::IsWindow(m_MyTree)) {
		return;
	}

	HTREEITEM scrollFile = m_MyTree.GetRootItem();

	int im;
	int sm;

	if(curS == -1)
		_missionStatus = mission_none;
	else if(curS == 0 && curB == 0)
		_missionStatus = mission_initializing;
	else if(curS >= 0 && curB > 0)
		_missionStatus = mission_going;

	if(_missionStatus == mission_initializing ||
		_missionStatus == mission_going)
		m_missionRunning = True;
	else
		m_missionRunning = False;

	while(scrollFile != NULL){	
		if(curS == m_MyTree.GetItemData(scrollFile)) {
			HTREEITEM tempBehavior = m_MyTree.GetNextItem(scrollFile, TVGN_CHILD);
			while(tempBehavior != NULL) {
				m_MyTree.GetItemImage(tempBehavior,im,sm);
				if(curB+1 == m_MyTree.GetItemData(tempBehavior) && curB != -1 &&
					_upStatus == con_start) {
					if(im != 0 && sm != 1)
						m_MyTree.SetItemImage(tempBehavior,0,1);
				} else {
					if(im != 4 || sm != 4)
						m_MyTree.SetItemImage(tempBehavior,4,4);
				}	
				tempBehavior = m_MyTree.GetNextSiblingItem(tempBehavior);
			}
			m_MyTree.GetItemImage(scrollFile, im, sm);
			if(im != 3 && sm != 2) {
				TRACE("Setting item\n");
				m_MyTree.SetItemImage(scrollFile,3,2);
			}
		} else  {
			HTREEITEM tempBehavior = m_MyTree.GetNextItem(scrollFile, TVGN_CHILD);
			while(tempBehavior != NULL) {
				m_MyTree.GetItemImage(tempBehavior,im,sm);	
				if(im != 4 || sm != 4)
					m_MyTree.SetItemImage(tempBehavior,4,4);	
				tempBehavior = m_MyTree.GetNextSiblingItem(tempBehavior);
			}
			m_MyTree.GetItemImage(scrollFile, im, sm);
			if(im != 4 || sm != 4)
				m_MyTree.SetItemImage(scrollFile,4,4);
		}
		scrollFile = m_MyTree.GetNextSiblingItem(scrollFile);
	}
}

BOOL CAttribEditDlg::OnInitDialog()
{
	BOOL val = CDialog::OnInitDialog();
	if(m_abortName.IsEmpty())
		SetWindowText(m_normalName.GetBuffer(0));
	else {
		CString t = m_normalName + " with abort plan "+m_abortShort;
		SetWindowText(t.GetBuffer(0));
	}

	//This sets a three second timer
	SetTimer(1,AttTimerPeriod*1000,0);

	_upStatus = uncon_stop;
	_newStatus = uncon_stop;

	//loading bitmaps

	CImageList* pImageList = new CImageList();
	pImageList->Create(12,12,TRUE,4,4);

	CBitmap bitmap;
//	TRACE("Love: %d %d\n", IDB_BITMAP1, IDB_BITMAP2);
//	for (UINT iCnt=IDB_BITMAP1; iCnt<=IDB_BITMAP2; iCnt++)
//	{
	
	bitmap.LoadBitmap(IDB_BITMAP1);
	pImageList->Add(&bitmap, (COLORREF)0xFFFFFF);
	bitmap.DeleteObject();
	bitmap.LoadBitmap(IDB_BITMAP2);
	pImageList->Add(&bitmap, (COLORREF)0xFFFFFF);
	bitmap.DeleteObject();
	bitmap.LoadBitmap(IDB_BITMAP3);
	pImageList->Add(&bitmap, (COLORREF)0xFFFFFF);
	bitmap.DeleteObject();
	bitmap.LoadBitmap(IDB_BITMAP4);
	pImageList->Add(&bitmap, (COLORREF)0xFFFFFF);
	bitmap.DeleteObject();

	m_MyTree.SetImageList(pImageList, TVSIL_NORMAL);

	fileLparam = 0;

	if(m_abortName.IsEmpty())
		LoadFile(0, m_normalName);
	else {
		LoadFile(0, m_normalName);
		LoadFile(1, m_abortName);
	}
	return val;
}

//i better be 0 or 1 for now
void CAttribEditDlg::LoadFile(int i, CString fname)
{
	char lineBuffer[256];
	int isComment = 0;
	
	fstream missionFile;
	missionFile.open(fname.GetBuffer(0),ios::in); 

	int behaviorNum = 0;

	//for comments
	Behavior* comB = new Behavior();
	comB->priority = behaviorNum++;
	comB->name = "comments";
	_behaviors[i].Add(comB);

	while (missionFile.eof() != 1) {
		missionFile.getline(lineBuffer, 256);
		CString cLBuffer = lineBuffer;
		
		//seeing if line is commented
		//a comment is defined as having "#"
		//with any amount of whitespace before it
		//as the first things on a line
		int t;
		isComment = 0;
		if((t = cLBuffer.Find("#")) != -1) {
			CString check = cLBuffer;
			check = check.Left(t);
			check.TrimLeft();
			if(check.IsEmpty())
				isComment = 1;
		}
		if(isComment){
			//do nothing unless
			if(cLBuffer.Find("#!") != -1) {
				CString comName = cLBuffer;		
				int eqcom = comName.Find("=");
				int excom = comName.Find("!");
				comName = comName.Mid(excom+1, eqcom-excom-1);
				comName.TrimLeft();
				comName.TrimRight();
				
				CString comData = cLBuffer;
				int semicom = comData.Find(";");
				comData = comData.Mid(eqcom+1, semicom-eqcom-1);
				comData.TrimLeft();
				comData.TrimRight();

				if(!(comName.IsEmpty()) &&
					!(comData.IsEmpty())){	
					Attribute *comAtt = new Attribute();
					comAtt->name = comName;
					comAtt->data = comData;
					comAtt->dataDiffSaved = 0;
					comAtt->dataToSend = 0;
					_behaviors[i][0]->attributes.Add(comAtt);
				}
			}

		} else if(cLBuffer.Find("behavior") != -1){
			Behavior* tempB = new Behavior();
			tempB->priority = behaviorNum++;
			tempB->name = cLBuffer;
			int endbe = tempB->name.Find("r");
			int bp = tempB->name.Find("{");
			if(bp > -1)
				tempB->name = tempB->name.Mid(endbe+1,bp-endbe-1);
			else
				tempB->name = tempB->name.Right(tempB->name.GetLength()-endbe -1);
			tempB->name.TrimLeft();
			tempB->name.TrimRight();
			//TRACE(tempB->name);
			//TRACE("!\n");
			//opening brace not on same line as behavior name
			while(strchr(lineBuffer, '{') == NULL) {	
				missionFile.getline(lineBuffer,256);
			}
			//at this point, opening brace has been found
			//now we get lines until there's something with an equal
				
			while(1) {
				//go until attributes not found
				while((strchr(lineBuffer, '=') == NULL) &&
					(strchr(lineBuffer, '}') == NULL)) {
					missionFile.getline(lineBuffer,256);
				}
				//now the line is either an attribute, an attribute and a closing brace
				//or just a closing brace

				if(strchr(lineBuffer, '}') != NULL &&
					strchr(lineBuffer, '=') == NULL) break;

				//otherwise we have a good attribute				
				CString tempName(lineBuffer);
				CString tempData(lineBuffer);
				
				//Getting the name
				int bopen = tempName.Find("{");
				int eq = tempName.Find("=");
				if(bopen > -1)
					tempName = tempName.Mid(bopen+1, eq-1);
				else 
					tempName = tempName.Left(eq);
				tempName.TrimLeft();
				tempName.TrimRight();
				
				int semi = tempData.Find(";");
				tempData = tempData.Mid(eq+1, semi-eq-1);
				tempData.TrimLeft();
				tempData.TrimRight();
				Attribute *tempAtt = new Attribute();
				tempAtt->name = tempName;
				tempAtt->data = tempData;
				tempAtt->dataDiffSaved = 0;
				tempAtt->dataToSend = 0;
				tempB->attributes.Add(tempAtt);
				//closing bracket on same line as behavior
				if(strchr(lineBuffer, '}') != NULL) break;
				missionFile.getline(lineBuffer,256);
			}
		
			_behaviors[i].Add(tempB);
		}
	}

	//TRACE("%d %d\n", _comments.GetSize(), _behaviors[i].GetSize());
	FillTree(i, fname);
}

void CAttribEditDlg::WriteFile(int snum, CString fname, WhichChanges w)
{
	
	FILE *fp;
	fp = fopen(fname,"w");

	for(int i=0; i < _behaviors[snum][0]->attributes.GetSize(); i++){
		if(w == KEEPNEW && _behaviors[snum][0]->attributes[i]->dataDiffSaved){
			fprintf(fp, "#!	%s = %s;\n", _behaviors[snum][0]->attributes[i]->name,
				_behaviors[snum][0]->attributes[i]->dataNew);
		} else {
			fprintf(fp, "#!	%s = %s;\n", _behaviors[snum][0]->attributes[i]->name,
				_behaviors[snum][0]->attributes[i]->data);
		}
		_behaviors[snum][0]->attributes[i]->dataDiffSaved = 0;
	}

	for(int j=1; j < _behaviors[snum].GetSize(); j++){
		fprintf(fp, "\n");
		fprintf(fp, "####Behavior %s Priority %d\n", _behaviors[snum][j]->name, _behaviors[snum][j]->priority);
		fprintf(fp, "behavior %s\n", _behaviors[snum][j]->name);
		fprintf(fp, "{\n");
		CString tempName;
		CString tempData;		
		
		for(int k=0;k < _behaviors[snum][j]->attributes.GetSize();k++){
			if(w == KEEPNEW && _behaviors[snum][j]->attributes[k]->dataDiffSaved){
				fprintf(fp, "	%s = %s;\n", _behaviors[snum][j]->attributes[k]->name,
					_behaviors[snum][j]->attributes[k]->dataNew);
			} else {
				fprintf(fp, "	%s = %s;\n", _behaviors[snum][j]->attributes[k]->name,
					_behaviors[snum][j]->attributes[k]->data);
			}
			_behaviors[snum][j]->attributes[k]->dataDiffSaved = 0;
		}
		fprintf(fp, "}\n");	
	}
	fclose(fp);
}

//for now, if the tree isn't empty, we assume that another state is already
//there and put the other one as it's sibling


void CAttribEditDlg::FillTree(int i, CString fname) {
	CWaitCursor cursor; //display wait cursor

	TV_INSERTSTRUCT tvstructFile;
	TV_INSERTSTRUCT tvstructBeh;
	TV_INSERTSTRUCT tvstructAtt;
	TV_INSERTSTRUCT dummyKid;

	CString hereShort = getShortName(fname);
	if(i == 0)
		m_normalShort = hereShort;
	else
		m_abortShort = hereShort;

	int behaviorLParam = 0;
	int attributeLParam = 0;

	HTREEITEM curRoot = m_MyTree.GetRootItem();

	if(curRoot != NULL){
		int curHeight = m_MyTree.GetItemHeight();
		m_MyTree.SetItemHeight(curHeight+5);
	}

	tvstructFile.hParent = TVI_ROOT;
	tvstructFile.hInsertAfter = TVI_LAST;
	tvstructFile.item.iImage = 4;
	tvstructFile.item.iSelectedImage = 4;
	tvstructFile.item.pszText = hereShort.GetBuffer(1);
	tvstructFile.item.lParam = fileLparam++;
	tvstructFile.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;

	HTREEITEM hRootFileItem = m_MyTree.InsertItem(&tvstructFile);

	//next level: missions

	tvstructBeh.hParent = hRootFileItem;
	tvstructBeh.hInsertAfter = TVI_LAST;
	tvstructBeh.item.iSelectedImage = 4;
	tvstructBeh.item.iImage = 4;
	tvstructBeh.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
	for(int j=0; j < _behaviors[i].GetSize(); j++){
		tvstructBeh.item.pszText = _behaviors[i][j]->name.GetBuffer(1);
		tvstructBeh.item.lParam = behaviorLParam++;
		HTREEITEM hRootBehavior = m_MyTree.InsertItem(&tvstructBeh);
		tvstructAtt.hParent = hRootBehavior;
		tvstructAtt.hInsertAfter = TVI_LAST;
		tvstructAtt.item.iImage = 4;
		tvstructAtt.item.iSelectedImage = 4;
		tvstructAtt.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
		CString tempName;
		CString tempData;	
		attributeLParam = 0;
		for(int k=0;k < _behaviors[i][j]->attributes.GetSize();k++){
			tempName = _behaviors[i][j]->attributes[k]->name;
			tempData = _behaviors[i][j]->attributes[k]->data;
			tempName = tempName + " = " +tempData;
			tvstructAtt.item.pszText = tempName.GetBuffer(0);
			tvstructAtt.item.lParam = attributeLParam++;
			HTREEITEM att = m_MyTree.InsertItem(&tvstructAtt);
			dummyKid.hParent = att;
			m_MyTree.InsertItem(&dummyKid);
		}
	}
}

void CAttribEditDlg::OnOK() 
{
	OnStopupdate();
	m_fm->DeleteAttribEdit();
}

CString CAttribEditDlg::ExtractData(CString nd) {
	
	int eq = nd.Find("=");
	if(eq == -1){
		CString e;
		return(e);
	}
	CString d = nd.Right(nd.GetLength()-eq-1);
	d.TrimLeft();
	d.TrimRight();
	return(d);
}

CString CAttribEditDlg::ExtractName(CString nd) {
	int eq = nd.Find("=");
	if(eq == -1){
		CString e;
		return(e);
	}
	CString d = nd.Left(eq);
	d.TrimLeft();
	d.TrimRight();
	return(d);
}

//0 means m_MyTree, 1 means m_ChangeTree
int CAttribEditDlg::StateAsParent(HTREEITEM h, int i)
{
	//Tracking back to root, until parent is null

	HTREEITEM p;
	while(1) {
		if(i == 0)
			p = m_MyTree.GetParentItem(h);
		else
			p = m_ChangeTree.GetParentItem(h);
		if(p == NULL) break;
		h = p;
	}

	//should have file level tree item
	CString t;
	if(i == 0)
		t = m_MyTree.GetItemText(h);
	else
		t = m_ChangeTree.GetItemText(h);

	CString changeString = "Changes to "+ m_normalShort+":";
	if(t == m_normalShort || t == changeString)
		return 0;
	changeString = "Changes to "+ m_abortShort+":";
	if(t == m_abortShort || t == changeString)
		return 1;
	
	return -1;
}

void CAttribEditDlg::AddStateToChange(int x)
{
	//if tree is totally empty
	if(m_ChangeTree.GetCount() == 0){
		//if tree empty, just add state with correct 
		TV_INSERTSTRUCT changeRoot;
		changeRoot.hParent = TVI_ROOT;
		changeRoot.hInsertAfter = TVI_LAST;
		CString r;
		if(x == 0)
			r = "Changes to " + m_normalShort+":";
		else
			r = "Changes to " + m_abortShort+":";
			changeRoot.item.pszText = r.GetBuffer(0);
			changeRoot.item.lParam = x;
			changeRoot.item.mask = TVIF_TEXT | TVIF_PARAM;
			it_changeRoot = m_ChangeTree.InsertItem(&changeRoot);
	} else {
		HTREEITEM croot = m_ChangeTree.GetRootItem();
		HTREEITEM csib = m_ChangeTree.GetNextSiblingItem(croot);
		if(m_ChangeTree.GetItemData(croot) != x &&
			csib == NULL) {
			TVINSERTSTRUCT changeNew;
			changeNew.hParent = TVI_ROOT;
			if(x == 0)
				changeNew.hInsertAfter = TVI_FIRST;
			else
				changeNew.hInsertAfter = TVI_LAST;
			CString r;
			if(x == 0)
				r = "Changes to " + m_normalShort+":";
			else
				r = "Changes to " + m_abortShort+":";
			changeNew.item.pszText = r.GetBuffer(0);
			changeNew.item.lParam = x;
			changeNew.item.mask = TVIF_TEXT | TVIF_PARAM;
			m_ChangeTree.InsertItem(&changeNew);
		}
	}
}


void CAttribEditDlg::OnItemexpandingTree1(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here
	
	TVITEM* tempNew = new TVITEM(pNMTreeView->itemNew);

	//so if the item has data, then it is an attribute

	CString ourText = m_MyTree.GetItemText(tempNew->hItem);

	CString nameOld = ExtractName(ourText);
	CString dataOld = ExtractData(ourText);
	if(!(dataOld.IsEmpty())) {

		int whichState = StateAsParent(tempNew->hItem, 0);
		if(whichState == -1){
			*pResult = 1;
			return;
		}

		CEditAttribData editDataDlg(this);
		editDataDlg.SetEditData(dataOld.GetBuffer(1));

		//Getting behavior and attribute name
		HTREEITEM rent = m_MyTree.GetParentItem(tempNew->hItem);
		int numBehavior = m_MyTree.GetItemData(rent);
		int numAttribute = m_MyTree.GetItemData(tempNew->hItem);
		CString pri;
		pri.Format("%d",_behaviors[whichState][numBehavior]->priority);
		CString changed = "Behavior: "+_behaviors[whichState][numBehavior]->name+" Priority: "+pri+ " Attribute: "+
			_behaviors[whichState][numBehavior]->attributes[numAttribute]->name;
		editDataDlg.SetDialogCaption(changed);
		editDataDlg.DoModal();


		CString dataNew;
		if(editDataDlg.GetGoodData())
			dataNew = editDataDlg.GetEditData();
		else
			dataNew = dataOld;

		editDataDlg.DestroyWindow();

		if(dataOld != dataNew) {

			AddStateToChange(whichState);

			//if there's already a change of this attribute we want to kill it
			//so only the most recent one will take effect
			if(_behaviors[whichState][numBehavior]->attributes[numAttribute]->dataToSend){
				//gots to find previous entry in the tree and get rid of it
				
				HTREEITEM tRoot = m_ChangeTree.GetRootItem();
				if(m_ChangeTree.GetItemData(tRoot) != whichState)
					tRoot = m_ChangeTree.GetNextSiblingItem(tRoot);

				if(tRoot == NULL)
					TRACE("Something serious screwed in changeTree\n");
			
				HTREEITEM tempBehavior = m_ChangeTree.GetNextItem(tRoot, TVGN_CHILD);
				HTREEITEM tKid; 

				while(tempBehavior != NULL) {

					TRACE("%s\n", m_ChangeTree.GetItemText(tempBehavior));
					tKid = m_ChangeTree.GetChildItem(tempBehavior);

					TRACE("%d %d %d %d\n", numBehavior, numAttribute, m_ChangeTree.GetItemData(tempBehavior),
						m_ChangeTree.GetItemData(tKid));

					if(m_ChangeTree.GetItemData(tempBehavior) == numBehavior &&
						m_ChangeTree.GetItemData(tKid) == numAttribute) {
						m_ChangeTree.DeleteItem(tempBehavior);
						break;
					}

					tempBehavior = m_ChangeTree.GetNextSiblingItem(tempBehavior);
				}
			}

			_behaviors[whichState][numBehavior]->attributes[numAttribute]->dataNew=dataNew;
			_behaviors[whichState][numBehavior]->attributes[numAttribute]->dataToSend=1;
			_behaviors[whichState][numBehavior]->attributes[numAttribute]->dataDiffSaved=1;


			m_MyTree.SetItemText(tempNew->hItem,nameOld+" = "+dataNew);
			//changeTree Insertion

			HTREEITEM tRoot = m_ChangeTree.GetRootItem();
			if(m_ChangeTree.GetItemData(tRoot) != whichState)
				tRoot = m_ChangeTree.GetNextSiblingItem(tRoot);

			if(tRoot == NULL)
				TRACE("Something serious screwed in changeTree\n");

			TV_INSERTSTRUCT changeBe;
			TV_INSERTSTRUCT changeAt;

			changeBe.hParent = tRoot;
			changeBe.hInsertAfter = TVI_LAST;
			CString pri;
			pri.Format("%d",_behaviors[whichState][numBehavior]->priority);
			CString changed = "Behavior: "+_behaviors[whichState][numBehavior]->name+" Priority: "+pri+ " Attribute: "+
				_behaviors[whichState][numBehavior]->attributes[numAttribute]->name;	
			changeBe.item.pszText = changed.GetBuffer(1);
			changeBe.item.lParam = numBehavior;
			changeBe.item.mask = TVIF_TEXT | TVIF_PARAM;
			HTREEITEM it_changeBe = m_ChangeTree.InsertItem(&changeBe);

			m_ChangeTree.Expand(tRoot, TVE_EXPAND);

			changeAt.hParent = it_changeBe;
			changeAt.hInsertAfter = TVI_LAST;
			CString attChanged = "Data changed from "+_behaviors[whichState][numBehavior]->attributes[numAttribute]->data + " to " + dataNew;
			changeAt.item.pszText=attChanged.GetBuffer(1);
			changeAt.item.lParam = numAttribute;
			changeAt.item.mask = TVIF_TEXT | TVIF_PARAM;
			m_ChangeTree.InsertItem(&changeAt);
		}
		*pResult = 1;
	} else {
		*pResult = 0;
	}

	delete tempNew;
}

//0 for normal, 1 for abort
void CAttribEditDlg::SaveAttribFile(int snum)
{
	CString f;

	if(snum == 0)
		f = m_normalName;
	else
		f = m_abortName;

	CFileDialog attFileD(FALSE, "mis", f, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, NULL, this);

	attFileD.DoModal();

	CString fullPath = attFileD.GetPathName();

	if(snum == 0)
		m_normalName = fullPath;
	else
		m_abortName = fullPath;

	WriteFile(snum,fullPath,KEEPNEW);

	//Now we need to replace the file name up top
	//and in the attribute tree if a new one was chosen

	if(fullPath != f){

		CString hereShort = getShortName(fullPath);
		if(snum == 0)
			m_normalShort = hereShort;
		else
			m_abortShort = hereShort;
		
		//setting root name
		HTREEITEM tempRoot = m_MyTree.GetRootItem();
		if(m_MyTree.GetItemData(tempRoot) != snum)
			tempRoot = m_MyTree.GetNextSiblingItem(tempRoot);
		if(tempRoot != NULL)
			m_MyTree.SetItemText(tempRoot,hereShort.GetBuffer(1));

		//setting window name
		if(m_abortName.IsEmpty())
			SetWindowText(m_normalName.GetBuffer(0));
		else {
			CString t = m_normalName + " with abort plan "+m_abortShort;
			SetWindowText(t.GetBuffer(0));
		}

		HTREEITEM changeRoot = m_ChangeTree.GetRootItem();
		if(changeRoot != NULL){
			if(m_ChangeTree.GetItemData(changeRoot) != snum)
				changeRoot = m_ChangeTree.GetNextSiblingItem(changeRoot);
			if(changeRoot != NULL){
				CString tempText = "Changes to "+hereShort+":";
				m_ChangeTree.SetItemText(changeRoot,tempText);
			}
		}

	}

}

void CAttribEditDlg::PackageSend(){

	//single send on single message

	int numChanges = toSend.GetSize();

	if(numChanges == 1){
		m_recipient->setBehavior(toSend[0]->state, toSend[0]->priority,toSend[0]->name.GetLength(),
								 toSend[0]->name.GetBuffer(0), toSend[0]->data.GetLength(),
								 toSend[0]->data.GetBuffer(0));
		TRACE("name %d namesize %s data %d datasize %s\n",toSend[0]->name.GetLength(),
								 toSend[0]->name.GetBuffer(0), toSend[0]->data.GetLength(),
								 toSend[0]->data.GetBuffer(0));
	} else if(toSend.GetSize() != 0) {
		
		short* states = (short *)malloc(sizeof(short)*numChanges);
		short* pri = (short *)malloc(sizeof(short)*numChanges);
		short* nameSizes = (short *)malloc(sizeof(short)*numChanges);
		short* dataSizes = (short *)malloc(sizeof(short)*numChanges);

		char** names = (char **)malloc(sizeof(char *)*numChanges);
		char** data = (char **)malloc(sizeof(char *)*numChanges);	
		
		for(int i = 0; i < numChanges; i++) {
			states[i] = toSend[i]->state;
			pri[i] = toSend[i]->priority;
			nameSizes[i] = toSend[i]->name.GetLength();
			dataSizes[i] = toSend[i]->data.GetLength();
			names[i] = strdup(toSend[i]->name.GetBuffer(0));
			data[i] = strdup(toSend[i]->data.GetBuffer(0));
		}	
	
		m_recipient->setBehaviorArray(numChanges, states, pri, nameSizes,
									  names, dataSizes, data);

		for(int j = 0; j < numChanges; j++){
			free(names[j]);
			free(data[j]);
		}

		free(pri);
		free(nameSizes);
		free(dataSizes);

		free(names);
		free(data);
	}

}
	
void CAttribEditDlg::OnSavesend() 
{
	OnJustsave();

	//HTREEITEM hRoot = m_ChangeTree.GetRootItem();
	//m_ChangeTree.DeleteAllItems();
	//DeleteItem(hRoot);
	
	//creating an array of the attributes to be sent

	//for the two states
	for(int snum = 0; snum < 2; snum++) {
		for(int i = 0; i <_behaviors[snum].GetSize(); i++) {
			for(int j = 0; j < _behaviors[snum][i]->attributes.GetSize(); j++) {
				if(_behaviors[snum][i]->attributes[j]->dataToSend) {
					AttToSend *tempSend = new AttToSend();
					tempSend->state = snum;
					tempSend->priority = _behaviors[snum][i]->priority-1; //comments is a behavior
					tempSend->name = _behaviors[snum][i]->attributes[j]->name;
					tempSend->data = _behaviors[snum][i]->attributes[j]->dataNew;
					toSend.Add(tempSend);

					//for now, you commit changes only when you send successfully

					//_behaviors[snum][i]->attributes[j]->data =
					//	_behaviors[snum][i]->attributes[j]->dataNew;
					//_behaviors[snum][i]->attributes[j]->dataNew.Empty();
					//_behaviors[snum][i]->attributes[j]->dataChanged = 0;
				}
			}
		}
	}

	PackageSend();

	for(int h=0; h < toSend.GetSize(); h++) {
		delete toSend[h];
	}
	toSend.RemoveAll();
}

CString CAttribEditDlg::getShortName(CString s)
{
	int lastSlash = s.ReverseFind('\\');
	return(s.Right(s.GetLength()-lastSlash-1));
}

bool CAttribEditDlg::ChangesNeedSaving(int snum)
{
	bool need = False;

	for(int i = 0; i <_behaviors[snum].GetSize(); i++) {
		for(int j = 0; j < _behaviors[snum][i]->attributes.GetSize(); j++) {
			if(_behaviors[snum][i]->attributes[j]->dataDiffSaved) {
				need = True;
			}
		}
	}

	return need;
}

void CAttribEditDlg::OnJustsave() 
{
	bool s0 = ChangesNeedSaving(0);
	bool s1;
	if(! m_abortName.IsEmpty())
		s1 = ChangesNeedSaving(1);
	else
		s1 = False;
	
	if(s0)
		SaveAttribFile(0);
	
	TRACE("Past saving normal\n");

	if(s1) 
		SaveAttribFile(1);

	if(!s0 && !s1){
		CString temp="No changes need saving";
		this->MessageBox(temp.GetBuffer(0));
	}
}

void CAttribEditDlg::OnKillchange() 
{

	HTREEITEM sel = m_ChangeTree.GetSelectedItem();

	int snum = StateAsParent(sel,1);

	if(snum == -1)
		return;

	int Bnum;
	int Anum;

	if(sel == m_ChangeTree.GetRootItem() ||
		sel == NULL) return;

	HTREEITEM selFile;

	//find parent and kill
	if(m_ChangeTree.ItemHasChildren(sel)){
		HTREEITEM selKid = m_ChangeTree.GetChildItem(sel);
		Bnum = m_ChangeTree.GetItemData(sel);
		Anum = m_ChangeTree.GetItemData(selKid);
		//m_ChangeTree.DeleteItem(selKid);
		selFile = m_ChangeTree.GetParentItem(sel);
		m_ChangeTree.DeleteItem(sel);
	} else {
		HTREEITEM selRent = m_ChangeTree.GetParentItem(sel);
		Bnum = m_ChangeTree.GetItemData(selRent);
		Anum = m_ChangeTree.GetItemData(sel);
		//m_ChangeTree.DeleteItem(sel);
		selFile = m_ChangeTree.GetParentItem(selRent);
		m_ChangeTree.DeleteItem(selRent);
	}

	//if that file has no more changes delete it
	if(! m_ChangeTree.ItemHasChildren(selFile)) {
		m_ChangeTree.DeleteItem(selFile);
	}

	//now we have to restore the original data to MyTree
	//and delete the change in the behavior structure

	//first in _behaviors

	//so if dataDiffSaved is 0, means we already saved what we got,
	//so we actually need to resave the old data
	//so the oldData should be in data
	//and we can safely empty newData
	if(_behaviors[snum][Bnum]->attributes[Anum]->dataDiffSaved == 0)
		_behaviors[snum][Bnum]->attributes[Anum]->dataDiffSaved = 1;

	_behaviors[snum][Bnum]->attributes[Anum]->dataToSend = 0;
	_behaviors[snum][Bnum]->attributes[Anum]->dataNew.Empty();
	CString oldData = _behaviors[snum][Bnum]->attributes[Anum]->data;
	CString oldName = _behaviors[snum][Bnum]->attributes[Anum]->name;

	//finding the behavior

	HTREEITEM tRoot = m_MyTree.GetRootItem();
	if(snum != m_MyTree.GetItemData(tRoot))
		tRoot = m_MyTree.GetNextSiblingItem(tRoot);

	if(tRoot == NULL) return;

	HTREEITEM tBehavior = m_MyTree.GetNextItem(tRoot, TVGN_CHILD);

	while(tBehavior!= NULL) {
		if(m_MyTree.GetItemData(tBehavior) == Bnum)
			break;

		tBehavior = m_MyTree.GetNextSiblingItem(tBehavior);
	}


	HTREEITEM tAttribute;
	if(tBehavior != NULL){
		
		tAttribute = m_MyTree.GetNextItem(tBehavior, TVGN_CHILD);

		while(tAttribute != NULL) {
			if(m_MyTree.GetItemData(tAttribute) == Anum)
				break;
			tAttribute = m_MyTree.GetNextSiblingItem(tAttribute);
		}
	}

	if(tAttribute != NULL){
		CString tString = oldName+" = "+oldData;
		m_MyTree.SetItemText(tAttribute, tString.GetBuffer(0));
	}
}

void CAttribEditDlg::OnTimer(UINT nIDEvent) 
{
	//first, change connection status in update

	//we may have changed _upStatus by buttons
	if(_upStatus != _newStatus){
		_newStatus = _upStatus;
	}

	if(CCommsDlg::getConnected()){
		if(_upStatus == uncon_stop)
			_newStatus = con_stop;
		else if(_upStatus == uncon_start)
			_newStatus = con_start;
	} else if(!CCommsDlg::getConnected()) {
		if(_upStatus == con_stop)
			_newStatus = uncon_stop;
		else if(_upStatus == con_start)
			_newStatus = uncon_start;
	}

	if(_upStatus != _newStatus){
		switch(_newStatus){
		case con_stop:
			BlitzIcon();
			break;
		case con_start:
			m_recipient->requestData(MMAgentRequest::Start,
				ModemMessage::tMMActiveBehavior,ATT_BEHAVIOR_UPDATE_PERIOD);
			break;
		case uncon_stop:
			break;
		case uncon_start:
			break;
		}
		_upStatus = _newStatus;
	}



	WriteStatus();
	CDialog::OnTimer(nIDEvent);
}

void CAttribEditDlg::WriteStatus()
{
	CString con;
	CString mis;
	CString tot;
	
	switch(_upStatus){
	case con_stop:
		con = "Connected and not updating. ";
		break;
	case con_start:
		con = "Connected and updating. ";
		break;
	case uncon_start:
		con = "Unconnected and waiting to update. ";
		break;
	case uncon_stop:
		con = "Unconnected and not waiting to update. ";
		break;
	}

	switch(_missionStatus){
	case mission_none:
		mis = "No mission running.";
		break;
	case mission_initializing:
		mis = "Mission initializing.";
		break;
	case mission_going:
		mis = "Mission currently running.";
		break;
	}

	if(_upStatus == con_stop ||
		_upStatus == con_start)
		tot = con+mis;
	else
		tot = con+"Mission status unknown.";

	m_Status.SetWindowText(tot);
}

void CAttribEditDlg::BlitzIcon()
{

	HTREEITEM tempRoot = m_MyTree.GetRootItem();
	HTREEITEM tempBehavior = m_MyTree.GetNextItem(tempRoot, TVGN_CHILD);
	int im, sm;

	while(tempBehavior != NULL) {
		m_MyTree.GetItemImage(tempBehavior,im, sm);

		if(im != 4 || sm != 4)
			m_MyTree.SetItemImage(tempBehavior,4,4);
		
		tempBehavior = m_MyTree.GetNextSiblingItem(tempBehavior);
	}
}

//TODO
void CAttribEditDlg::OnAddatt() 
{

	//figure out where the cursor is
	//as attribute will be added to that behavior

	HTREEITEM sel = m_MyTree.GetSelectedItem();

	if(sel == m_MyTree.GetRootItem() ||
		sel == NULL) return;
	
	int snum = StateAsParent(sel,0);

	CString temp = m_MyTree.GetItemText(sel);
	temp = ExtractData(temp);
	//is this then we got the kid
	if(!temp.IsEmpty())
		sel = m_MyTree.GetParentItem(sel);

	//should have behavior at this point

	CString targetName = m_MyTree.GetItemText(sel);
	int targetPriority = m_MyTree.GetItemData(sel);
	
		
	CAddAttDlg addAtt = new CAddAttDlg();

	CString t;
	t.Format("%d", targetPriority);
	t = "Behavior "+targetName+" Priority "+t;
	addAtt.SetDialogCaption(t);

	addAtt.DoModal();

	if(!addAtt.GetGoodData()) return;
		
	CString nameNew = addAtt.GetNewName();
	CString dataNew = addAtt.GetNewData();
	CString textNew = nameNew+" = "+dataNew;

	if(nameNew.IsEmpty() || dataNew.IsEmpty()) return;

	//see if the attribute name is a duplicate
	//by iterating through the children of the behavior

	HTREEITEM tempAtt = m_MyTree.GetNextItem(sel, TVGN_CHILD);

	while(tempAtt != NULL) {
		
		CString attText = ExtractName(m_MyTree.GetItemText(tempAtt));

		if(attText == nameNew){
		
			m_MyTree.SetItemText(tempAtt, textNew.GetBuffer(0));
			break;
		}
		tempAtt = m_MyTree.GetNextSiblingItem(tempAtt);
	}
	
	int selNum = m_MyTree.GetItemData(sel);
	int attNum = _behaviors[snum][selNum]->attributes.GetSize();
	
	//if we replaced an entry, we need to create a change
	if(tempAtt != NULL) {
		
		int attNum = m_MyTree.GetItemData(tempAtt);
		_behaviors[snum][selNum]->attributes[attNum]->dataNew=dataNew;
		_behaviors[snum][selNum]->attributes[attNum]->dataDiffSaved=1;
		m_MyTree.SetItemText(tempAtt,textNew.GetBuffer(0));
	
	} else {

		//otherwise, we need to add a member

		//first add to behaviors
	
		Attribute *attNew = new Attribute();
		attNew->name = nameNew;
		attNew->data = dataNew;
		attNew->dataNew = dataNew;
		attNew->dataDiffSaved = 1;
		_behaviors[snum][selNum]->attributes.Add(attNew);

		//then add to the tree

		TV_INSERTSTRUCT tvstructAtt;
		TV_INSERTSTRUCT dummyKid;

		tvstructAtt.hParent = sel;
		tvstructAtt.hInsertAfter = TVI_LAST;
		tvstructAtt.item.iImage = 4;
		tvstructAtt.item.iSelectedImage = 4;
		tvstructAtt.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
		tvstructAtt.item.pszText = textNew.GetBuffer(0);
		tvstructAtt.item.lParam = attNum;

		HTREEITEM t = m_MyTree.InsertItem(&tvstructAtt);

		//and you have to create the artificial child
	
		dummyKid.hParent = t;
		m_MyTree.InsertItem(&dummyKid);
	
		delete attNew;
	}
	
	//finally, add to changeTree

	TV_INSERTSTRUCT cB;
	TV_INSERTSTRUCT cA;
	
	AddStateToChange(snum);

	HTREEITEM tRoot = m_ChangeTree.GetRootItem();
	if(m_ChangeTree.GetItemData(tRoot) != snum)
		tRoot = m_ChangeTree.GetNextSiblingItem(tRoot);

	if(tRoot == NULL)
		TRACE("Something serious screwed in changeTree\n");
	

	cB.hParent = tRoot;
	cB.hInsertAfter = TVI_LAST;
	CString pri;
	pri.Format("%d",_behaviors[snum][selNum]->priority);
	CString changed = "Behavior: "+_behaviors[snum][selNum]->name+" Priority: "+pri+ " New Attribute: "+
		_behaviors[snum][selNum]->attributes[attNum]->name;	
	cB.item.pszText = changed.GetBuffer(0);
	cB.item.lParam = selNum;
	cB.item.mask = TVIF_TEXT | TVIF_PARAM;
	HTREEITEM it_B = m_ChangeTree.InsertItem(&cB);

	cA.hParent = it_B;
	cA.hInsertAfter = TVI_LAST;
	CString attChanged = "New Attribute Data: " + dataNew;
	cA.item.pszText=attChanged.GetBuffer(0);
	cA.item.lParam = attNum;
	cA.item.mask = TVIF_TEXT | TVIF_PARAM;
	m_ChangeTree.InsertItem(&cA);

	delete addAtt;

}

void CAttribEditDlg::OnSingleupdate() 
{
	//only if connected and stopped send message
	if(_upStatus == con_stop){
		m_recipient->requestData(MMAgentRequest::Single,
			ModemMessage::tMMActiveBehavior, -1);
	}	
	//doesn't change status
}

void CAttribEditDlg::OnStartupdate() 
{
	//only if connected and not updating send message
	if(_upStatus == con_stop){
		m_recipient->requestData(MMAgentRequest::Start,
			ModemMessage::tMMActiveBehavior, ATT_BEHAVIOR_UPDATE_PERIOD);
	}
	if(_upStatus == con_stop)
		_upStatus = con_start;
	else if (_upStatus == uncon_stop)
		_upStatus = uncon_start;

	
}

void CAttribEditDlg::OnStopupdate() 
{
	//only if connected and updating send message
	if(_upStatus == con_start){
		m_recipient->requestData(MMAgentRequest::Stop,
			ModemMessage::tMMActiveBehavior, -1);
	}
	if(_upStatus == con_start)
		_upStatus = con_stop;
	else if (_upStatus == uncon_start)
		_upStatus = uncon_stop;
}

void CAttribEditDlg::OnShowWindow(BOOL bShow, UINT nStatus) 
{
	CDialog::OnShowWindow(bShow, nStatus);
	
	// TODO: Add your message handler code here
	
}

void CAttribEditDlg::Cleanup()
{
	for(int i = 0; i < 2; i++) {
		for(int j = 0; j < _behaviors[i].GetSize(); j++) {
			for(int k = 0; k < _behaviors[i][j]->attributes.GetSize(); k++) {
				delete _behaviors[i][j]->attributes[k];
			}
			_behaviors[i][j]->attributes.RemoveAll();
			delete _behaviors[i][j];
		}
		_behaviors[i].RemoveAll();
	}

	for(int h=0; h < toSend.GetSize(); h++) {
		delete toSend[h];
	}
	toSend.RemoveAll();

	CImageList* gonnaDie = m_MyTree.GetImageList(TVSIL_NORMAL);

	delete gonnaDie;
}


void CAttribEditDlg::OnClose() 
{
	OnStopupdate();
	m_fm->DeleteAttribEdit();
}

void CAttribEditDlg::OnJumpBehavior() 
{

	HTREEITEM sel = m_MyTree.GetSelectedItem();

	if(sel == m_MyTree.GetRootItem() ||
		sel == NULL) return;
	
	CString temp = m_MyTree.GetItemText(sel);
	temp = ExtractData(temp);
	//is this then we got the kid
	if(!temp.IsEmpty())
		sel = m_MyTree.GetParentItem(sel);

	//should have behavior at this point

	CString targetName = m_MyTree.GetItemText(sel);
	int targetPriority = m_MyTree.GetItemData(sel);
	
	targetPriority--; //because of comments

	CString tempS;
	tempS.Format("%d\n", targetPriority);
	CString mes = "Are you sure you want to jump to behavior name "+targetName+" priority "+tempS;

	if(MessageBox(mes,"Confirm",MB_YESNO) != IDYES) return;

	m_recipient->setJumpBehavior(targetPriority);
		
}

void CAttribEditDlg::setAttributeAck(bool type, bool success, short state, short priority, char* name)
{
	//if it's a single ack it's easy

	//first we need to find the index of the attribute in the big tree
	
	//comments are in _behaviors[state][0], so we need to iterate one
	priority++;

	CString n = name;

	int attIndex = findAttIndexFromName(state, priority,n);

	if(attIndex == -1) TRACE("Something totally screwed in setAttributeAck");

	if(success) {
		_behaviors[state][priority]->attributes[attIndex]->data =
		_behaviors[state][priority]->attributes[attIndex]->dataNew;
		_behaviors[state][priority]->attributes[attIndex]->dataNew.Empty();
		_behaviors[state][priority]->attributes[attIndex]->dataToSend = 0;
	} 

	//singleAck
	if(type == False) {
		//if it worked we can wipe it
		if(success) {
			m_ChangeTree.DeleteAllItems();
		} else {
			//we have to mark it failed
			
			//the root item must be the parent state
			HTREEITEM root = m_ChangeTree.GetRootItem();

			//mark the kid as failed
			HTREEITEM kid = m_ChangeTree.GetChildItem(root);
			CString temp = m_ChangeTree.GetItemText(kid);
			temp = "***FAILED***"+temp;
			m_ChangeTree.SetItemText(kid,temp.GetBuffer(0));
		}
	} else {
		//whole bunch of crap in change list
		//life gets more complicated

		//now we need to find it in the tree

		HTREEITEM tRoot = m_ChangeTree.GetRootItem();
		if(m_ChangeTree.GetItemData(tRoot) != state)
			tRoot = m_ChangeTree.GetNextSiblingItem(tRoot);

		if(tRoot == NULL)
		TRACE("Something serious screwed in changeTree\n");
				
		HTREEITEM tempBehavior = m_ChangeTree.GetChildItem(tRoot);
		HTREEITEM tKid; 

	//	CString s = m_ChangeTree.GetItemText(tempBehavior);
	//	TRACE("Beh: %s\n", s);

		while(tempBehavior != NULL) {

			tKid = m_ChangeTree.GetChildItem(tempBehavior);

			if(m_ChangeTree.GetItemData(tempBehavior) == priority &&
				m_ChangeTree.GetItemData(tKid) == attIndex) {
				if(success){
						m_ChangeTree.DeleteItem(tempBehavior);
				} else {
					CString temp = m_ChangeTree.GetItemText(tempBehavior);
					temp = "***FAILED***"+temp;
					m_ChangeTree.SetItemText(tempBehavior,temp.GetBuffer(0));
					break;
				}
			}

			tempBehavior = m_ChangeTree.GetNextSiblingItem(tempBehavior);
		}
		//if tRoot doesn't have children at this point, kill it
		if(!m_ChangeTree.ItemHasChildren(tRoot)) {
			m_ChangeTree.DeleteItem(tRoot);
		}

	}

}

int CAttribEditDlg::findAttIndexFromName(short state, short priority, CString name)
{

	int t = _behaviors[state][priority]->attributes.GetSize();
	for(int j = 0; j < t; j++) {
		if(_behaviors[state][priority]->attributes[j]->name == name) {
				return j;
		}
	}

	return -1;
}
