// Copyright (C) 2000
//          by the Massachusetts Institute of Technology
//
//    Export of this software from the United States of America may
//    require a specific license from the United States Government.  It
//    is the responsibility of any person or organization contemplating
//    export to obtain such a license before exporting.
//
// WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
// distribute this software and its documentation for any purpose and
// without fee is hereby granted, provided that the above copyright
// notice appear in all copies and that both that copyright notice and
// this permission notice appear in supporting documentation, and that
// the name of M.I.T. not be used in advertising or publicity pertaining
// to distribution of the software without specific, written prior
// permission.  M.I.T. makes no representations about the suitability of
// this software for any purpose.  It is provided "as is" without express
// or implied warranty.

// winsshView.cpp 
//	: additional implementation of the CWinsshView class

#include <mbstring.h>		 //for _mbslen

#include "stdafx.h"
#include "winssh.h"
#include "Errors.h"

#include "winsshDoc.h"
#include "winsshView.h"
#include "MainFrm.h"

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


//Functions that pastes all incoming data on the mainview
void CWinsshView::DisplayVtText(CString& strMessage)
{
	if (m_bFreshReconnection)
		OnInitialUpdate();

	pDoc = GetDocument();
	if (pDoc == NULL) return;
	int		iOriginalMessageLen;

	//new change
	int		iBufferIndex = 0;
	int		iTermCapOutLen;
	int		iScreenOutputIndex = 0;
	UCHAR*	uszMessageBuffer;

	memset(m_uszDisplayASCIILine, NULL, SSH_MAX_TERM_COLS);

	if (pDoc->m_pTC != NULL)
	{
		if (pDoc->m_pTC->GetRemainderLength() > 0) // there's a remainder from the last process
			strMessage = CString(pDoc->m_pTC->GetRemainderString()) + strMessage;

		iOriginalMessageLen = strMessage.GetLength();
		uszMessageBuffer = (UCHAR*) strMessage.GetBuffer(iOriginalMessageLen);
		uszMessageBuffer[iOriginalMessageLen] = '\0';
	
		iTermCapOutLen = pDoc->m_pTC->VtRecvProcess(uszMessageBuffer, iOriginalMessageLen );
#ifdef DEBUG_SSH
		Debug("CWinsshView::DisplayVtText() - Termcap length pre:%d, post:%d ",iOriginalMessageLen,iTermCapOutLen);
#endif

		for (iBufferIndex=0; iBufferIndex < iTermCapOutLen; iBufferIndex++)
		{
			if ((BYTE)uszMessageBuffer[iBufferIndex] == TC_CMDSIGNAL)
			{
				if (iScreenOutputIndex > 0)	// Output whatever is there
				{
					privateOutputToScreen(); //internally displays the content of m_uszDisplayASCIILine
					iScreenOutputIndex = 0;
					m_ulLastCommand = m_ulSecLastCommand = TC_ANSICHAR;
				}
				HandleTermCap();			//Call private TermCap interpretation function
			}
			else if (	((BYTE)uszMessageBuffer[iBufferIndex] == TC_CMDFILLER)  ||
						((BYTE)uszMessageBuffer[iBufferIndex] == TC_NULL)	)
			{ //do nothing
			}
			else								//ASCII chars goes here!
			{
				if (iScreenOutputIndex >= m_usTermX)
				{	//need to wrap to the next line!
					privateOutputToScreen();
					iScreenOutputIndex = 0;
					CursorDown();
					CursorTo(m_usCursorY,1);
					ClearToEOLN();
				}
				m_uszDisplayASCIILine[iScreenOutputIndex] = uszMessageBuffer[iBufferIndex];
				iScreenOutputIndex++;
				m_ulLastCommand = m_ulSecLastCommand = TC_ANSICHAR;
			}
		} // end for
		
		// Output whatever is there
		if (iScreenOutputIndex > 0)
		{
			privateOutputToScreen();
			m_ulLastCommand = m_ulSecLastCommand = TC_ANSICHAR;
		}

		//Check if Caret should be displayed
		if (pDoc->m_iAppState != APP_STATE_DISCONNECTED)
			DisplayCaret();
		else
		{
			DestroyCaret();
			m_bFreshReconnection = TRUE;
		}
		pDoc->m_bTermModify = TRUE;
	} //end if (pDoc->m_pTC != NULL)
	strMessage.ReleaseBuffer();
	strMessage.Empty();
}

/////////////////////////////////////////////////////////////////////
//
// Displaying
//
void CWinsshView::privateOutputToScreen() // Called *ONLY* by Message()
{
	pDoc = GetDocument();
	CDC*		pDC = GetDC();
	RECT		rectText;

	DestroyCaret();

	unsigned short usTextLen = (unsigned short) _mbslen( m_uszDisplayASCIILine );

	// puts it in DisplayBuffer first
	memcpy( &m_uszDisplayBuffer[((m_usDisplayBufferTop+m_usCursorY-1) % SSH_MAX_TERM_ROWS)][m_usCursorX-1],
			m_uszDisplayASCIILine, usTextLen);
	
	rectText.top = GetCursorCoordinateY();
	rectText.bottom = GetCursorCoordinateY() + m_usFontY;
	rectText.left = GetCursorCoordinateX();
	rectText.right = GetCursorCoordinateX() + (usTextLen*m_usFontX);

	pDC->ExtTextOut(rectText.left, rectText.top, ETO_CLIPPED | ETO_OPAQUE,
				&rectText, (char*)m_uszDisplayASCIILine, (int)usTextLen, m_iSpacingArray);

	m_usCursorX += usTextLen;

	//Zero out the line output buffer
	memset(m_uszDisplayASCIILine, NULL, usTextLen);
}

void CWinsshView::DisplayCaret()
{
	m_CursorPoint.x = GetCursorCoordinateX();
	m_CursorPoint.y = GetCursorCoordinateY();
	CreateSolidCaret(m_usFontX, m_usFontY);
	SetCaretPos(m_CursorPoint);
	ShowCaret();
}

void CWinsshView::ChangeAttrib()   // all the default font details
{
	CDC* pDC = GetDC();

	if (m_isAttribRevs)
	{
		pDC->SetTextColor(GetApp->m_crBack);
		pDC->SetBkColor(GetApp->m_crText);
	}else
	{
		pDC->SetBkColor(GetApp->m_crBack);
		pDC->SetTextColor(GetApp->m_crText);
	}

	if (m_isAttribUndl)
		GetApp->m_lf.lfUnderline = TRUE;
	else
		GetApp->m_lf.lfUnderline = FALSE;

	if (m_isAttribBold)
		GetApp->m_lf.lfWeight = 800;
	else
		GetApp->m_lf.lfWeight = 100;


	m_font.DeleteObject();
	m_font.CreateFontIndirect(&GetApp->m_lf);
	pDC->SelectObject(&m_font);
}

void CWinsshView::ChangeDisplayFont() 
{
	ChangeAttrib();

	CDC* pDC = GetDC();
	ABCFLOAT	myABC;

	//Getting width of Normal font
	pDC->GetCharABCWidths('a', 'a', &myABC);
	m_usFontY = (unsigned short) (-GetApp->m_lf.lfHeight);
	m_usFontX = (unsigned short) (myABC.abcfA + myABC.abcfB + myABC.abcfC);

	for (int i=0; i < SSH_MAX_TERM_COLS; i++)
		m_iSpacingArray[i] = m_usFontX;

	UpdateTermXY();

	DestroyCaret();
	//flood fill the background
	RECT	myClientRect;
	myClientRect.left = 0;
	myClientRect.top = 0;
	myClientRect.right = m_usWndX;
	myClientRect.bottom = m_usWndY;
	pDC->FillSolidRect(&myClientRect, GetApp->m_crBack);

	RepaintMissingArea(1, m_usTermY, 1, m_usTermX);

	DisplayCaret();

	if (pDoc != NULL)
		if (pDoc->m_iAppState != APP_STATE_DISCONNECTED)
			pDoc->m_bTermModify = TRUE;
}

void CWinsshView::RepaintMissingArea(	unsigned short TopRow,
										unsigned short BottomRow,
										unsigned short LeftCol,
										unsigned short RightCol)
{
	CDC* pDC = GetDC();
	RECT		rectText;
	int iIndexY;

	for (int i = TopRow; i <= BottomRow; i++)
	{
		for (int j = LeftCol; j <= RightCol; j++)
		{
			iIndexY	= (i-1+m_usDisplayBufferTop) % SSH_MAX_TERM_ROWS;

			if ( m_uszDisplayBuffer[iIndexY][j-1] != NULL )
			{
				rectText.top = (i-1) * m_usFontY;
				rectText.bottom = rectText.top + m_usFontY;
				rectText.left = (j-1) * m_usFontX;
				rectText.right = rectText.left + m_usFontX;

				pDC->ExtTextOut(rectText.left, rectText.top, ETO_CLIPPED | ETO_OPAQUE,
						&rectText, (char*)&m_uszDisplayBuffer[iIndexY][j-1], 1, m_iSpacingArray);
			}
		}
	}//end for
}

//////////////////////////////////////////////////////////////////
// Private Operation
//////////////////////////////////////////////////////////////////

void CWinsshView::HandleTermCap() // handles all termcap commands
{
	pDoc = GetDocument();
	if (pDoc->m_pTC == NULL) return;

	ULONG	ulCmd;				//VT command storage 
	int		iArg1, iArg2;
	pDoc->m_pTC->DequeueCommand(ulCmd, iArg1, iArg2);

	DestroyCaret();
	switch(ulCmd)
	{
	case TC_ANSICHAR:		/*do nothing*/							break;
	case TC_BELL:			MessageBeep(MB_OK);						break;
	case TC_BACKSPACE:		CursorLeft();							break;
	case TC_TAB:			CursorTab();							break;
	case TC_LINEFEED:
	case TC_VERTTAB:			CursorDown();
								CursorTo(m_usCursorY,1);			break;
	case TC_RETURN:				CursorTo(m_usCursorY,1);			break;
	case TC_CURSOR_UP:			CursorUp();							break;
	case TC_CURSOR_DOWN:		CursorDown();						break;
	case TC_CURSOR_RIGHT:		CursorRight();						break;
	case TC_CURSOR_HOME:		CursorTo(1,1);						break;
	case TC_CURSOR_UP_ARG:		CursorUp(iArg1);					break;
	case TC_CURSOR_DOWN_ARG:	CursorDown(iArg1);					break;
	case TC_CURSOR_RIGHT_ARG:	CursorRight(iArg1);					break;
	case TC_CURSOR_LEFT_ARG:	CursorLeft(iArg1);					break;
	case TC_CURSORTO_ARG_ARG:	CursorTo(iArg1, iArg2);				break;

	case TC_SAVECURSOR:
								m_usCursorSaveY	= m_usCursorY;
								m_usCursorSaveX	= m_usCursorX;		break;
	case TC_RESTORECURSOR:		CursorTo(m_usCursorSaveY, m_usCursorSaveX);	break;
	case TC_SCROLLFWD:												break;
	case TC_SCROLLREV:			ScrollReverse();					break;
	case TC_SCROLLTO_ARG_ARG:	SetScrollRegion(iArg1, iArg2);		break;
	case TC_CLR_AFTERCURSOR:	ClearAfterCursor();					break;
	case TC_CLR_TO_EOLN:		ClearToEOLN();						break;
	case TC_SETTAB:				SetTab();							break;
	case TC_CLEAR_TAB:												break;
	case TC_ATTR_BOLD:			m_isAttribBold = TRUE;
								ChangeAttrib();						break;
	case TC_ATTR_UNDERLINE:		m_isAttribUndl = TRUE;
								ChangeAttrib();						break;
	case TC_ATTR_BLINK:												break;
	case TC_ATTR_REVERSE:		m_isAttribRevs = TRUE;
								ChangeAttrib();						break;
	case TC_ATTR_OFF:
								m_isAttribBold = FALSE;
								m_isAttribUndl = FALSE;
								m_isAttribRevs = FALSE;
								ChangeAttrib();						break;
	case TC_DEVICE_STATUS:		ReplyDeviceStatus();				break;
	case TC_DEVICE_CURSOR:		ReplyDeviceCursor();				break;

// things i don't worry about at the moment at all
	case TC_ANSWERBACK:				break;
	case TC_FORMFEED:				break;
	case TC_KEYPAD_ON:				break;
	case TC_KEYPAD_OFF:				break;
	case TC_ALTCHARSET_ON:			break;
	case TC_ALTCHARSET_OFF:			break;
	case TC_INVOKEG1:				break;
	case TC_INVOKEG0:				break;
	case TC_CANCELESC:				break;
	case TC_END:					break;
	case TC_SENTBY_HOME:			break;
	case TC_SENTBY_INSERT:			break;
	case TC_SENTBY_DELETE:			break;
	case TC_SENTBY_PAGEUP:			break;
	case TC_SENTBY_PAGEDOWN:		break;
	case TC_SENTBY_UP:				break;
	case TC_SENTBY_DOWN:			break;
	case TC_SENTBY_RIGHT:			break;
	case TC_SENTBY_LEFT:			break;
	case TC_SENTBY_F0:				break;
	case TC_SENTBY_F1:				break;
	case TC_SENTBY_F2:				break;
	case TC_SENTBY_F3:				break;
	case TC_SENTBY_F4:				break;
	case TC_SENTBY_F5:				break;
	case TC_SENTBY_F6:				break;
	case TC_SENTBY_F7:				break;
	case TC_SENTBY_F8:				break;
	case TC_SENTBY_F9:				break;
	case TC_SENTBY_F10:				break;
	case TC_SENTBY_F11:				break;
	case TC_SENTBY_F12:				break;
	case TC_INIT_STR:				break;
	case TC_RESET_STR:				break;
	case TC_NULL:					break;
	case TC_UNKNOWN:				break;
	default:						break;
	}

	
#ifdef DEBUG_SSH		// debug message pendings
	switch (ulCmd)
	{
	case TC_ANSWERBACK:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= ANSWERBACK");		break;
	case TC_BELL:				Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= BELL");				break;
	case TC_BACKSPACE:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= BACKSPACE");		break;
	case TC_TAB:				Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= TAB");				break;
	case TC_LINEFEED:
	case TC_VERTTAB:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= LINEFEED");		break;
	case TC_FORMFEED:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= FORMFEED");		break;
	case TC_RETURN:				Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= RETURN");		break;
	case TC_INVOKEG1:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= INVOKEG1");		break;
	case TC_INVOKEG0:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= INVOKEG0");		break;
	case TC_CANCELESC:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= CANCELESC");		break;
	case TC_END:				Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= END");				break;
	case TC_ATTR_BOLD:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= ATTR_BOLD");		break;
	case TC_ATTR_UNDERLINE:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= ATTR_UNDERLINE");break;
	case TC_ATTR_BLINK:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= ATTR_BLINK");		break;
	case TC_ATTR_REVERSE:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= ATTR_REVERSE");	break;
	case TC_ATTR_OFF:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= ATTR_OFF");		break;
	case TC_KEYPAD_ON:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= KEYPAD_ON");		break;
	case TC_KEYPAD_OFF:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= KEYPAD_OFF");		break;
	case TC_ALTCHARSET_ON:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= ALTCHARSET_ON");	break;
	case TC_ALTCHARSET_OFF:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= ALTCHARSET_OFF");break;
	case TC_SETTAB:				Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SETTAB");			break;
	case TC_CLEAR_TAB:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= CLEAR_TAB");		break;
	case TC_CURSOR_UP:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= CUSOR_UP");		break;
	case TC_CURSOR_DOWN:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= CUSOR_DOWN");		break;
	case TC_CURSOR_RIGHT:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= CUSOR_RIGHT");	break;
	case TC_CURSOR_HOME:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= CUSOR_HOME");		break;
	case TC_CURSOR_UP_ARG:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= UP_ARG %d", iArg1);		break;
	case TC_CURSOR_DOWN_ARG:	Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= DOWN_ARG %d", iArg1);	break;
	case TC_CURSOR_RIGHT_ARG:	Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= RIGHT_ARG %d", iArg1);	break;
	case TC_CURSOR_LEFT_ARG:	Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= LEFT_ARG %d", iArg1);	break;
	case TC_CURSORTO_ARG_ARG:	
		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= CURSOR_TO_ARG_ARG %d %d",iArg1,iArg2);break;
	case TC_SAVECURSOR:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SAVECURSOR");		break;
	case TC_RESTORECURSOR:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= RESTORECURSOR");	break;
	case TC_SCROLLFWD:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SCROLLFWD");		break;
	case TC_SCROLLREV:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SCROLLREV");		break;
	case TC_SCROLLTO_ARG_ARG:	
		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SCROLLTO_ARG_ARG %d %d",iArg1,iArg2);	break;
	case TC_CLR_AFTERCURSOR:	Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= CLR_AFTERCURSOR");	break;
	case TC_CLR_TO_EOLN:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= CLR_TO_EOLN");	break;
	case TC_SENTBY_HOME:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_HOME");	break;
	case TC_SENTBY_INSERT:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_INSERT");	break;
	case TC_SENTBY_DELETE:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_DELETE");	break;
	case TC_SENTBY_PAGEUP:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_PAGEUP");	break;
	case TC_SENTBY_PAGEDOWN:	Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_PAGEDOWN");	break;
	case TC_SENTBY_UP:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_UP");		break;
	case TC_SENTBY_DOWN:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_DOWN");	break;
	case TC_SENTBY_RIGHT:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_RIGHT");	break;
	case TC_SENTBY_LEFT:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_LEFT");	break;
	case TC_SENTBY_F0:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_F0");		break;
	case TC_SENTBY_F1:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_F1");		break;
	case TC_SENTBY_F2:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_F2");		break;
	case TC_SENTBY_F3:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_F3");		break;
	case TC_SENTBY_F4:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_F4");		break;
	case TC_SENTBY_F5:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_F5");		break;
	case TC_SENTBY_F6:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_F6");		break;
	case TC_SENTBY_F7:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_F7");		break;
	case TC_SENTBY_F8:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_F8");		break;
	case TC_SENTBY_F9:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_F9");		break;
	case TC_SENTBY_F10:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_F10");		break;
	case TC_SENTBY_F11:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_F11");		break;
	case TC_SENTBY_F12:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= SENTBY_F12");		break;
	case TC_DEVICE_STATUS:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= DEVICE_STATUS");		break;
	case TC_DEVICE_CURSOR:		Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= DEVICE_CURSOR");		break;
	case TC_INIT_STR:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= INIT_STR");		break;
	case TC_RESET_STR:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= RESET_STR");		break;
	case TC_NULL:				Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= NULL");				break;
	case TC_UNKNOWN:			Debug("CWinsshView::HandleTermCap()-pDoc->TermCap= UNKNOWN");			break;
	default:						break;
	}
#endif  // end debug message postings

	m_ulSecLastCommand = m_ulLastCommand;
	m_ulLastCommand = ulCmd;
	return;
}


////////////////////////////////////////////////////////////////////////////////////////
// Cursor Movement functions

void CWinsshView::CursorTo(int Row, int Col)  // VT terminal coordinates
{
	if (Row <= 1)			Row = 1;
	if (Row > m_usTermY)	Row = m_usTermY;
	if (Col <= 1)			Col = 1;
	if (Col	> m_usTermX)	Col = m_usTermX;

	m_usCursorY = Row;
	m_usCursorX = Col;
	return;
}

void CWinsshView::CursorLeft(int Cols)
{
	if ( (m_usCursorX-Cols) < 1 )
		m_usCursorX = 1;
	else
		m_usCursorX = m_usCursorX - Cols;
	return;	
}

void CWinsshView::CursorRight(int Cols)
{
	if ( (m_usCursorX+Cols) > m_usTermX )
		m_usCursorX = m_usTermX;
	else
		m_usCursorX += Cols;
	return;	
}

void CWinsshView::CursorDown(int Rows)
{
	int		i;		//loop counter
	unsigned short usLinesToScroll;
	RECT	rectScroll;	//rectangle space for scrolling

	if ((m_usTermY == m_usScrollRegionBottom) && (m_usScrollRegionTop == 1)) //if no scrolling region is set
	{
		if (m_usCursorY == m_usTermY) //bottom line
		{
			ScrollWindow(0, -Rows*m_usFontY, NULL, NULL);

			m_usDisplayBufferTop = (m_usDisplayBufferTop+Rows) % SSH_MAX_TERM_ROWS;
			for (i=0; i < Rows; i++)
				memset( m_uszDisplayBuffer[ (m_usDisplayBufferTop+i) % SSH_MAX_TERM_ROWS ], NULL, SSH_MAX_TERM_COLS);

		}
		else if ( (m_usCursorY+Rows) > m_usTermY) //need to scroll *some* lines
		{
			usLinesToScroll = (m_usCursorY+Rows) - m_usTermY;
			m_usCursorY = m_usTermY;	//move cursor position to bottom line
			ScrollWindow(0, -usLinesToScroll*m_usFontY, NULL, NULL);
			
			//updates buffer index
			m_usDisplayBufferTop = (m_usDisplayBufferTop+usLinesToScroll) % SSH_MAX_TERM_ROWS;
			for (i=0; i < usLinesToScroll; i++)
				memset( m_uszDisplayBuffer[ (m_usDisplayBufferTop+i) % SSH_MAX_TERM_ROWS ], NULL, SSH_MAX_TERM_COLS);
		}
		else	// no scrolling needed
		{
			m_usCursorY += Rows;
		}
	}
	else //there *is* a scrolling region set
	{
		unsigned short usBufferDest, usBufferSrc;

		if (m_usCursorY == m_usScrollRegionBottom) // if at bottom of scrolling region
		{
			rectScroll.top	= (m_usScrollRegionTop +Rows -1) * m_usFontY;
			rectScroll.bottom = m_usScrollRegionBottom * m_usFontY;
			rectScroll.left = 0;
			rectScroll.right = m_usWndX;

			ScrollWindow(0, -Rows*m_usFontY, &rectScroll, NULL);

			//update display buffer
			for (i = 0; i < (m_usScrollRegionBottom - m_usScrollRegionTop + 1 - Rows); i++)
			{
				usBufferDest	= (m_usDisplayBufferTop+m_usScrollRegionTop-1+i) % SSH_MAX_TERM_ROWS;
				usBufferSrc		= (usBufferDest + Rows) % SSH_MAX_TERM_ROWS;
				memcpy(m_uszDisplayBuffer[usBufferDest], m_uszDisplayBuffer[usBufferSrc], SSH_MAX_TERM_COLS);
			}
			for (i = 0; i < Rows; i++)
			{
				usBufferDest = (m_usDisplayBufferTop + m_usScrollRegionBottom - Rows + i) % SSH_MAX_TERM_ROWS;
				memset( m_uszDisplayBuffer[usBufferDest], NULL, SSH_MAX_TERM_COLS);
			}
		}
		else if ( (m_usCursorY+Rows) > m_usScrollRegionBottom) //need to scroll *some* lines
		{
			usLinesToScroll = (m_usCursorY+Rows) - m_usScrollRegionBottom;
			m_usCursorY = m_usScrollRegionBottom;

			rectScroll.top = (m_usScrollRegionTop +usLinesToScroll -1) * m_usFontY;
			rectScroll.bottom = m_usScrollRegionBottom * m_usFontY;
			rectScroll.left = 0;
			rectScroll.right = m_usWndX;

			ScrollWindow(0, -usLinesToScroll*m_usFontY, &rectScroll, NULL);

			//update display buffer
			for (i = 0; i < (m_usScrollRegionBottom - m_usScrollRegionTop + 1 - usLinesToScroll); i++)
			{
				usBufferDest	= (m_usDisplayBufferTop+m_usScrollRegionTop-1+i) % SSH_MAX_TERM_ROWS;
				usBufferSrc		= (usBufferDest + Rows) % SSH_MAX_TERM_ROWS;
				memcpy(m_uszDisplayBuffer[usBufferDest], m_uszDisplayBuffer[usBufferSrc], SSH_MAX_TERM_COLS);
			}
			for (i = 0; i < usLinesToScroll; i++)
			{
				usBufferDest	= (m_usDisplayBufferTop + m_usScrollRegionBottom - usLinesToScroll + i) % SSH_MAX_TERM_ROWS;
				memset( m_uszDisplayBuffer[usBufferDest], NULL, SSH_MAX_TERM_COLS);
			}
		}
		else
		{
			m_usCursorY += Rows;
		}
	}// end if ((m_usTermY == m_usScrollRegionBottom) && (m_usScrollRegionTop == 1))

	UpdateWindow();
	return;	
}

void CWinsshView::CursorUp(int Rows)
{
	if ( (m_usCursorY-Rows) < 1 ) 
		m_usCursorY = 1;
	else
		m_usCursorY = m_usCursorY - Rows;
	return;	
}

void CWinsshView::CursorTab()
{
	unsigned short usSpacesToTabStop = 0;
	if (GetApp->m_usTabStop != 0) //divide by 0 protection
	{
		while( ((usSpacesToTabStop+m_usCursorX -1) % GetApp->m_usTabStop) != 0)
			usSpacesToTabStop++;
		if ( (( m_usCursorX -1) % GetApp->m_usTabStop) == 0)//special case: if cursor was sitting right on a tab stop
			usSpacesToTabStop += GetApp->m_usTabStop;

		memset(m_uszDisplayASCIILine, ' ', usSpacesToTabStop);

		privateOutputToScreen();
	}
}

void CWinsshView::ClearAfterCursor()
{
	ClearToEOLN();

	CDC*		pDC = GetDC();
	RECT		rectClr;
	
	rectClr.top = GetCursorCoordinateY() + m_usFontY;
	rectClr.bottom = m_usWndY;
	rectClr.left = 1;
	rectClr.right = m_usWndX;

	if (m_isAttribRevs)
		pDC->FillSolidRect(&rectClr, GetApp->m_crText);
	else
		pDC->FillSolidRect(&rectClr, GetApp->m_crBack);

	//Updates Display Buffer
	for (int i = m_usDisplayBufferTop+m_usCursorY; i < m_usDisplayBufferTop+m_usTermY; i++)
		memset( m_uszDisplayBuffer[ i % SSH_MAX_TERM_ROWS ], NULL, SSH_MAX_TERM_COLS);
}

void CWinsshView::ClearToEOLN()
{
	CDC*		pDC = GetDC();
	RECT		rectClr;
	
	rectClr.top = GetCursorCoordinateY();
	rectClr.bottom = GetCursorCoordinateY() + m_usFontY;
	rectClr.left = GetCursorCoordinateX();
	rectClr.right = GetCursorCoordinateX() + ((m_usTermX-m_usCursorX)*m_usFontX);

	if (m_isAttribRevs)
		pDC->FillSolidRect(&rectClr, GetApp->m_crText);
	else
		pDC->FillSolidRect(&rectClr, GetApp->m_crBack);

	//Updates Display Buffer
	memset( &m_uszDisplayBuffer[((m_usDisplayBufferTop+m_usCursorY-1) % SSH_MAX_TERM_ROWS)][m_usCursorX-1],
			NULL, SSH_MAX_TERM_COLS-(m_usCursorX-1) );
}

void CWinsshView::ScrollReverse()
{
	RECT	rectScroll;
	unsigned short usBufferDest, usBufferSrc;

	rectScroll.top		= (m_usScrollRegionTop-1) * m_usFontY;
	rectScroll.bottom	= (m_usScrollRegionBottom-1) * m_usFontY;
	rectScroll.left		= 0;
	rectScroll.right	= m_usWndX;

	ScrollWindow(0, m_usFontY, &rectScroll, NULL);

	//update display buffer
	for (int i = m_usScrollRegionBottom; i >= (m_usScrollRegionTop); i--)
	{
		usBufferDest	= (m_usDisplayBufferTop+i-1) % SSH_MAX_TERM_ROWS;
		usBufferSrc		= (usBufferDest-1) % SSH_MAX_TERM_ROWS;
		memcpy(m_uszDisplayBuffer[usBufferDest], m_uszDisplayBuffer[usBufferSrc], SSH_MAX_TERM_COLS);
	}
	memset( m_uszDisplayBuffer[((m_usDisplayBufferTop+m_usScrollRegionTop-1) % SSH_MAX_TERM_ROWS)], NULL,
			SSH_MAX_TERM_COLS);
}

void CWinsshView::SetScrollRegion(int Top, int Bottom)
{
	m_usScrollRegionTop = (unsigned short) Top;
	m_usScrollRegionBottom = (unsigned short) Bottom;
}

void CWinsshView::SetTab()
{
}
