/*
*******************************************************************************
* 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.                                                                        *
*                                                                             *
*******************************************************************************

// PacketByteView.cpp : implementation file
//

Revision History:

   $History: PacketByteView.cpp $
 * 
 * *****************  Version 22  *****************
 * User: Mikez        Date: 7/11/97    Time: 5:02p
 * Branched in $/Components/Windows/NT/Sync/Build/Diag
 * 
 * *****************  Version 21  *****************
 * 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 "PacketByteView.h"
#include "PacketTreeView.h"

#define WM_COMMANDHELP      0x0365  // lResult = TRUE/FALSE,

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

/////////////////////////////////////////////////////////////////////////////
// CPacketByteView

IMPLEMENT_DYNCREATE(CPacketByteView, CScrollView)

CPacketByteView::CPacketByteView()
{
	m_Font = NULL;
	m_bActive = FALSE;
}

CPacketByteView::~CPacketByteView()
{
	delete m_Font;
}


BEGIN_MESSAGE_MAP(CPacketByteView, CScrollView)
	//{{AFX_MSG_MAP(CPacketByteView)
	ON_WM_LBUTTONDOWN()
	ON_WM_RBUTTONUP()
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPacketByteView drawing

void CPacketByteView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();

	// TODO: calculate the total size of this view
	if (m_Font == NULL)
	{
		SetScrollSizes(MM_TEXT, CSize(0, 0));

		CDC *pDC = GetDC();

		m_Font = new CFont;
		m_Font->CreatePointFont(90, "Courier", pDC);

		SetFont(m_Font);
		pDC->SelectObject(m_Font);

		TEXTMETRIC tm;
		pDC->GetTextMetrics(&tm);
		m_Width = tm.tmAveCharWidth;
		m_Height = tm.tmHeight;

		ReleaseDC(pDC);

		m_HighlightColor = (COLORREF)GetSysColor(COLOR_HIGHLIGHT);
		m_WindowColor = (COLORREF)GetSysColor(COLOR_WINDOW);
		m_TextColor = (COLORREF)GetSysColor(COLOR_WINDOWTEXT);
	}
}

void CPacketByteView::SwapBkText(CDC *dc, BOOL& mode)
{
	mode = !mode;

	if (mode) {
		dc->SetBkColor(m_bActive ? m_HighlightColor : PALETTERGB(192,192,192));
		dc->SetTextColor(m_bActive ? m_WindowColor : m_TextColor);
		}
	else {
		dc->SetTextColor(m_TextColor);
		dc->SetBkColor(m_WindowColor);
		}
}

void CPacketByteView::SizeText()
{
	GetClientRect(m_Size);

	m_Size.right = m_Size.left + m_Width * 73;
	m_Size.bottom = m_Size.top + m_Height * (m_Text.GetLength() + 2) / 75;

	SetScrollSizes(MM_TEXT, m_Size.Size(), CSize(m_Width, m_Height), CSize(m_Width, m_Height));
}

void CPacketByteView::OnDraw(CDC* pDC)
{
	BOOL active = GetParentFrame()->GetActiveView() == this;
	CDocument* pDoc = GetDocument();
	// TODO: add draw code here
	pDC->SetTextAlign(TA_UPDATECP);
	pDC->SetBkColor(m_WindowColor);
	pDC->SetBkMode(OPAQUE);

	LPCSTR text = m_Text;
	BOOL mode = FALSE;
	const int addr = 8;
	const int llen = 75;

	CFont *font = pDC->SelectObject(m_Font);
	for (short i = 0; i < (m_Text.GetLength() + 2) / llen; i++) {
		int linePos = i * m_Height;
		int charPos = i * llen;
		int ByteStartPos = i * 16;

		if (pDC->RectVisible(CRect(0, linePos, llen * m_Width, linePos + m_Height))) {
			pDC->MoveTo(0, linePos);
			if (mode)
				SwapBkText(pDC, mode);
			pDC->ExtTextOut(0, 0, 0, NULL, &text[charPos], addr, NULL);

			for (int j = 0; j < 48; j+=3) {
				if ((ByteStartPos+j/3 >= selStart && ByteStartPos+j/3 < selEnd) ^ mode)
					SwapBkText(pDC, mode);

				if (j == 45 || ByteStartPos+j/3 == selEnd - 1) {
					pDC->ExtTextOut(0, 0, 0, NULL, &text[charPos+j+addr], 2, NULL);
					if (mode)
						SwapBkText(pDC, mode);
					pDC->ExtTextOut(0, 0, 0, NULL, &text[charPos+j+addr+2], 1, NULL);
					}
				else
					pDC->ExtTextOut(0, 0, 0, NULL, &text[charPos+j+addr], 3, NULL);
				}
			
			if (mode)
				SwapBkText(pDC, mode);
			pDC->ExtTextOut(0, 0, 0, NULL, &text[charPos+j+addr], 1, NULL);
			
			for (j = 49+addr; j < 49+addr+16; j++) {
				if ((ByteStartPos+(j-49-addr) >= selStart && ByteStartPos+(j-49-addr) < selEnd) ^ mode)
					SwapBkText(pDC, mode);
				pDC->ExtTextOut(0, 0, 0, NULL, &text[charPos+j], 1, NULL);
				}
			}
		}

	pDC->SelectObject(font);

	CRgn rgn;
	rgn.CreateRectRgnIndirect(m_Size);

	CRect wrect;
	GetClientRect(wrect);
	CRgn wrgn;
	wrgn.CreateRectRgnIndirect(wrect);

	wrgn.CombineRgn(&wrgn, &rgn, RGN_DIFF);

	::FillRgn(*pDC, wrgn, (HBRUSH)GetStockObject(WHITE_BRUSH));
}

/////////////////////////////////////////////////////////////////////////////
// CPacketByteView diagnostics

#ifdef _DEBUG
void CPacketByteView::AssertValid() const
{
	CScrollView::AssertValid();
}

void CPacketByteView::Dump(CDumpContext& dc) const
{
	CScrollView::Dump(dc);
}

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

/////////////////////////////////////////////////////////////////////////////
// CPacketByteView message handlers

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

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

	if (SameParentFrame) {
		if (lHint & uavFrameListSelChange) {
			if ((int)pHint > -1) {
				CFrame *frame = GetDocument()->GetTraceData()->GetTempFrame((DWORD)pHint);
				PrintHex(m_Text, frame->GetData(), frame->GetDataLen());
				}
			else
				m_Text = "";
			
			SizeText();
			RedrawWindow(NULL, NULL, RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOERASE);
			}
		if (lHint & uavFrameTreeSelChange) {
			DWORD sel = (DWORD)pHint;
			selStart = LOWORD(sel);
			selEnd = HIWORD(sel);

			int pos = (selStart / 16) * m_Height;
			if (sel > 0 && GetScrollPosition().y > pos)
				ScrollToPosition(CPoint(0, pos));
			RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_NOERASE);
			}
		}
}

void CPacketByteView::PrintHex(CString& str, PUCHAR bpos, int len)
{
	static char *hex = "0123456789ABCDEF";
	char *Line = str.GetBufferSetLength((len+15) / 16 * 75 + 1);

	for (short i = 0; i < len; i+=16) {
		if (i > 0) {
			*Line++ = '\r';
			*Line++ = '\n';
			}

		*Line++ = '0';
		*Line++ = 'x';
		for (int j = 12; j >= 0; j -= 4)
			*Line++ = hex[(i >> j) & 0xF];
		*Line++ = ' ';
		*Line++ = ' ';

		char *asc = Line + 32 + 16 + 1;

		for (j = 0; j < 16; j++) {
			if (i + j < len) {
				*Line++ = hex[*bpos >> 4];
				*Line++ = hex[*bpos & 0xF];

				*asc = isprint(*bpos) ? *bpos : '.';
				}
			else {
				*Line++ = ' ';
				*Line++ = ' ';
				*asc = ' ';
				}
			bpos++;
			asc++;
			*Line++ = ' ';
			}
		*Line++ = ' ';
		Line += 16;
		}
}

void CPacketByteView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	
	CScrollView::OnLButtonDown(nFlags, point);
	point += GetScrollPosition();

	CRect rect;
	GetClientRect(rect);

	int LineNum = (point.y - rect.top) / m_Height;

	int LineIndex = (point.x - rect.left) / m_Width;
	if (LineIndex >= 8 && LineIndex < 56)
		m_ByteIndex = (LineIndex - 8) / 3;

	if (LineIndex >= 57 && LineIndex < 73)
		m_ByteIndex = LineIndex - 57;
	m_ByteIndex += 16 * LineNum;

	m_MinSep = 0x7FFFFFFF;
	m_Found = NULL;

	CPacketTreeView *treeview = (CPacketTreeView *)((CSplitterWnd *)GetParent())->GetPane(1, 0);
	treeview->TraverseTree(&FindItemFunc, this);
	treeview->GetTreeCtrl().SelectItem(m_Found);
	SetFocus();
}

BOOL CPacketByteView::FindItemFunc(CTreeCtrl& DataTree, HTREEITEM item, LPVOID userData)
{
	CPacketByteView *THIS = static_cast<CPacketByteView *>(userData);

	DWORD_PTR sel = DataTree.GetItemData(item);
	int selStart = LOWORD(sel);
	int selEnd = HIWORD(sel);

	if (THIS->m_ByteIndex >= selStart && THIS->m_ByteIndex < selEnd && selEnd - selStart < THIS->m_MinSep) {
		THIS->m_MinSep = selEnd - selStart;
		THIS->m_Found = item;
		}

	return TRUE;
}

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

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

	RedrawWindow(NULL, NULL, RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOERASE);
}

void CPacketByteView::OnRButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	ClientToScreen(&point);
	GetParentFrame()->SendMessage(WM_RBUTTONUP, nFlags, (point.y << 16) + point.x);
}
