// GosViewDoc.cpp : implementation of the CGosViewDoc class
//

#include "stdafx.h"
#include "GosView.h"

#include "GosViewDoc.h"
#include "MainFrm.h"
#include "goseventpane.h"
#include "TimeFrame.h"
#include "TargetDialog.h"

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


/////////////////////////////////////////////////////////////////////////////
// CGosViewDoc

IMPLEMENT_DYNCREATE(CGosViewDoc, CDocument)

BEGIN_MESSAGE_MAP(CGosViewDoc, CDocument)
	//{{AFX_MSG_MAP(CGosViewDoc)
	ON_EN_CHANGE(IDC_EDIT1, OnChangeEdit1)
	ON_COMMAND(ID_CONNECT, OnConnect)
	ON_COMMAND(ID_DISCONNECT, OnDisconnect)
	ON_UPDATE_COMMAND_UI(ID_CONNECT, OnUpdateConnect)
	ON_UPDATE_COMMAND_UI(ID_DISCONNECT, OnUpdateDisconnect)
	ON_COMMAND(ID_START_TRACE, OnStartTrace)
	ON_UPDATE_COMMAND_UI(ID_START_TRACE, OnUpdateStartTrace)
	ON_COMMAND(ID_STOP_TRACE, OnStopTrace)
	ON_UPDATE_COMMAND_UI(ID_STOP_TRACE, OnUpdateStopTrace)
	ON_COMMAND(ID_TRACE_ONCE, OnTraceOnce)
	ON_UPDATE_COMMAND_UI(ID_TRACE_ONCE, OnUpdateTraceOnce)
	ON_UPDATE_COMMAND_UI(ID_FONTBUTTON, OnUpdateFontbutton)
	ON_COMMAND(ID_FONTBUTTON, OnFontbutton)
	ON_COMMAND(ID_TARGET_BUTTON, OnTargetButton)
	//}}AFX_MSG_MAP
	ON_UPDATE_COMMAND_UI(ID_CONNECTION_STATUS, OnUpdateConnectionStatus)
	ON_UPDATE_COMMAND_UI(IDC_SHOWDOC, OnUpdateDocName )

END_MESSAGE_MAP()



void CGosViewDoc::OnUpdateConnectionStatus(CCmdUI* pCmdUI)
{
	/*
    CString string;
	switch( m_Session.State() )
	{
	case CSession::NotConnected:
	    string.Format (_T ("Not Connected"));
		break;
	case CSession::AwaitingConnection:
	    string.Format (_T ("Awaiting Connection"));
		break;
	case CSession::Connected:
	    string.Format (_T ("Connected"));
		break;
	case CSession::SessionError:
	    string.Format (_T ("Error"));
		break;
	default:
	    string.Format (_T ("UNKNOWN !"));
	}
	*/
    pCmdUI->Enable (TRUE);
    pCmdUI->SetText ( m_Session.StateName() );
}
void CGosViewDoc::OnUpdateDocName(CCmdUI* pCmdUI)
{
//    CString string;
//	static int cnt=0;
//	cnt++;
 //   string.Format (_T ("Doc %d %s"), cnt, m_ConnName);
 //   pCmdUI->Enable (TRUE);
 //   pCmdUI->SetText (string);
}


/////////////////////////////////////////////////////////////////////////////
// CGosViewDoc construction/destruction

CGosViewDoc::CGosViewDoc()
{
	m_Session.SetOwningDoc( this );

	m_fTracing = false;
	m_fTraceReady = false;

	gethostname( m_ConnName, 50 );

	RECT rect = { 0, 0, 0, 0 };
	CMainFrame *pFrame = (CMainFrame *) AfxGetApp()->m_pMainWnd;

	m_pLog = NULL;
	m_pLogEnd = NULL;
	m_pFont = NULL;
	m_nFreq = 731000000;

	m_Session.Create(NULL,"Session",WS_CHILD, rect, pFrame, ID_SESSION );
}

CGosViewDoc::~CGosViewDoc()
{
	if( m_pLog )
		free( m_pLog );
}

BOOL CGosViewDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;


	return TRUE;
}



/////////////////////////////////////////////////////////////////////////////
// CGosViewDoc serialization

void CGosViewDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		ar << CString("GosView V1.0.0 file");

		for( TagInfoEntry *pTIE = m_TagInfo.First(); pTIE; pTIE = m_TagInfo.Next(pTIE) )
		{
			ar << CString("Tag");
			ar << pTIE->id;
			ar << CString(pTIE->Name);
		}

		ar << CString("CPU Freq");
		ar.Write( (void *)& m_nFreq, sizeof(m_nFreq) );

		ar << CString("TStart");
		ar.Write( (void *)& m_tLogStart, sizeof(m_tLogStart) );

		ar << CString("TEnd");
		ar.Write( (void *)& m_tLogEnd, sizeof(m_tLogEnd) );

		ar << CString("LogSize") << (unsigned long)m_pLogEnd - (unsigned long)m_pLog;

		ar << CString("LogData");

		ar.Write( (void *)m_pLog, (unsigned long)m_pLogEnd - (unsigned long)m_pLog );

		ar << CString("EndOfFile");


	}
	else
	{
		CString version;
		ar >> version;
		if( version != CString("GosView V1.0.0 file") )
		{
			DebugBreak();	// incompatible file version
			return;
		}
		CString lType;
		GosLogInfo logInfo;
		unsigned long *pNewLog;

		for( ar >> lType; lType != CString("EndOfFile"); ar >> lType )
		{
			if( lType == CString("Tag") )
			{
				unsigned long id;
				CString name;
				ar >> id;
				ar >> name;
				TagInfoEntry *pTIE = m_TagInfo.Allocate(id);
				pTIE->id = id;
				strcpy( pTIE->Name, name );
			}
			else if( lType == CString("CPU Freq") )
			{
				ar.Read( (void *)&m_nFreq, sizeof(m_nFreq) );
			}
			else if( lType == CString("TStart") )
			{
				ar.Read( (void *)&logInfo.tLogStart, sizeof(logInfo.tLogStart) );
			}
			else if( lType == CString("TEnd") )
			{
				ar.Read( (void *)&logInfo.tLogEnd, sizeof(logInfo.tLogEnd) );
			}
			else if( lType == CString("LogSize") )
			{
				ar.Read( (void *)&logInfo.logLength, sizeof(logInfo.logLength) );
			}
			else if( lType == CString("LogData") )
			{
				pNewLog = (unsigned long *)malloc(logInfo.logLength);
				ar.Read( (void *)pNewLog, logInfo.logLength );
			}
			else
			{
				// Error reading log
				DebugBreak();
			}
		}
		ParseNewLog( pNewLog, &logInfo );

	}
}

/////////////////////////////////////////////////////////////////////////////
// CGosViewDoc diagnostics

#ifdef _DEBUG
void CGosViewDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CGosViewDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CGosViewDoc commands



void CGosViewDoc::OnChangeEdit1() 
{
	// TODO: If this is a RICHEDIT control, the control will not
	// send this notification unless you override the CDocument::OnInitDialog()
	// function and call CRichEditCtrl().SetEventMask()
	// with the ENM_CHANGE flag ORed into the mask.
	
	// TODO: Add your control notification handler code here

	CMainFrame *pFrame = (CMainFrame *) AfxGetApp()->m_pMainWnd;

	CDialogBar *pDialogBar = &(pFrame->m_wndDlgBar2);
	
	CEdit *pEdit = (CEdit *)(pDialogBar->GetDlgItem(IDC_EDIT1));

	pEdit->GetLine(0,m_ConnName,250);
}


void CGosViewDoc::SetFocus()
{
	/*
	CMainFrame *pFrame = (CMainFrame *) AfxGetApp()->m_pMainWnd;

	CDialogBar *pDialogBar = &(pFrame->m_wndDlgBar2);
	
	CEdit *pEdit = (CEdit *)(pDialogBar->GetDlgItem(IDC_EDIT1));

	pEdit->SetSel(0,-1);

	pEdit->ReplaceSel(m_ConnName);
	*/

}

void CGosViewDoc::OnConnect() 
{
	m_Session.Connect( m_ConnName );
}

void CGosViewDoc::OnDisconnect() 
{
	m_fTracing = false;
	m_Session.Disconnect();
}

void CGosViewDoc::OnUpdateConnect(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( m_Session.State() == CSession::NotConnected );
}

void CGosViewDoc::OnUpdateDisconnect(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( m_Session.State() != CSession::NotConnected );

}

//	bool SendCommand( int command, void *pData, void (*pHandler)(void *, int, void *) )


void CGosViewDoc::OnStartTrace() 
{
	m_fTraceOnce = false;
	m_fTracing = true;
	m_Session.SendCommand( GVCMD_STARTLOG, 0, NULL );
}

void CGosViewDoc::OnUpdateStartTrace(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( false ); // !m_fTracing && ( m_Session.State() == CSession::Connected ) );

}

void CGosViewDoc::OnStopTrace() 
{
	m_fTracing = false;
	m_Session.SendCommand( GVCMD_STOPLOG, 0, NULL );

}

void CGosViewDoc::OnUpdateStopTrace(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( m_fTracing && ( m_Session.State() == CSession::Connected ) );
	
}



void CGosViewDoc::ParseNewLog( DWORD *pLog, GosLogInfo *pLogInfo )
{
	// walk through the log looking for new IDs
	DWORD *pLogEntry;
	DWORD *pLogEnd = (DWORD *)(((char *)pLog)+pLogInfo->logLength);

	if( m_fTraceOnce )
		m_fTracing = false;

	bool NewTags = false;
	
	UpdateTimeFrameList();

	DWORD tag;
	DWORD time;

	for( pLogEntry = pLog; pLogEntry < pLogEnd; )
	{
		// check if it is a valid entry start
		// FOR NOW ASSUME WE ONLY HAVE A VALID LOG START & STOP

		tag = *pLogEntry++;
		time = *pLogEntry++;

		// check if we have this ID already
		if( !m_TagInfo.Contains(tag) )
		{
			// get the details of the new id
			GetIDName( tag );

			for( POSITION pos = m_TimeFrameList.GetHeadPosition(); pos!=NULL; )
			{
				CTimeFrame *pFrame = (CTimeFrame *)(m_TimeFrameList.GetNext(pos));
				pFrame->AddId( tag );
			}
		}
	}

	// Substitute this for the current log
	if( m_pLog )
		free( m_pLog );
	m_pLog = pLog;
	m_pLogEnd = pLogEnd;
	m_tLogStart = pLogInfo->tLogStart;
	m_tLogEnd = pLogInfo->tLogEnd;

	m_fTraceReady = true;

	
	// Get each timeframe to update itself
	for( POSITION pos = m_TimeFrameList.GetHeadPosition(); pos!=NULL; )
	{
		CTimeFrame *pFrame = (CTimeFrame *)(m_TimeFrameList.GetNext(pos));
		pFrame->SetDocument(this);
		pFrame->UpdateAllIds();
		pFrame->ProcessNewLog();
	}

	// now get each view to update itself
	UpdateAllViews(NULL);

}

char * CGosViewDoc::GetIDName( DWORD id )
{
	TagInfoEntry *pTIE = m_TagInfo.Find(id);
	if( !pTIE )
	{
		m_Session.SendCommand( GVCMD_GETEVENTNAME, 4, (char *)&id );
		pTIE = m_TagInfo.Allocate(id);
		m_Session.ReceiveData( 255, pTIE->Name );
		pTIE->id = id;
	}
	return pTIE->Name;
};

void CGosViewDoc::OnTraceOnce() 
{
	m_fTraceOnce = true;
	m_fTracing = true;
	m_Session.SendCommand( GVCMD_STARTLOGONCE, 0, NULL );
}

void CGosViewDoc::OnUpdateTraceOnce(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( !m_fTracing && ( m_Session.State() == CSession::Connected ) );
}




void CGosViewDoc::UpdateTimeFrameList()
{
	m_TimeFrameList.RemoveAll();

	POSITION pos;
	CGosEventPane *pView;
	for( pos = GetFirstViewPosition(); pos; )
	{
		pView = (CGosEventPane *)GetNextView( pos );
		if( m_TimeFrameList.Find(pView->m_pParentFrame) == NULL )
			m_TimeFrameList.AddTail(pView->m_pParentFrame);
	}
}

void CGosViewDoc::OnUpdateFontbutton(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable();
}

void CGosViewDoc::OnFontbutton() 
{
	CFontDialog cFontDlg;
	if( cFontDlg.DoModal() == IDOK )
	{
		if( m_pFont )
			delete m_pFont;
		m_pFont = new CFont();
		LOGFONT logFont;
		cFontDlg.GetCurrentFont(&logFont);
		m_pFont->CreateFontIndirect(&logFont);
		UpdateAllViews(NULL);
	}
}

void CGosViewDoc::OnTargetButton() 
{
	CTargetDialog dlg( this );
	dlg.DoModal();
}
