/*
*******************************************************************************
* Copyright (c) 1996-97 Digi International Inc., All Rights Reserved          *
*                                                                             *
* This  software  contains  proprietary  and  confidential   information   of *
* Digi International  Inc.   By  accepting  transfer  of this copy, Recipient *
* agrees to retain this software in  confidence,  to  prevent  disclosure  to *
* others,  and  to make no  use of this software other than that for which it *
* was delivered.  This is an unpublished copyright work  Digi   International *
* Inc.    Except   as   permitted   by  federal  law,  17 USC 117, copying is *
* strictly prohibited.                                                        *
*                                                                             *
* Digi  International  Inc.  CONFIDENTIAL  -   (Digi    International    Inc. *
* Confidential  when   combined   with   the   aggregated  modules  for  this *
* product) OBJECT CODE ONLY SOURCE MATERIALS                                  *
*                                                                             *
* (C) COPYRIGHT Digi International Inc. 1996-97                               *
*                                                                             *
* All Rights Reserved                                                         *
*                                                                             *
* US   Government   Users   Restricted   Rights   -   Use,   duplication   or *
* disclosure  restricted by GSA ADP Schedule Contract with Digi International *
* Inc.                                                                        *
*                                                                             *
*******************************************************************************

// PacketListView.cpp : implementation file
//

Revision History:

   $History: PacketListView.cpp $
 * 
 * *****************  Version 31  *****************
 * User: Mikez        Date: 7/11/97    Time: 5:02p
 * Branched in $/Components/Windows/NT/Sync/Build/Diag
 * 
 * *****************  Version 30  *****************
 * User: Rodgerb      Date: 2/25/97    Time: 1:23p
 * Updated in $/Components/Windows/NT/Sync/rev2diag
 * 
 * *****************  Version 29  *****************
 * User: Rodgerb      Date: 1/27/97    Time: 1:18p
 * Updated in $/Components/Windows/NT/Sync/rev2diag
 * 1) documentation
 * 2) added some new params to Physical layer stats

*/

#include "stdafx.h"
#include "Diagnostic.h"

#include "DiagDoc.h"
#include "PacketListView.h"

#include "progdlg.h"

#include <afxpriv.h>

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

/////////////////////////////////////////////////////////////////////////////
// CPacketListView

IMPLEMENT_DYNCREATE(CPacketListView, CListViewEx)

CPacketListView::CPacketListView() : m_FilterCircuit()
{
	InListChange = FALSE;
	m_bActive = FALSE;
	m_FilterMask = fmALL;
}

CPacketListView::~CPacketListView()
{
}


BEGIN_MESSAGE_MAP(CPacketListView, CListViewEx)
	//{{AFX_MSG_MAP(CPacketListView)
	ON_WM_ERASEBKGND()
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
	ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, OnItemchanged)
	ON_COMMAND(ID_VIEW_FINDMISSING, OnViewMissing)
	ON_WM_SIZE()
	ON_NOTIFY_REFLECT(NM_RCLICK, OnRclick)
	ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetdispinfo)
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPacketListView drawing

void CPacketListView::OnDraw(CDC*)
{
	CDocument* pDoc = GetDocument();
	// TODO: add draw code here
}

/////////////////////////////////////////////////////////////////////////////
// CPacketListView diagnostics

#ifdef _DEBUG
void CPacketListView::AssertValid() const
{
	CListViewEx::AssertValid();
}

void CPacketListView::Dump(CDumpContext& dc) const
{
	CListViewEx::Dump(dc);
}

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

/////////////////////////////////////////////////////////////////////////////
// CPacketListView message handlers

LRESULT CPacketListView::OnCommandHelp(WPARAM wParam, LPARAM lParam)
{
	if (lParam == 0)
	{
		lParam = cvtidListView;
	}
	
	return GetParentFrame()->SendMessage(WM_COMMANDHELP, wParam, lParam);
}

void CPacketListView::OnUpdate(CView *pSender, LPARAM lHint, CObject*) 
{
	// TODO: Add your specialized code here and/or call the base class
	BOOL SameParentFrame =	pSender == NULL || 
													pSender->GetParentFrame() == GetParentFrame();

	CListCtrl& ListCtrl = GetListCtrl();

// high 24 bits is item in list
	int nListItemIndex = (int)(lHint) >> 8;
// low byte is update message
	lHint = LOBYTE(lHint);
	
	if ((lHint & uavFrameListSelChange) > 0 && SameParentFrame)
	{
		InListChange = TRUE;

		int nSel = ListCtrl.GetNextItem(-1, LVNI_SELECTED);
		
		if (nSel > -1)
			ListView_SetItemState(ListCtrl.GetSafeHwnd(), nSel, 0,
														LVIS_FOCUSED | LVIS_SELECTED);

		if (nListItemIndex > -1)
		{
			ListView_SetItemState(ListCtrl.GetSafeHwnd(),
														nListItemIndex,
														LVIS_FOCUSED | LVIS_SELECTED,
														LVIS_FOCUSED | LVIS_SELECTED);
			ListCtrl.EnsureVisible(nListItemIndex, FALSE);
		}

		InListChange = FALSE;
	}
}

extern BOOL ListViewEraseBkgnd(CDC* pDC, CWnd *parent, CListCtrl&);
BOOL CPacketListView::OnEraseBkgnd(CDC* pDC) 
{
	// TODO: Add your message handler code here and/or call default
	return ListViewEraseBkgnd(pDC, this, GetListCtrl())
						? CView::OnEraseBkgnd(pDC)
						: TRUE;
}

BOOL CPacketListView::PreCreateWindow(CREATESTRUCT& cs) 
{
	// TODO: Add your specialized code here and/or call the base class
	cs.style &= ~LVS_TYPEMASK;
	cs.style |= LVS_REPORT | LVS_ALIGNLEFT | LVS_SINGLESEL |
							LVS_NOSORTHEADER | LVS_SHOWSELALWAYS;

// use new common controls DLL LVS_OWNERDATA list control style
	if (HasNewCommonControls())
		cs.style |= LVS_OWNERDATA;

	return CListViewEx::PreCreateWindow(cs);
}

void CPacketListView::OnActivateView(	BOOL bActivate,
																			CView* pActivateView,
																			CView* pDeactiveView) 
{
	// TODO: Add your specialized code here and/or call the base class
	CListViewEx::OnActivateView(bActivate, pActivateView, pDeactiveView);

	m_bActive = bActivate;

	if (bActivate)
		GetParentFrame()->OnUpdateFrameTitle(TRUE);

	RepaintSelectedItems();
}

void CPacketListView::OnInitialUpdate() 
{
	// TODO: Add your specialized code here and/or call the base class
	CListViewEx::OnInitialUpdate();

	CTraceData *pTD = GetDocument()->GetTraceData();
	CListCtrl& ListCtrl = GetListCtrl();

	m_Hint = uavFrameListSelChange;

	if (pTD == NULL)
		ListCtrl.DeleteAllItems();
	else
	{
		LPCSTR Name[plcNumColumns] =
										{ "Frame Number", "Timestamp", "Source",
											pTD->GetEndPointName(), "Protocol", "Description"
										};
		int Size[plcNumColumns] = { 85, 80, 60, 55, 55, 150 };
		int Align[plcNumColumns] =
										{ LVCFMT_RIGHT, LVCFMT_RIGHT, LVCFMT_LEFT,
											LVCFMT_RIGHT, LVCFMT_CENTER, LVCFMT_LEFT
										};

		for (short i = 0; i < plcNumColumns; i++)
			ListCtrl.InsertColumn(i, Name[i], Align[i], Size[i], i);

		GetFilterFrames();
	}

// last column is sizes to take up remaining space in window
	SetFocus();
	CRect rect;
	GetWindowRect(rect);
	OnSize(SIZE_RESTORED, rect.Width(), rect.Height());
}

void CPacketListView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
	CListViewEx::OnKeyDown(nChar, nRepCnt, nFlags);

// when the user holds down a key that scrolls through list
// the a different message is sent out to the other views
// the tree control will not update itself so that scrolling
// will go faster
	if (nRepCnt > 1 && (nChar >= VK_PRIOR && nChar <= VK_DOWN))
		m_Hint = uavFrameListSelChange | uavFrameListRepSelChange;
}

void CPacketListView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
	CListViewEx::OnKeyUp(nChar, nRepCnt, nFlags);

	if ((m_Hint & uavFrameListRepSelChange) > 0)
	{
		m_Hint &= ~uavFrameListRepSelChange;

		int nSel = GetListCtrl().GetNextItem(-1, LVNI_SELECTED);

		if (nSel > -1)
		{
			DWORD frame = GetFilteredIndex(nSel);

			GetDocument()->UpdateAllViews(this,
																		(nSel << 8) + uavFrameListSelChange,
																		(CObject *)frame);
		}
	}
}

void CPacketListView::OnItemchanged(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here
	*pResult = 0;

	if (InListChange)
		return;

	InListChange = TRUE;

	if (	pNMListView->uChanged == LVIF_STATE &&
				(pNMListView->uNewState & LVIS_SELECTED) > 0
			)
	{
		DWORD frame = GetFilteredIndex(pNMListView->iItem);

		GetDocument()->UpdateAllViews(this,
																	(pNMListView->iItem << 8) + m_Hint,
																	(CObject *)frame);
	}

	InListChange = FALSE;
}

// ListView_SetItemState is used to be compatible with
// new common controls DLL
void CPacketListView::OnViewMissing() 
{
	// TODO: Add your command handler code here
	CListCtrl& ListCtrl = GetListCtrl();

	int nSel = ListCtrl.GetNextItem(-1, LVNI_SELECTED);

	if (nSel > -1)
	{
		CTraceData *pTD = GetDocument()->GetTraceData();
	
		DWORD FrameNum = pTD->GetTempFrame(GetFilteredIndex(nSel))->GetFrameNum();
	
		int StartSel = nSel;

		for (nSel++; nSel < ListCtrl.GetItemCount(); nSel++)
		{
			DWORD NewFrameNum = pTD->GetTempFrame(GetFilteredIndex(nSel))->GetFrameNum();

			if (FrameNum + 1 != NewFrameNum)
			{
				ListView_SetItemState(ListCtrl.GetSafeHwnd(),
															StartSel,
															0,
															LVIS_SELECTED);

				ListView_SetItemState(ListCtrl.GetSafeHwnd(),
															nSel,
															LVIS_SELECTED,
															LVIS_SELECTED);

				ListCtrl.EnsureVisible(nSel, TRUE);
				break;
			}

			FrameNum = NewFrameNum;
		}
	}
}

void CPacketListView::OnSize(UINT nType, int cx, int cy) 
{
	CListViewEx::OnSize(nType, cx, cy);
	
	// TODO: Add your message handler code here
	CListCtrl& ListCtrl = GetListCtrl();

	if	(	nType != SIZE_MINIMIZED && !IsIconic() &&
				ListCtrl.GetSafeHwnd() != NULL
			)
	{
		int OtherColumnsWidth = 0;
		
		for (short i = 0; i < 5; i++)
			OtherColumnsWidth += ListCtrl.GetColumnWidth(i);

		ListCtrl.SetColumnWidth(5, __max(150, cx - OtherColumnsWidth));
	}
}

void CPacketListView::OnRclick(NMHDR*, LRESULT* pResult) 
{
	// TODO: Add your control notification handler code here
	POINT pt;

	GetCursorPos(&pt);
	GetParentFrame()->SendMessage(WM_RBUTTONUP,
																MK_RBUTTON,
																(pt.y << 16) + pt.x);

	*pResult = 1;
}

void CPacketListView::OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult) 
{
	LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
	// TODO: Add your control notification handler code here
	*pResult = 0;

	if ((pDispInfo->item.mask & LVIF_TEXT) != LVIF_TEXT)
		return;

	CTraceData *pTD = GetDocument()->GetTraceData();

	CFrame *pFrame = pTD->GetTempFrame(GetFilteredIndex(pDispInfo->item.iItem));

	CString temp;

	switch (pDispInfo->item.iSubItem)
	{
		case plcFrameNumber :
			temp.Format("%d", pFrame->GetFrameNum());
			break;
		case plcTime :
			temp.Format("%6.3f", pTD->TimeInSeconds(pFrame->GetTimeStamp()));
			break;
		case plcSource :
			temp = pFrame->GetTxRx() ? "Remote" : "Local";
			break;
		case plcCircuitNumber :
			if (pFrame->GetCircuit() != (DWORD)-1)
				temp.Format("%4d", pFrame->GetCircuit());
			else
				temp = "N/A";
			break;
		case plcFrameProtocol :
			temp = pFrame->GetProtocol();
			break;
		case plcDescription :
			pFrame->GetDescription(temp);
			break;
	}

	strncpy(pDispInfo->item.pszText, temp, pDispInfo->item.cchTextMax);
}

void CPacketListView::GetFilterFrames() 
{
	CTraceData *pTraceData = GetDocument()->GetTraceData();
	
	if (pTraceData == NULL)
		return;

	pTraceData->GetFilteredFrames(m_Filtered, m_FilterMask, &m_FilterCircuit);

	InListChange = TRUE;

	CListCtrl& ListCtrl = GetListCtrl();
	CWaitCursor wait;

	ListCtrl.DeleteAllItems();

	if (HasNewCommonControls())
		ListView_SetItemCountEx(ListCtrl.GetSafeHwnd(),
														GetNumFilteredFrames(),
														LVSICF_NOSCROLL | LVSICF_NOINVALIDATEALL);
	else
	{
		CProgressDlg ProgressDlg; // 0 to 100 percent range
	
		int nNumframes = GetNumFilteredFrames();

// bring up progress when there are more than 1000 frame
		if (nNumframes > 1000)
		{
			ProgressDlg.Create();
			ProgressDlg.SetRange(0, 100);
		}

// how many frames in 1%
		float onepercent = nNumframes / 100.0f;
// count of percentage complete
		float total = onepercent;
// tell control to prealloc mem
		ListCtrl.SetItemCount(nNumframes);

		for (int i = 0; i < nNumframes;)
		{
			ListCtrl.InsertItem(i++, LPSTR_TEXTCALLBACK);

			if (nNumframes > 1000 && i == (int)round(total))
			{
				ProgressDlg.StepIt();
				total += onepercent;
			}
		}
	}

	InListChange = FALSE;

	int nIndex = ListCtrl.GetItemCount() > 0 ? ListCtrl.GetTopIndex() : -1;
	DWORD dwFrame = nIndex > -1 ? GetFilteredIndex(nIndex) : -1;

	GetDocument()->UpdateAllViews(NULL,
																(nIndex << 8) + uavFrameListSelChange,
																(CObject *)dwFrame);
}

BOOL CPacketListView::OnCaptureFilter() 
{
	// TODO: Add your command handler code here
	CTraceData *pTraceData = GetDocument()->GetTraceData();
	BOOL Result = FALSE;

	if	(	pTraceData != NULL &&
				pTraceData->DoFilterOptions(m_FilterMask, &m_FilterCircuit)
			)
	{
		GetFilterFrames();
		Result = TRUE;
	}

	return Result;
}
