/*
*******************************************************************************
* Copyright (c) 1996-2000 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.                                                                        *
*                                                                             *
*******************************************************************************

// X25VCStatView.cpp : implementation file
//

*/

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

#include "DataSource.h"
#include "X25VCStatView.h"

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

/////////////////////////////////////////////////////////////////////////////
// CX25VCStatView

IMPLEMENT_DYNCREATE(CX25VCStatView, CTracePage)

CX25VCStatView::CX25VCStatView() : CTracePage(CX25VCStatView::IDD)
{
}

CX25VCStatView::~CX25VCStatView()
{
}


void CX25VCStatView::DoDataExchange(CDataExchange* pDX)
{
	CTracePage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CLAPBLineView)
	DDX_Control(pDX, IDC_VCStatList, m_ListCtrl);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CX25VCStatView, CTracePage)
	//{{AFX_MSG_MAP(CX25VCStatView)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CX25VCStatView message handlers

inline int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM)
{
	return (int)(lParam1 - lParam2);
}

BOOL CX25VCStatView::OnInitDialog() 
{
	CPropertyPage::OnInitDialog();
	
	// TODO: Add extra initialization here
	LPCSTR str[5] = { "Channel", "Frames tx", "Frames rx", "Bytes tx", "Bytes rx" };
	int size[5] = { 55, 70, 70, 70, 70 };
	
	for (short i = 0; i < 5; i++)
		m_ListCtrl.InsertColumn(i, str[i], LVCFMT_LEFT, size[i], i);

	const CX25TraceData *td = (CX25TraceData *)GetTraceData();

	if (td != NULL)
	{
		POSITION pos = td->m_VCStats.GetStartPosition();
		int index = 0;
		
		while (pos)
		{
			DWORD ch;
			sX25VCStats *vc;

			td->m_VCStats.GetNextAssoc(pos, ch, vc);
			m_ListCtrl.SetItemData(m_ListCtrl.InsertItem(index++, LPSTR_TEXTCALLBACK), ch);
		}

		m_ListCtrl.SortItems(CompareFunc, NULL);
	}

	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CX25VCStatView::OnUpdate(WPARAM lHint) 
{
	// TODO: Add your specialized code here and/or call the base class
	if (lHint == uavTraceFasterPeriod) {
		const CX25TraceData *td = (const CX25TraceData *)GetTraceData();

		CDC *pDC = m_ListCtrl.GetDC();
		CFont *font = pDC->SelectObject(GetFont());

		int limit = __min(m_ListCtrl.GetItemCount(), 
											m_ListCtrl.GetTopIndex() + m_ListCtrl.GetCountPerPage());

		for (short i = m_ListCtrl.GetTopIndex(); i < limit; i++) {
			int channel = (int)(m_ListCtrl.GetItemData(i));
			sX25VCStats *vc = NULL;
			
			td->m_VCStats.Lookup(channel, vc);
			if (vc) {
				DRAWITEMSTRUCT DrawItemStruct = { ODT_LISTVIEW,
																					0,
																					0,
																					ODA_DRAWENTIRE,
																					0,
																					NULL,
																					*pDC };
	
				RECT rect;
				m_ListCtrl.GetItemRect(i, &rect, LVIR_BOUNDS);
				DrawItemStruct.rcItem = rect;

				DrawItemStruct.itemData = channel;

				m_ListCtrl.DrawItem(&DrawItemStruct);
				}
			}

		pDC->SelectObject(font);
		ReleaseDC(pDC);
		}
}

void RemoveRectRgn(CRgn& rgn, CWnd *sheet, CWnd *wnd)
{
	WORD style = LOWORD(wnd->GetStyle());
	char cls[32];
	
	::GetClassName(wnd->GetSafeHwnd(), cls, 32);
	if (strcmp(cls, "Button") == 0 && style == BS_GROUPBOX)
		return;

	CRect rect;
	wnd->GetWindowRect(rect);
	sheet->ScreenToClient(rect);
	CRgn region;
	region.CreateRectRgnIndirect(rect);

	rgn.CombineRgn(&rgn, &region, RGN_DIFF);
}

BOOL GenericEraseBkgnd(CDC* pDC, CWnd *parent)
{
	CRect rct;
	parent->GetClientRect(rct);
	
	if (!rct.IsRectEmpty()) {
		CRgn rgn;
		rgn.CreateRectRgnIndirect(rct);

		for (CWnd *wnd = parent->GetWindow(GW_CHILD); wnd; wnd = wnd->GetWindow(GW_HWNDNEXT))
			RemoveRectRgn(rgn, parent, wnd);

		FillRgn(*pDC, rgn, (HBRUSH)GetStockObject(LTGRAY_BRUSH));
		}
	return rct.IsRectEmpty();
}

void RemoveListRectRgn(CRgn& rgn, CWnd *sheet, CListCtrl& wnd, int item)
{
	CRect rect;
	if (wnd.GetItemRect(item, rect, LVIR_BOUNDS)) {
		sheet->ScreenToClient(rect);
		CRgn region;
		region.CreateRectRgnIndirect(rect);

		rgn.CombineRgn(&rgn, &region, RGN_DIFF);
		}
}

BOOL ListViewEraseBkgnd(CDC* pDC, CWnd *parent, CListCtrl& list)
{
	CRect rct;
	parent->GetClientRect(rct);
	
	if (!rct.IsRectEmpty()) {
		CRgn rgn;
		rgn.CreateRectRgnIndirect(rct);

		for (int top = 0; top < list.GetCountPerPage(); top++)
			RemoveListRectRgn(rgn, parent, list, top + list.GetTopIndex());

		FillRgn(*pDC, rgn, (HBRUSH)GetStockObject(WHITE_BRUSH));
		}
	return rct.IsRectEmpty();
}

/////////////////////////////////////////////////////////////////////////////
// CX25VCListCtrl

CX25VCListCtrl::CX25VCListCtrl()
{
}

CX25VCListCtrl::~CX25VCListCtrl()
{
}


BEGIN_MESSAGE_MAP(CX25VCListCtrl, CListCtrl)
	//{{AFX_MSG_MAP(CX25VCListCtrl)
	ON_NOTIFY_REFLECT(NM_RCLICK, OnRclick)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CX25VCListCtrl message handlers

extern int DrawText(CDC *, LPCSTR, CRect);
extern LPSTR NumInBytes(char *buf, DWORD num);

void CX25VCListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	CTracePage *pPage = static_cast<CTracePage *>(GetParent());
	const CX25TraceData *td = (const CX25TraceData *)pPage->GetTraceData();
	CDC *dc = CDC::FromHandle(lpDrawItemStruct->hDC);
	CRect rect = CRect(lpDrawItemStruct->rcItem);
	DWORD ch = (DWORD)(lpDrawItemStruct->itemData);
	sX25VCStats *vc = NULL;

	if (td == NULL || !td->m_VCStats.Lookup(ch, vc))
		return;
	
	CStringArray Text;
	char buf[64];
	
	wsprintf(buf, "%10d", ch);
	Text.Add(buf);

	wsprintf(buf, "%d", vc->Frames[0]);
	Text.Add(buf);
	wsprintf(buf, "%d", vc->Frames[1]);
	Text.Add(buf);

	Text.Add(NumInBytes(buf, vc->Bytes[0]));
	Text.Add(NumInBytes(buf, vc->Bytes[1]));

	int LastWidth = 0;
	for (short i = 0; i < Text.GetSize(); i++) {
		rect.left += LastWidth;
		rect.right = rect.left + GetColumnWidth(i);
		LastWidth = rect.Width();
		
		DrawText(dc, Text[i], rect);
		}
}

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

	GetCursorPos(&pt);
	ScreenToClient(&pt);

	GetParent()->SendMessage(WM_RBUTTONUP, MK_RBUTTON, (pt.y << 16) + pt.x);	
	*pResult = 0;
}
