// macrodlg.cpp : implementation file
//

#include "stdafx.h"
#include <string.h>
#include "macrodlg.h"
#include "macrointerface.h"
#include "macrosymbols.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CMacroDlg dialog

CMacroDlg::CMacroDlg(CWnd* pParent, MacroInterface *pMacroInterface)
	: CDialog(CMacroDlg::IDD, pParent)									   
{
	_macroId = 0;
	m_pDialog = pParent;
	_pMacroInterface = pMacroInterface;

	//{{AFX_DATA_INIT(CMacroDlg)
	m_MacroProcess = _T("");
	//}}AFX_DATA_INIT


	HICON hIcon[4];

	imageList.Create( 16, 16, 0, 4, 4 );

	hIcon[Macro::LOADED] = AfxGetApp()->LoadIcon(IDR_LOAD);	//LOADING
	hIcon[Macro::RUNNING] = AfxGetApp()->LoadIcon(IDR_RUN); //RUNNING
	hIcon[Macro::COMPLETED] = AfxGetApp()->LoadIcon(IDR_COMPLETE); //COMPLETE
	hIcon[Macro::STOPPED] = AfxGetApp()->LoadIcon(IDR_STOP); //STOPPED

	for(int i=0; i<4; i++)
		imageList.Add(hIcon[i]);		

	_inProcess = TRUE;
	_prevDelay = 0;
	_delayStartTime = 0;

	if( (CDialog::Create(CMacroDlg::IDD) ) == TRUE)
		CWnd::ShowWindow(SW_SHOW);
}

void CMacroDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CMacroDlg)
	DDX_Text(pDX, IDC_STATIC_PROCESSNAME, m_MacroProcess);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CMacroDlg, CDialog)
	//{{AFX_MSG_MAP(CMacroDlg)
	ON_BN_CLICKED(ID_EXIT, OnExit)
	ON_BN_CLICKED(ID_START, OnStart)
	ON_BN_CLICKED(ID_STOP, OnStop)
	ON_BN_CLICKED(ID_RESUME, OnResume)
	ON_WM_TIMER()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMacroDlg message handlers

void CMacroDlg::OnExit() 
{
	// Stop macro processing
	// OnStop();	

	KillTimer(mTimer);
	if(m_pDialog != NULL)
		m_pDialog->PostMessage(WM_MODELESSEXIT,(LPARAM) this);				
	else //handle modal dialog case
		CDialog::OnCancel();		
}


Int16 CMacroDlg::Load(char *filename) 
{	
	MacroInterpreter::loadStatus status;
	Nat16 i;
	Nat32 id;
	CString s;

	MACROSOURCE source;
	if(Filter(filename, &source) == -1)
		return -1;

	MACROSOURCE::iterator line;

	if(_pMacroInterface->loadMacroProcess((char *)filename, &status, &id) == FALSE)
	{
		InsertItem("Error loading macros", 0); 
		if(status.err == Macro::BAD_FILETYPE_ERR)
		{				
			s.Format("Missing PROGRAM: identifier string");
			AfxMessageBox("Missing PROGRAM identifier string");
			EmptyVector(&source);
			return -1;
		}				
		if (status.err == Macro::MACRO_ALREADY_LOADED)
		{
			AfxMessageBox("MacroProcess already loaded");
			return -1;
		}

		for (line = source.begin(); line != source.end(); line++) {
			if (status.failedLine == (*line)->lineNo)
				break;
		}

		if(status.err == Macro::BAD_ARGC)				
		{
			s.Format("Macro %s bad argument count on line %d", 
				(*line)->text, (*line)->lineNo);

			AfxMessageBox(s.GetBuffer(60)); 
		}

		if(status.err == Macro::MACRO_NOT_FOUND)				
		{
			s.Format("Macro %s not found line %d", 
				(*line)->text, (*line)->lineNo);
				
			AfxMessageBox(s.GetBuffer(60)); 
		}
		if(status.err == Macro::ARG_OUT_RANGE)				
		{
			s.Format("Macro %s arg out of range line %d",
				(*line)->text, (*line)->lineNo);

			AfxMessageBox(s.GetBuffer(60)); 
		}
		if(status.err == Macro::MISSING_ARG)				
		{
			s.Format("Macro %s missing args line %d",
				(*line)->text, (*line)->lineNo);

			AfxMessageBox(s.GetBuffer(60)); 
		}	
		if (status.err == Macro::UNKNOWN_NAME)
		{
			s.Format("Unknown name specified in macro \"%s\", line %d",
				(*line)->text, (*line)->lineNo);

			AfxMessageBox(s.GetBuffer(60));
		}
		
		EmptyVector(&source);
		return -1;

	}

	_macroId = id;

	CWnd *button;
	button = GetDlgItem(ID_START);
	button->EnableWindow(TRUE);
	button = GetDlgItem(ID_STOP);
	button->EnableWindow(TRUE);
	button = GetDlgItem(ID_RESTART);
	button->EnableWindow(TRUE);

	CListCtrl *pListView = (CListCtrl*) GetDlgItem(IDC_MACROLIST);
	pListView->DeleteAllItems();

	line = source.begin();

	char programname[50];
	sscanf((*line)->text, "PROGRAM: %s", programname);
	m_MacroProcess = programname;

	for (i = 0, line++; line != source.end(); i++, line++) {
		InsertItem((*line)->text, i);
	}	

	EmptyVector(&source);
	UpdateData(FALSE);
	return 0;
}


void CMacroDlg::OnStart() 
{	
	_inProcess = TRUE;
	ClearAllStatus();

	Nat16 len = m_MacroProcess.GetLength();		
	_pMacroInterface->runMacroProcess((char *)m_MacroProcess.GetBuffer(len));
}
void CMacroDlg::ClearAllStatus()
{
	Nat16 cnt = 0;
	LV_ITEM lvi;
		
	CListCtrl *pListView = (CListCtrl*) GetDlgItem(IDC_MACROLIST);		
	lvi.mask = LVIF_IMAGE;

	do
	{
	lvi.iItem = cnt;		
	lvi.iSubItem = 0;			
	lvi.iImage = Macro::LOADED;	
	cnt++;
	}while(pListView->SetItem(&lvi));
}
void CMacroDlg::OnResume() 
{
	_inProcess = TRUE;
	_pMacroInterface->resumeMacro();
}

void CMacroDlg::OnStop() 
{	
	_pMacroInterface->stopProcess();
}

BOOL CMacroDlg::OnInitDialog() 
{
	CDialog::OnInitDialog();

	CListCtrl *pListView = (CListCtrl*) GetDlgItem(IDC_MACROLIST);
	pListView->InsertColumn(0, "STATUS", LVCFMT_LEFT,60, 0);	
	pListView->InsertColumn(1, "STEP", LVCFMT_LEFT,50, 1);	
	pListView->InsertColumn(2, "MACRO", LVCFMT_LEFT,220, 2);			
	pListView->SetImageList(&imageList,LVSIL_SMALL);		
	pListView->SetBkColor(RGB(0,255,255));
	pListView->SetTextBkColor(RGB(0,255,255));


	mTimer = SetTimer(1,2000,NULL); //~2000 msec second check for program status
	ASSERT(mTimer != 0);
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

Void CMacroDlg::InsertItem(char *text, Nat16 i) 
{
CString s;
LV_ITEM lvi;
Int32 ndx;
CListCtrl *pListView = (CListCtrl*) GetDlgItem(IDC_MACROLIST);		
if(text != NULL)
{
	lvi.mask = LVIF_IMAGE;
	lvi.iItem = i;		
	lvi.iSubItem = 0;		
	lvi.iImage = 0; //load image 0 IDR_LOAD
	ndx = pListView->InsertItem(&lvi);
	if(ndx != -1)
	{
		lvi.mask = LVIF_TEXT;
		s.Format("%d", i);		
		lvi.pszText = s.GetBuffer(s.GetLength());
		lvi.iItem = i;
		lvi.iSubItem = 1;
		pListView->SetItem(&lvi);

		s.Format("%s",text);
		s.TrimRight();	//trim newline chars
		lvi.pszText = s.GetBuffer(s.GetLength());
		lvi.iItem = i;
		lvi.iSubItem = 2;
		pListView->SetItem(&lvi);
	}
}//end if
}
void CMacroDlg::OnTimer(UINT nIDEvent) 
{
	CListCtrl *pListView = (CListCtrl*) GetDlgItem(IDC_MACROLIST);		
	LV_ITEM lvi;
	MacroInterface::status  s;

	_pMacroInterface->getProcessStatus(0,_macroId, &s);	

	Nat16 len = m_MacroProcess.GetLength();

	// if last recorded line count is greater than this step,must
	//have started over. Update status bitmaps to reflect this
	if(_lineCnt > s.step)
		ClearAllStatus();

	_lineCnt = s.step;

	//TRACE("Reading state for %s: %d\n", m_MacroProcess.GetBuffer(len), s.state);		

	if (_inProcess) {			

		lvi.mask = LVIF_IMAGE;
		lvi.iSubItem = 0;	
		lvi.iItem = s.step;				
		lvi.iImage = s.state;
		pListView->SetItem(&lvi);		
		DisplayTimeDelay(s.delay);
		
		if(s.state == Macro::STOPPED)
		{
			KillTimer(mTimer);
			AfxMessageBox(s.msg);
			SetTimer(1,2000,NULL); //~2000 msec second check for program status
		}
	}
	
	switch (s.state)
	{
	case(Macro::LOADED):
		_inProcess = FALSE;
		break;
	case(Macro::COMPLETED):
		_inProcess = TRUE;
		break;
	case(Macro::RUNNING):
		_inProcess = TRUE;
		break;
	case(Macro::STOPPED):
		_inProcess = FALSE;
		break;
	default:
		_inProcess = FALSE;
		break;
	}	

}
void CMacroDlg::DisplayTimeDelay(Nat32 delay)
{
	CString string;

	if (delay != _prevDelay) {
		if (delay == 0) {
			// No delay, so hide clock display
			string.Format("");
			SetDlgItemText(IDC_MESSAGE, string);
		}
		else {
			// Show clock display and start clock
			_delayStartTime = clock() / CLOCKS_PER_SEC;
		}
		_prevDelay = delay;
	}
	else if (_prevDelay != 0) {
		// Must be in delay macro; update clock display
		clock_t elapsed = clock() / CLOCKS_PER_SEC - _delayStartTime;
		string.Format("Delayed %d min %d sec (%d min %d sec remaining)", 
			elapsed/60, elapsed%60, (delay - elapsed)/60, (delay  - elapsed)% 60);		
		SetDlgItemText(IDC_MESSAGE, string);
	}
}


Int16 CMacroDlg::Filter(const char *filename, MACROSOURCE *source)
{
	CString s;

	if(filename == NULL)
		return -1;	

	FILE *stream = fopen(filename, "r+t"); 	
	if(stream == NULL) 
	{
		s.Format("Error opening program file: %s",filename);
		AfxMessageBox(s);		
		return -1;
	}

	char line[100];

	// Note that lineNo is one-based
	for (int lineNo = 1; fgets(line, sizeof(line), stream) != NULL; lineNo++)
	{		
		// Strip off trailing newline
		if (line[strlen(line) - 1] == '\n')
			line[strlen(line) - 1] = '\0';

		char *ptr;
		// Strip off comments
		if ((ptr = strchr(line, COMMENT_CHAR)) != NULL) {
			*ptr = '\0';
		}

		if(!strcmp(line, END_MNEM)) //found end of program break out of loop
			break;

		// Look for non-blank characters 
		Boolean allBlanks = TRUE;
		for (ptr = line; *ptr != '\0'; ptr++)
		{
			if (*ptr != ' ' && *ptr != '\t') {
				allBlanks = FALSE;
			}
		}

		// If line is all blank, then skip it
		if (allBlanks)
			continue;

		MacroSourceLine *srcLine = new MacroSourceLine(line, lineNo);
		if(srcLine != NULL)
			source->push_back(srcLine);
	}

	fclose(stream);
	return 0;
}
Void CMacroDlg::EmptyVector(MACROSOURCE *theVector)
{
	MACROSOURCE::iterator line;

	if(theVector != NULL)
		for (line = theVector->begin(); line != theVector->end(); line++) 
			delete (*line);

	theVector->clear();
}

char *CMacroDlg::ProcessName()
{
	UpdateData(TRUE);
	Nat16 len = m_MacroProcess.GetLength();
	return m_MacroProcess.GetBuffer(len);
}


void CMacroDlg::Refresh()
{
	ShowWindow(SW_SHOW);
	
	mTimer = SetTimer(1,2000,NULL); //~2000 msec second check for program status
	ASSERT(mTimer != 0);
	
	ClearAllStatus();

	MacroInterface::status  s;
	_pMacroInterface->getProcessStatus(0,_macroId, &s);	

	Nat16 cnt = 0;
	LV_ITEM lvi;		
	CListCtrl *pListView = (CListCtrl*) GetDlgItem(IDC_MACROLIST);		
	lvi.mask = LVIF_IMAGE;

	for(cnt=0;cnt<s.step;cnt++)
	{
	lvi.iItem = cnt;		
	lvi.iSubItem = 0;			
	lvi.iImage = Macro::COMPLETED;
	pListView->SetItem(&lvi);
	}
	
	lvi.iItem = s.step;		
	lvi.iSubItem = 0;			
	lvi.iImage = s.state;

}
