/*  Project Tec3270

	 SUBSYSTEM:    Tec3270.exe (Tec3270 application)
	 FILE:         ALFFNvt.cpp
	 AUTHOR:       Alcindo Ferreira Filho

	 OVERVIEW:

    ALFFNvt class implementation. It is used to manage the basic terminal
    (Network Virtual Terminal - NVT) buffer and screen.

    COPYRIGHT:    © 1998-2007
                  Alcindo Ferreira Filho
                  <alcindo@inttec.com.br>

    LICENSE:      Tec3270_License (docs/Tec3270_License.txt)
*/
#include "alffnall.h"

//{{ALFFNvt Implementation}}
//
//////////////////////////////////////////////////////////
// ALFFNvt
// ==========
// Construction/Destruction handling.
ALFFNvt::ALFFNvt(ALFFConnData* cnnData, bool printer):
                       isPrinter(printer),
							  undoBuffer(MAXUNDOOPER,0,MAXUNDOOPER/4),
							  scrField()
{
  connData   = cnnData;

  /* Initialize the NVT character buffer  */
  charBuffer = new unsigned char[DEFAULTNVTBUFSIZE];

  /*
	* Reset All NVT Terminal Controls
	*/
  cursorPos = 0;
  beginKeybModPos = endKeybModPos =
  unprotBeginPos = 0;
  unprotEndPos = sizeNVTBuf;
  lastBufPosMod = lastBufPosRecv =
  currScrBegin = currentBufPos = 0;
  selStartPos = selEndPos = 0;
  nNVTState = nNVT_IDLE;
  bufferInitialized = false;
  keyboardRestore = true;
  lastAID = NOAIDGEN;

  /* Default NVT Char Attributtes */
  defaultHighLight = EHDEFAULT;
  defaultCharSet = CSDEFAULT;
  defaultTransparency = TPDEFAULT;
  defaultValidation = FVNONE;
  defaultOutLining =  FONOOUTLINE;

  /* Reset Undo Buffer Controls */
  ResetUndo();
}

ALFFNvt::~ALFFNvt()
{
  if (charBuffer)
	 delete[] charBuffer;
}

void
ALFFNvt::ClearBuf()
{
 if (bufferInitialized)
  {
	unsigned int i;
	currChar = NULL;

	/* Clear All Char on Char Buffer */
	for (i=0;i<sizeNVTBuf;i++)
	 {
	  charBuffer[i] = currChar;
	 }

	/*
	* Reset NVT Terminal Controls to Initial State
	*/
	cursorPos = 0;
	lastBufPosMod = lastBufPosRecv = currScrBegin = currentBufPos = 0;
	selStartPos = selEndPos = unprotBeginPos = 0;
   unprotEndPos = sizeNVTBuf;
  }
}

void
ALFFNvt::InitBuf(const int defNumLines, const int defLineSize,
								 const int altNumLines, const int altLineSize,
								 const bool colorTerm, const bool extendedAttr)
{
 /*
  * Initialize NVT Terminal Buffer
  */
 scrLineSize = defLineSize;
 scrNumLines = defNumLines;
 defScrLineSize = defLineSize;
 defScrNumLines = defNumLines;
 altScrLineSize = altLineSize;
 altScrNumLines = altNumLines;
 sizeNVTBuf    = defLineSize*defNumLines;

 /* Hope that alternate screen is the greater !! */
 int maxSizeNVTBuf = altNumLines*altLineSize;

 /*
  * Initialize NVT Terminal Buffer
  */
 replyMode = FDMODE;
 if (maxSizeNVTBuf != DEFAULTNVTBUFSIZE)
  {
	if (charBuffer)
	 delete [] charBuffer;
	charBuffer = new unsigned char[maxSizeNVTBuf];
  }

 /* Set Terminal Colors and Highlighting Characteristics */
 colorTerminal = colorTerm;
 extendedAttribute = extendedAttr;
 defaultCharColor = connData->scrCharColor;
 defaultBkgdColor = connData->scrBkgdColor;

 /*
  * Clear Screen Positions To All Binary Zeroes
  */
 bufferInitialized = true;
 ClearBuf();

 /*
  * Set NVT Terminal Ready To Receive Data
  */
 printBuffer    = false;
 keyboardRestore = false;
 alternateScreen = false;
 nNVTState = nNVT_IDLE;
}

void
ALFFNvt::Reset()
{
  /*
	* Reset NVT Terminal Controls
	*/
  selStartPos = selEndPos = 0;
  nNVTState = nNVT_IDLE;
  keyboardRestore = true;
  lastAID = NOAIDGEN;

  /* Reset Undo Buffer Controls */
  ResetUndo();
}

bool
ALFFNvt::IsTerminalOn()
{
 return bufferInitialized;
}

int
ALFFNvt::GetNVTBufSize()
{
 return sizeNVTBuf;
}

bool
ALFFNvt::IsUnprotField(const unsigned int pos)
{
 if ((pos >= unprotBeginPos)&&(pos < unprotEndPos))
	return true;
 else return false;
}

bool
ALFFNvt::AutomaticSkip(int pos)
{
 if (pos < sizeNVTBuf)
  return false;
 else return true;
}

unsigned int
ALFFNvt::NextFieldPos(const unsigned int fromPos,
										bool unProtFd, bool resetPos)
{
 bool endSearch = false;
 bool getUnprotectedField = unProtFd;
 unsigned int  searchPos = fromPos;
 while (!endSearch)
  {
	if (getUnprotectedField)
	 {
	  if (IsUnprotField(searchPos))
		  endSearch = true;
	  else
		{
		 searchPos = NextBufPos(searchPos);
		 if (searchPos == fromPos)
		  {
			/* In This Case the NVT buffer was wrapped */
			searchPos = 0;
			endSearch = true;
		  }
		}
	 }
	else
	 {
	  if (!AutomaticSkip(searchPos))
		{
		 searchPos = NextBufPos(searchPos);
		 if (searchPos == fromPos)
		  {
			/* In This Case the NVT buffer was wrapped */
			searchPos = 0;
			endSearch = true;
			}
		}
	  else getUnprotectedField = true;
	 }

	 if (resetPos)
		charBuffer[searchPos]=NULL;
  }

 return searchPos;
}

TPoint
ALFFNvt::GetCursorPos(UINT pos, bool convertToPoint)
{
 UINT position;
 TPoint cursorXY;
 if (convertToPoint)
	position = pos;
  else position = cursorPos;
 cursorXY.y = position / scrLineSize;
 cursorXY.x = position - (cursorXY.y*scrLineSize);
 return cursorXY;
}

TPoint
ALFFNvt::GetNextUnprotField(const int fromPos)
{
 return GetCursorPos(NextFieldPos(fromPos,UNPROTFD,NORESET),true);
}

bool
ALFFNvt::IsWordDelimiter(unsigned char Char)
{
 if ( (Char == ' ')
	 ||(Char == '.')
	 ||(Char == ',')
	 ||(Char == ';')
	 ||(Char == ':')
	 ||(Char == '!')
	 ||(Char == '?')
	 ||(Char == '+')
	 ||(Char == '-')
	 ||(Char == '*')
	 ||(Char == '/')
	 ||(Char == '=') )
	 return true;
  else return false;
}
TPoint
ALFFNvt::GetNextWord(const int fromPos)
{
 unsigned int  searchPos;
 unsigned char thisChar, beforeChar;
 searchPos = fromPos;
 bool endSearch = false;
 while (!endSearch)
  {
	if (searchPos < sizeNVTBuf-1)
	 {
		searchPos += 1;
		if (IsUnprotField(searchPos))
		 {
		  thisChar = charBuffer[searchPos];
		  beforeChar = charBuffer[searchPos-1];
		  if (searchPos < sizeNVTBuf-1)
			{
			 if (!IsWordDelimiter(thisChar)
				&& IsWordDelimiter(beforeChar) )
				{ endSearch = true; }
			}
			else
			 {
			  searchPos = fromPos;
			  endSearch = true;
			 }
		 }
	 }
	 else
		{
		 searchPos = fromPos;
		 endSearch = true;
		}
  }
 return GetCursorPos(searchPos,true);
}

TPoint
ALFFNvt::GetPrevUnprotField(const int fromPos)
{
 int initPos = fromPos;
 int sbPos = initPos-1;
 bool endLook = false;
 while (!endLook)
  {
	if (IsUnprotField(sbPos))
	 {
	  sbPos = (sbPos/scrLineSize)*scrLineSize;
	  endLook = true;
	 }
	 else
	 {
	  sbPos = PrevBufPos(sbPos);
	  if (sbPos == initPos)
		{
		 sbPos = 0;
		 endLook = true;
		}
	 }
  }
 return GetCursorPos(sbPos,true);
}

TPoint
ALFFNvt::GetPrevWord(const int fromPos)
{
 unsigned int  searchPos;
 unsigned char thisChar, beforeChar;
 searchPos = fromPos;
 bool endSearch = false;
 while (!endSearch)
  {
	if (searchPos > 0)
	 {
		searchPos -= 1;
		if (IsUnprotField(searchPos))
		 {
		  thisChar = charBuffer[searchPos];
		  beforeChar = charBuffer[searchPos-1];
		  if (searchPos > 0)
			{
			 if ( !IsWordDelimiter(thisChar)
				&& IsWordDelimiter(beforeChar) )
			  { endSearch = true; }
			}
			else
			 {
			  if (!IsWordDelimiter(thisChar))
				 {endSearch = true;}
			 }
		 }
	 }
	 else
		{
		 searchPos = fromPos;
		 endSearch = true;
		}
  }
 return GetCursorPos(searchPos,true);
}

UINT
ALFFNvt::EndOfField(const unsigned int fromPos)
{
 /* Under NVT Field Ends at Line End */
 return (((fromPos/scrLineSize)+1)*scrLineSize)-1;
}

TPoint
ALFFNvt::GetBeginOfField(const int fromPos)
{
 return GetCursorPos(GetLineBegin(fromPos),true);
}

TPoint
ALFFNvt::GetEndOfField(const int fromPos)
{
 UINT fdEndPos = EndOfField(fromPos);
 return GetCursorPos(fdEndPos,true);
}

/**************************************************************************
* IsWithinField: Verify if incremented position is within field           *
**-----------------------------------------------------------------------**
* Input   : Initial Position, that must between begin and end of field    *
*           Increment, that is number of positions ahead to be verified   *
*           if is within field.                                           *
* Process : Get current field begin an end positions, calculate the       *
*           incremented buffer position (ring buffer) and check if it is  *
*           within the range begin-end of field. Fields can begin on any  *
*           any position of the buffer an ends in positions after or      *
*           before begin (the buffer wraparound end to its begin like it  *
*           is a circular buffer).                                        *
* Returns : true if incremented position is within Field.                 *
*           false if incremented position is outside Field.               *
**************************************************************************/
bool
ALFFNvt::IsWithinField(const int initPos, const int increment)
{
 int fieldEnd = EndOfField(initPos);
 int fieldBegin = (initPos/scrLineSize)*scrLineSize;
 int incPos = initPos+increment-1;
 if (fieldBegin <= fieldEnd )
  {
	if (incPos <= fieldEnd)
	  return true;
	 else return false;
  }
 else
  {
	if (incPos < sizeNVTBuf)
		return true;
	else
	 {
		incPos -= sizeNVTBuf;
		if (incPos < fieldEnd)
		  return true;
		else return false;
	 }
  }
}

bool
ALFFNvt::IsEndOfField()
{
 int fieldEnd = unprotEndPos;
 int fieldBegin = unprotBeginPos;
 if (fieldBegin <= fieldEnd )
  {
	if (cursorPos < (fieldEnd-1))
	  return false;
	 else return true;
  }
  else
	{
	 if (cursorPos >= fieldBegin)
		return false;
	 else
	  {
		if (cursorPos < (fieldEnd-1))
			 return false;
		else return true;
	  }
	}
}

void
ALFFNvt::SetCursorPos(unsigned int pos)
{
 cursorPos = pos;
}

void
ALFFNvt::SetCursorPos(TPoint* pos)
{
 cursorPos = pos->y*scrLineSize + pos->x;
}

void
ALFFNvt::SoundAlarm()
{
 /* Sounds PC Speaker to simulate 3270 Alarm */
 if (connData->soundAlm)
	MessageBeep(MB_ICONEXCLAMATION);
 return;
}

bool
ALFFNvt::IsModifiedField(int cursorPos)
{
 return ((cursorPos > lastBufPosRecv)&&(cursorPos<=lastBufPosMod));
}


void
ALFFNvt::SetMDTBit(int cursorPos)
{
 lastBufPosMod=cursorPos;
}


void
ALFFNvt::ResetMDTBits()
{
 lastBufPosMod=0;
}


int
ALFFNvt::NextBufPos(int bufPos)
{
 if (bufPos < (currScrBegin+sizeNVTBuf-1))
  return(++bufPos);
 else return currScrBegin;
}

int
ALFFNvt::PrevBufPos(int bufPos)
{
 if (bufPos > currScrBegin)
  return(--bufPos);
 else return currScrBegin+sizeNVTBuf-1;
}

TColor
ALFFNvt::GetColor(int colorNVT)
{
 /* 3279 Color Values
  *
  * X'F0' -  Neutral           - (black on displays, white on printers)
  * X'F1' -  Blue              -
  * X'F2' -  Red               -
  * X'F3' -  Pink              -
  * X'F4' -  Green             -
  * X'F5' -  Turquoise         -
  * X'F6' -  Yellow            -
  * X'F7' -  Neutral           - (white on displays, black on printers)
  * X'F8' -  Black             -
  * X'F9' -  Deep Blue         -
  * X'FA' -  Orange            -
  * X'FB' -  Purple            -
  * X'FC' -  Pale Green        -
  * X'FD' -  Pale Turquoise    -
  * X'FE' -  Gray              -
  * X'FF' -  White             -
  */
 switch (colorNVT)
  {
	case  NEUTRAL         : return connData->neutral;
	case  BLUE            : return connData->blue;
	case  RED             : return connData->red;
	case  PINK            : return connData->pink;
	case  GREEN           : return connData->green;
	case  TURQUOISE       : return connData->turquoise;
	case  YELLOW          : return connData->yellow;
	case  INVERSENEUTRAL  : return connData->inverseNeutral;
	case  BLACK           : return connData->black;
	case  DEEPBLUE        : return connData->deepBlue;
	case  ORANGE          : return connData->orange;
	case  PURPLE          : return connData->purple;
	case  PALEGREEN       : return connData->paleGreen;
	case  PALETURQUOISE   : return connData->paleTurquoise;
	case  GRAY            : return connData->gray;
	case  WHITE           : return connData->white;
	default               : return connData->black;
  }
}

int
ALFFNvt::DataFromNetwork(LPALFFBUF pNetInBuf)
{
 register int streamSize;
 char* streamNVT;
 int saveStreamSize,retCode;

 if (!bufferInitialized)
  return BUFFERNOTAVAIL;

 /* Terminal Keyboard Must be Locked When Updating Buffer... */
 streamSize = pNetInBuf->ring_full_consecutive();
 lastStreamSize = saveStreamSize = streamSize;
 lastStreamNVT  = streamNVT = pNetInBuf->consume;

 endOfMessage    = false;       // WriteBuffer turns it on after receiving EM control char
 if (!isPrinter)
   keyboardRestore = true;     // Always restore keyboard after writing buffer (terminal only)
 else keyboardRestore = false;

 /* Get Current Char Attribute Information From 3270 Buffer */
 currentBufPos = cursorPos;
 currChar     =  charBuffer[currentBufPos];

 /*
  * Scan Data Received for parsing NVT controls
  */
 while ((streamSize) && (streamNVT[0] != EM))
 {
  switch (nNVTState)
	{
	/* NVT Idle: No operation being executed */
	case  nNVT_IDLE:
		{
		 nNVTState = nNVT_WRITE;
		 break;
		}   /* End of nNVT_IDLE State */

	/* NVT Write: Just write data to buffer .... */
	case  nNVT_WRITE:
		{
		 retCode = WriteBuffer(&streamNVT,streamSize);
		 if (retCode)
		  {
			pNetInBuf->ring_consumed(saveStreamSize);
			return retCode;
		  }
       if (isPrinter && endOfMessage)
        {
         pNetInBuf->ring_consumed(saveStreamSize-streamSize);
         return STARTPRINTING;
        }

		 nNVTState = nNVT_IDLE;
		 break;
		}
	} // end switch (n3270State)
 }  // end while (streamSize)

 /* Termination of NVT stream processing */
 if (streamSize > 0)
  {
   // We must leave the next message on buffer for further processing
   //  but excluding EndOfMessage Char (EM)
   saveStreamSize -= streamSize-1;
  }

 pNetInBuf->ring_consumed(saveStreamSize);
 pNetInBuf->ring_clear_mark();
 nNVTState = nNVT_IDLE;

 /*
  * Restore Keyboard Operation if WCC asks for ...
  */
 retCode = 0;
 if (!isPrinter)
  {
   if (keyboardRestore)
    {
    	keyboardRestore = false;
	   retCode |= KEYBOARDRESTORE;
    }
   else retCode |= NOKEYBOARDRESTORE;
  }
 return retCode;
}

UINT
ALFFNvt::GetLineBegin(const uint bufPos)
{
 return ((bufPos/scrLineSize) * scrLineSize);
}

void
ALFFNvt::IncCurrBufPos(const uint incPos, const int oper)
{
 int currLineBeg = (currentBufPos/scrLineSize)*scrLineSize;
 int scrSize = scrNumLines*scrLineSize;
 switch (oper)
  {
	case INCREMENT:
	 {
	  if ((currentBufPos+incPos) < sizeNVTBuf)
		currentBufPos += incPos;
	  else
		{
		 /* Should roll out first NVT Scr Line */
       int i=0;
		 for (i=0; i<(sizeNVTBuf-scrLineSize); i+=scrLineSize)
		  {
			memcpy(&charBuffer[i],&charBuffer[i+scrLineSize],scrLineSize);
		  }
		 memset(&charBuffer[i],NULL,scrLineSize);
		 currentBufPos = (currentBufPos-scrLineSize+incPos);
		}
	  break;
	 }
	case DECREMENT:
	 {
	  if ((currentBufPos-incPos) > currLineBeg)
		 currentBufPos -= incPos;
	  break;
	 }
	case BEGINLINE:
	 {
	  currentBufPos = currLineBeg;
	  break;
	 }
	case NEXTPAGE:
	 {
	  if (currentBufPos < (scrLineSize*scrNumLines))
		 currentBufPos = scrSize;
	  else currentBufPos = 0;
	  break;
	 }
	default:  break;
  }

 if (currentBufPos > scrSize)
	currScrBegin = (currentBufPos/scrLineSize)-scrNumLines;
 else currScrBegin = 0;
}

int
ALFFNvt::WriteBuffer(char** streamNVT, int& streamSize)
{
 register char byte;
 const int scrSize = (scrNumLines*scrLineSize);

 /* Get Current Char Information From NVT Buffer */
 currentBufPos = cursorPos;
 currChar     =  charBuffer[currentBufPos];

 /*
  * Scan Data Received for parsing NVT controls
  */
 while ((streamSize) && (*streamNVT[0] != EM))
 {
  byte = **streamNVT;  //HEX (**streamNVT);
  *streamNVT+=1; streamSize--;

  /* Writing NVT Buffer after receiving NetWork Data */
  switch (byte)
	{
	 case LF:   /* Line Feed Control:
					 * Moves cursor to the next screen line, keeping the
					 * same horizontal position
					 */
               if (isPrinter)
                {
                  charBuffer[currentBufPos] = byte;
					   IncCurrBufPos(1,INCREMENT);
                }
               else	IncCurrBufPos(scrLineSize,INCREMENT);
					break;

	 case CR:   /* Carriage Return
					 * Moves cursor to the first position of
					 * the current line
					 */
               if (isPrinter)
                {
                  charBuffer[currentBufPos] = byte;
					   IncCurrBufPos(1,INCREMENT);
                }
               else IncCurrBufPos(0,BEGINLINE);
					break;

	 case  BEL: /* Sound Alarm */
					SoundAlarm();
					break;

	 case  BS:  /* BackSpace */
               if (isPrinter)
                {
                  charBuffer[currentBufPos] = byte;
					   IncCurrBufPos(1,INCREMENT);
                }
               else	IncCurrBufPos(1,DECREMENT);
					break;

	 case  FF:  /* Form Feed Control:
					 * Moves cursor to the top of next screen line.
					 *   If current buffer position is on first page then
					 *   cursor will be positioned on first line of second
					 *   screen page, otherwise it will be positioned on
					 *   first line of first page.
					 */
               if (isPrinter)
                {
                  charBuffer[currentBufPos] = byte;
					   IncCurrBufPos(1,INCREMENT);
                }
               else	IncCurrBufPos(0,NEXTPAGE);
					break;

	 case   HT: /* Horizontal Tab: Ignore It on Terminal Buffer */
	 case   VT: /* Vertical   Tab: Ignore It on Terminal Buffer */
               if (isPrinter)
                {
                  charBuffer[currentBufPos] = byte;
					   IncCurrBufPos(1,INCREMENT);
                }

					break;

	 case  EM: /* End of Message/End of NVT Stream */
				  if (currentBufPos > scrSize)
					  currScrBegin = currentBufPos-scrSize;
				  cursorPos = currentBufPos;
				  unprotBeginPos = currentBufPos;
				  unprotEndPos   = sizeNVTBuf-1;
              endOfMessage = true;
              if (isPrinter)
               charBuffer[currentBufPos] = EPM;
				  return 0;

	 case NULL: /* NULL Character: Ignore It on Terminal Buffer */
               if (isPrinter)
                {
                 if (connData->printerNullAsSpace)
					    charBuffer[currentBufPos] = ASCIIBLANK;
                 else  charBuffer[currentBufPos] = byte;
					  IncCurrBufPos(1,INCREMENT);
					 }
               break;
               
	 default : /* Other Characters ... */
				  /* Insert character at currentBufPos
					* on screenBuffer
					*/
				  if (byte >= 0x20)
					{
					 charBuffer[currentBufPos] = byte;
					 IncCurrBufPos(1,INCREMENT);
					}
				  else return INVALIDORDER;
				  break;
	}
 }

 /*
  * Update Area of Terminal That User Can Change:
  * Unprot Field Begin at next NVT Screen Buffer Position after
  * last received from network and ends at last buffer position
  * If unprotBeginPos == unprotEndPos then no unprot fields exist.
  */
 unprotBeginPos = currentBufPos;
 unprotEndPos   = sizeNVTBuf-1;

 if (currentBufPos > scrSize)
	currScrBegin = currentBufPos-scrSize;

 cursorPos = currentBufPos;

 return 0;
}


unsigned char
ALFFNvt::GetAID(int command)
{
 switch(command)
  {
	case IDS_ENTERCOMMAND: return AIDENTER;
	case IDS_PF1         : return AIDPF1;
	case IDS_PF2         : return AIDPF2;
	case IDS_PF3         : return AIDPF3;
	case IDS_PF4         : return AIDPF4;
	case IDS_PF5         : return AIDPF5;
	case IDS_PF6         : return AIDPF6;
	case IDS_PF7         : return AIDPF7;
	case IDS_PF8         : return AIDPF8;
	case IDS_PF9         : return AIDPF9;
	case IDS_PF10        : return AIDPF10;
	case IDS_PF11        : return AIDPF11;
	case IDS_PF12        : return AIDPF12;
	case IDS_CLEAR       : return AIDCLEAR;
	default              : return NOAIDGEN;
  }
}

void
ALFFNvt::CommandKey(HWND hWindow, int command)
{
 lastAID = GetAID(command);
 ::SendMessage(hWindow,MSG_OUTPUT_NOTIFY,command,0);
 bufferUserModified = false;
 ResetUndo();
}

int
ALFFNvt::DataToNetwork(LPALFFBUF pNetOutBuf, int mode)
{
 int netCount, netOutMax, fromPos;
 char *netBufPtr;
 bool endSearch;

 /* Set Network Output Buffer Controls */
 netBufPtr = pNetOutBuf->supply;
 netOutMax = pNetOutBuf->ring_empty_consecutive();
 netCount = 0;

 /*
  * Set Inbound Text
  */
 switch (mode)
  {
	case MODIFIED : /* If Read Modified only the keyboard modified
						  * positions will be sent.
						  */
						 if (bufferUserModified)
						 {
						  fromPos = beginKeybModPos;
						  endSearch = false;
						  /* Insert just the current Line on Output Buffer */
						  while (!endSearch)
						  {
							if (fromPos <= endKeybModPos)
							{
							 *netBufPtr++ = charBuffer[fromPos];
							 netCount++;  fromPos++;
							 if (netCount > netOutMax)
							  {
								pNetOutBuf->ring_supplied(netOutMax-2);
								return IDS_RINGBUFFERFULL;
							  }
							}
							else endSearch = true;
						  }
						 }
						 *netBufPtr++ = CR;
						 netCount++;
						 break;

	default      : /* Nothing to do: ignore command */
						return IDS_INVALIDTONETMODE;
  }

 /* Update Buffer With Network Stream Data To Send */
 pNetOutBuf->ring_supplied(netCount);
 return DATASENT;
}

bool
ALFFNvt::SetExtendedAttr(Field& field)
{
 /* Copy field specific attributes not related to char attrs */
 field.fdBkgdTransparency = NULL;
 field.fdValidation = NULL;
 field.fdOutlining = NULL;

 /* Set Extended HighLight Attribute                  */
 field.fdEffects = NULL;

 /* Set Extended Pseudo Field Text and BackGround Colors */
 field.fdTextColor = connData->scrCharColor;
 field.fdBkgdColor = connData->scrBkgdColor;
 return true;
}

Field*
ALFFNvt::DataToScreen(int& fromPos, const int option,
								 const int suboption, const int code )
{
 char *fieldText;
 char *fieldTextBeg;
 int   initPos;
 char  posChar;

 /* Prepare Buffer searching end position */
 int endPos = sizeNVTBuf-1;
 if (scrField.fdText)
  {
	delete [] scrField.fdText;
	scrField.fdText = NULL;
  }

 /* Create Text Field To Store Buffer Characters */
 fieldTextBeg = fieldText = new char[sizeNVTBuf+1];
 memset(fieldText,NULL,sizeNVTBuf+1);

 /* Check For Getting only last buffer position updated */
 if (option == LASTUPDATED)
  {
	if (suboption == CONTINUE)
	 {
	  /* There is subfields that now are being picked up */
	  initPos = fromPos;
	 }
	else
	 {
	  /* In this case "fromPos" points to nothing.
		* The first position will be the last one that has been changed
		* (lastCharUpdated).		*/
	  initPos = lastCharUpdated;
	 }

	/* Get Field Properties */
	scrField.fdFormatted=false;         /* Must be an unformatted field */
	scrField.fdPosition.y = initPos / scrLineSize;
	scrField.fdPosition.x = initPos - (scrField.fdPosition.y*NVTLINESIZE);

	/* Getting char of last buffer position updated */
	if ((suboption != TOENDOFFIELD)
	  &&(suboption != CONTINUE) )
	 {
	  /* This option needs only the last buffer position updated */
	  posChar = charBuffer[lastCharUpdated];

	  if (code == UNDOTXT)
		{
		 if (posChar == NULL)
			posChar = ASCIINULL;
		 *fieldText++ = posChar;
		}
		else *fieldText++ = posChar;
	  *fieldText = NULL;
	  fromPos = -1;        //Indicates No More Fields Must Be Refreshed
	 }
	 else  //suboption == TOENDOFFIELD or CONTINUE //
	  {
		/* it needs to get field from last updated position to its end */
		endPos = EndOfField(initPos);
		bool endWhile = false;
		while (!endWhile)
		 {
		  posChar = charBuffer[initPos];
		  if (code == UNDOTXT)
			 {
			  if (posChar == NULL)
				posChar = ASCIINULL;
			  *fieldText++ = posChar;
			 }
			else *fieldText++ = posChar;
		  *fieldText = NULL;
		  if (initPos == endPos)
			{
			 endWhile = true;
			 fromPos = -1;
			}
		  else initPos = NextBufPos(initPos);
		 }
	  }
	int textLen = strlen(fieldTextBeg)+1;
	scrField.fdText = new char[textLen];
	strcpy(scrField.fdText,fieldTextBeg);
	delete [] fieldTextBeg;
	return &scrField;
  }

 else if (option == SELECTION)
  {
	/* In this case "fromPos" points to nothing except when "suboption"
	 *  is "CONTINUE".  In that case fromPos is the first position.
	 *  Else It's needed only the positions that are selected.
	 * It will improve Window Screen Updating performance too. */

	if (suboption == CONTINUE)
	  initPos = fromPos;
	else initPos = selStartPos;

	/* Getting Field Properties and Building high performance "Field" */
	scrField.fdFormatted=false;         /* Must be an unformatted field */
	scrField.fdPosition.y = initPos / scrLineSize;
	scrField.fdPosition.x = initPos - (scrField.fdPosition.y*scrLineSize);

	/* Getting char from initPos (selection start or fromPos) to selection end */
	endPos = PrevBufPos(selEndPos);
	bool endWhile = false;
	while (!endWhile)
	 {
	  posChar = charBuffer[initPos];
	  if (code == UNDOTXT)
		{
		 if (posChar == NULL)
		  posChar = ASCIINULL;
		 *fieldText++ = posChar;
		}
		else *fieldText++ = posChar;
	  *fieldText = NULL;

	  if (initPos < endPos)
		{
		 initPos = NextBufPos(initPos);
		 if ((suboption == JUSTTEXT) && !(initPos%scrLineSize))
		  {
			char CRLF[3] = {CR,LF,NULL};
			strcpy(fieldText,CRLF);
			fieldText+=2;
		  }
		 }
	  else
		 {
		  fromPos = -1;
		  endWhile = true;
		 }
	 }
	int textLen = strlen(fieldTextBeg)+1;
	scrField.fdText = new char[textLen];
	strcpy(scrField.fdText,fieldTextBeg);
	delete [] fieldTextBeg;
	return &scrField;
  }

 else if (option == REGULARFIELD)
  {
	/* Getting Regular Buffer Fields when it's not updating
	 * (in this option fromPos must be positive).
	 */
	bool endField = false;
	bool fieldInited = false;
	while (!endField)
	 {
	  if ((fromPos == endPos)
			|| (charBuffer[fromPos] == NULL))
		{
		 if (fieldInited)
		  {
			/* There is an field already inited */
			if (fromPos == endPos)
			 {
			  *fieldText++ = charBuffer[fromPos];
			  /* All Buffer Was searched: fromPos must have first field position */
			  fromPos = NextBufPos(fromPos);
			 }
			*fieldText = NULL;
			endField = true;
			fieldInited=false;
		  }
		 else
		  {
			/* There is no Field Inited */
			if (fromPos == endPos)
			 {
			  /* NVT buffer has no NULL Chars.
				  Field will be entire screen */
			  *fieldText = NULL;
			  endField = true;
			  fieldInited=false;
			  fromPos = NextBufPos(fromPos);
			 }
			/* No Field Inited So Try Next Buffer Pos */
			else fromPos = NextBufPos(fromPos);
		  }
		}
		else
		{
		 if (!fieldInited)
		  {
			fieldInited=true;
			scrField.fdFormatted=false;
			scrField.fdPosition.y = fromPos / scrLineSize;
			scrField.fdPosition.x = fromPos - (scrField.fdPosition.y*scrLineSize);
		  }
		 *fieldText++ = charBuffer[fromPos];
		 fromPos = NextBufPos(fromPos);
		}
	 } // while ...

	int textLen = strlen(fieldTextBeg)+1;
	scrField.fdText = new char[textLen];
	strcpy(scrField.fdText,fieldTextBeg);
	delete [] fieldTextBeg;

	return &scrField;
  }
 else return NULL; //invalid option//
}


int
ALFFNvt::DataToPrinter(ALFFPrinterBuffer* printerBuf)
{
 char  *fieldText = NULL;
 char  *fieldTextBeg = NULL;
 char  posChar;
 bool  fieldInited = false;
 bool  endField = false;
 bool  fdNodisp = false;

 /* Store All Screen Fields in an Printer Field */
 PrtField fdStore;
 bool endStoring = false;
 bool firsTime = true;
 int  pageNumber = 1;
 int  printFormatOffset = 0;
 int  fromBufPos = 0;
 int  endBufPos = sizeNVTBuf-1;

 // This method is available just for NVT Printers
 if (!isPrinter)
   return false;

 /* Create Text Field To Store Buffer Characters */
 int fieldLen = sizeNVTBuf+1;
 fieldTextBeg = new char[fieldLen];
 memset(fieldTextBeg,NULL,fieldLen);

 /* Set the correct page line size:
  *   if there is any value (not zero) in session parameters
  *      it must be used;
  *   else default buffer line size (set by wcc control) will be set.
  */
 int thisScrLineSize;
 if (connData->printerCharPerLine)
   thisScrLineSize = connData->printerCharPerLine;
 else thisScrLineSize = scrLineSize;

 int addRC = 0;              // ALFFPrinterBuffer StoreField Return Code

 try
  {
	while (!endStoring)
   {
    /*
     * Getting Print Fields from the position pointed by fromBufPos.
     * Generally the process is inited from buffer position 0, assuming that
     *  this position is where the first field begins even though there is no
     *   SF or SFE in this position. In this case it will be an "PSEUDOFIELD".
     */
    fieldInited = false;
    fieldText   = fieldTextBeg;
    *fieldText  = NULL;
    endField    = false;
    while (!endField)
	 {
	  if ((fromBufPos == 0)
      || (charBuffer[fromBufPos] == FF)
      || (charBuffer[fromBufPos] == CR)
      || (charBuffer[fromBufPos] == LF)
      || (charBuffer[fromBufPos] == BS)
      || (charBuffer[fromBufPos] == HT)
      || (charBuffer[fromBufPos] == VT)
      || (charBuffer[fromBufPos] == EPM)
      || (fromBufPos == endBufPos))
		{
		 if (fieldInited)
		  {
			if (fromBufPos == endBufPos)
			 {
			  /* All Buffer Was searched:
              No More fields available to print   */
			  posChar = charBuffer[fromBufPos];
			  *fieldText++ = posChar;  // NVTBUf is ASCII !! do not use ConvertToAscii(posChar);
			  endStoring = true;
			 }
         else if (charBuffer[fromBufPos] == EPM)
           endStoring = true;

         // Set Terminating Null of Field
			*fieldText = NULL;
         if (strlen(fieldTextBeg) > 0)
			  endField = true;
         else
          {
           fieldText = fieldTextBeg;
           *fieldText = NULL;
          }
			fieldInited=false;
		  }
		 else
		  {
         // Init this field
			fieldInited=true;

			posChar   = charBuffer[fromBufPos];

         /* Set Extended Field Attributes                 */
			SetExtendedAttr(fdStore);

         // Set Print Field Coordinates
         int actualPrintPos = fromBufPos + printFormatOffset;
         fdStore.fdPosition.y = actualPrintPos / thisScrLineSize;
			fdStore.fdPosition.x = actualPrintPos - (fdStore.fdPosition.y*thisScrLineSize);

         //  "ASCII FORMATTED PRINTING"
         fdStore.fdFormatted=false;
         if ( posChar < 0x20 )   // It is an control order = PSEUDOFIELD
          {
             // Print Format Controls "Pseudo Field": Adjust Printing Coordinates
             // We have assumed that valid print format control orders do not print,
             //    they just execute the "order"
             // Should be verified because Printer parms may alter this assumption
             switch (posChar)
              {
               case CR:  /* Negative Print Offset */
                         /* (fromBufPos+1) means that order will not be printed as space */
                         printFormatOffset = (fdStore.fdPosition.y*thisScrLineSize)-(fromBufPos+1);
                         fdStore.fdPosition.x = 0;
                         break;
               case LF:  /* Positive Print Offset */  // On NVT Buffer NL is LF (ASCII)
                         if (printFormatOffset == 0)
                           printFormatOffset = ((fdStore.fdPosition.y+1)*thisScrLineSize)-fromBufPos-1;
                         else printFormatOffset += thisScrLineSize-fdStore.fdPosition.x-1;

                         /* New horizontal offset will be 0 (new Line) */
                         fdStore.fdPosition.x = 0;
                         fdStore.fdPosition.y += 1;
                         if (fdStore.fdPosition.y > (connData->printerLinePerPage-1))
                           {
                            printFormatOffset = -(fromBufPos+1);
                            pageNumber += 1;
                           }
                         break;
               case FF:  /* New page - Inc page number */
                         fdStore.fdPosition.x = 0;
                         fdStore.fdPosition.y = 0;
                         /* On new page fromBufPos will be "zero" offset */
                         /* (fromBufPos+1) means that order will not be printed as space */
                         printFormatOffset = -(fromBufPos+1);
                         pageNumber += 1;
                         break;
               case BS:  /* Back space one column */
                         if (fdStore.fdPosition.x > 0)
                           fdStore.fdPosition.x--;
                           break;

               case HT:  /* Horizontal TAB set to this sessions's printer tab width  */
                         if ((fdStore.fdPosition.x + connData->printerTabWidth) < (connData->printerLinePerPage-1) )
                           fdStore.fdPosition.x += connData->printerTabWidth;
                         else
                          {
                           fdStore.fdPosition.y += 1;
                           fdStore.fdPosition.x = 0;
                           if (fdStore.fdPosition.y > (connData->printerLinePerPage-1))
                            {
                             fdStore.fdPosition.y = 0;
                             printFormatOffset = -(fromBufPos+1);
                             pageNumber += 1;
                            }
                           }
                         break;

               case VT:  /* Vertical TAB set to one line */
                           fdStore.fdPosition.y += 1;
                           if (fdStore.fdPosition.y > (connData->printerLinePerPage-1))
                            {
                             fdStore.fdPosition.y = 0;
                             printFormatOffset = -(fromBufPos+1);
                             pageNumber += 1;
                            }
                         break;

               // Something was wrong .....
               default:  fdStore.fdPosition.x = -1;
                         fdStore.fdPosition.y = -1;
                         break;
              }
          }
         else
          {
            // "First"  Field: No control order.  No coordinates adjust is needed.
            *fieldText++ = posChar;
          }

         /* Fill all printing control info */
         fdStore.scrLineSize   = scrLineSize;
		   fdStore.scrPrtBegLine = 0;
		   fdStore.scrPrtEndLine = connData->printerLinePerPage;
		   fdStore.scrNumber     = 1;
         fdStore.prtPageNumber = pageNumber;

			fromBufPos = NextBufPos(fromBufPos);
		  }
		}
		else
		{
       // It's sure that the field was inited because at least pos 0 is
       //    the first field (or pseudofield)
 	 	 posChar = charBuffer[fromBufPos];

       if ((posChar == NULL) && connData->printerNullAsSpace)
          posChar = ASCIIBLANK;
		 *fieldText++ = posChar;    // NVTBuf is always ASCII need not to "ConvertToAscii(posChar)";
		 fromBufPos = NextBufPos(fromBufPos);
		}

	 } // while endField

    int textLen = strlen(fieldTextBeg)+1;
    fdStore.fdText = new char[textLen];
    strcpy(fdStore.fdText,fieldTextBeg);
    addRC = printerBuf->StorePrtField(&fdStore);
    if (addRC)
     return addRC;

   } // while endStoring

   delete [] fieldTextBeg;
   return 0;
  } // try ....

 catch (xalloc)
  {
   delete [] fieldTextBeg;
	return -addRC;
  }
}


bool
ALFFNvt::FindNulls(const int initPos, int& firstNull, int& lastNull,
									const int count)
{
  /*
	* Searching a field (that must be unprotected) to find "count"
	* consecutive NULLs, before end of field.
	* If it is found return buffer position of first NULL,
	* else return -1.
	*/
  if (IsUnprotField(initPos))
	{
	 int pos, nullCount;
	 int endFor = NextBufPos(EndOfField(initPos));
	 bool nullFound;
	 for (pos = initPos;pos != endFor; pos=NextBufPos(pos))
	  {
		if (charBuffer[pos] == NULL)
		 {
		  firstNull = pos;
		  nullCount = count-1;
		  nullFound = true;
		  while (nullCount)
			{
			 pos = NextBufPos(pos);
			 if (pos != endFor)
			  {
				if (charBuffer[pos] != NULL)
				 {
				  nullFound = false;
				  nullCount = 0;
				 }
				else --nullCount;
			  }
			  else return false;
			}
		  if (nullFound)
			{
			 lastNull = pos;
			 return true;
			}
		 }
	  }
	}
  return false;
}

int
ALFFNvt::DataFromKeyboard(const char* buffer, int count, bool insertMode)
{
 int initPos = cursorPos;
 int rePaint = 0;
 if (IsUnprotField(cursorPos))
  {
	if (!insertMode)
	 {
	  if (!bufferUserModified)
		{
		 beginKeybModPos = endKeybModPos = initPos;
		 bufferUserModified = true;
		}
	  else
		{
		 if (initPos > endKeybModPos)
			endKeybModPos = initPos;
		 else if (initPos < beginKeybModPos)
				 beginKeybModPos = endKeybModPos = initPos;
		}
	  lastCharUpdated = initPos;
	  if (IsWithinField(initPos,count))
		{
		 SetSelection(initPos,initPos+count);
		 AddUndo(SELECTION);
		}
	  else  AddUndo(LASTUPDATED,TOENDOFFIELD);
	  while (count)
		{
		 charBuffer[cursorPos] = *buffer++;

		 SetMDTBit(cursorPos);
		 count--;
		 if (!IsEndOfField())
			cursorPos = NextBufPos(cursorPos);
		 else if (count)
			 return PROTECTEDFIELD;
		}
	 }
	else /* Terminal is in Insert Mode */
	 {
	  /* Try to Find "count" Nulls beyond cursor until Field End */
	  int firstNull = 0;
	  int lastNull = 0;
	  bool nullFound = FindNulls(initPos,firstNull,lastNull,count);
	  if (nullFound)
		{
		 if (!bufferUserModified)
		  {
			beginKeybModPos = initPos;
			bufferUserModified = true;
		  }
		 lastCharUpdated = initPos;
		 AddUndo(LASTUPDATED,TOENDOFFIELD);
		 SetMDTBit(cursorPos);
		 if (firstNull != initPos)
		  {
			/* Shift All Chars and Attrs To Right for "count" positions */
			int toPos = lastNull;
			int pos = PrevBufPos(firstNull);
			int endFor = PrevBufPos(initPos);
			for (pos; pos!=endFor; pos=PrevBufPos(pos))
			 {
			  charBuffer[toPos] = charBuffer[pos];
			  toPos = PrevBufPos(toPos);
			 }
		  }
		 while (count)
		  {
			charBuffer[cursorPos] = *buffer++;
			count--;
			if (!IsEndOfField())
			  cursorPos = NextBufPos(cursorPos);
			 else return PROTECTEDFIELD;  //Under Insertion we cannot go thru eof
		  }
		  rePaint = MUSTREPAINT;
		}
	  else return PROTECTEDFIELD;
	 }
  }
  else return PROTECTEDFIELD;

 // Update last modified position here, because we may have
 // more than one char on "buffer" (Paste text is an example)
 endKeybModPos = cursorPos - 1;
   
 return (initPos+rePaint);
}

int
ALFFNvt::DelBufferChar(const int option, const int pos)
{
 int retCode = PROTECTEDFIELD;
 int endField;
 int endPos;
 int buffPos;

 if (option == DELTOPOSITION)
  {
	if (IsUnprotField(cursorPos))
	 {
	  endField = EndOfField(cursorPos);
	  if (pos == ENDOFFIELD)
		{
		 /* Before changing 3270 Buffer Undo Field Must Be created */
		 bufferUserModified = true;
		 lastCharUpdated = cursorPos;
		 AddUndo(LASTUPDATED,TOENDOFFIELD);

		 /* It Implements Erase EOF Function */
		 endField = NextBufPos(endField);
		 for (buffPos=cursorPos; buffPos!=endField; buffPos=NextBufPos(buffPos))
		 {
		  charBuffer[buffPos] = NULL;
		 }
		}
	  else
		{
		  /* It implements Erase Selected String (and substitute erased
			* positions with remaining characteres of the field
			*/
		  if (endField >= cursorPos)
			{
			 if ((pos <= endField)
				&&(pos >= cursorPos))
				endPos = pos;        //To Position Not Included
			 else return PROTECTEDFIELD;
			}
		  else
			 {
			  if ((pos >= cursorPos)
				 ||(pos <= endField ) )
				 endPos = pos;      //To Position Not Included
				else return PROTECTEDFIELD;
			 }

		  /* Before changing NVT Buffer Undo Field Must Be created */
		  bufferUserModified = true;
		  lastCharUpdated = cursorPos;
		  AddUndo(LASTUPDATED,TOENDOFFIELD);

		  /* Move Char Buffer[endPos] to Char Buffer[pos] and transform
			  (endPos-pos) from the end of field to NULLs */
		  int fromPos = endPos;
		  endField = NextBufPos(endField);

		  /* Copy Remaining Chars to new position */
		  for (buffPos=cursorPos; fromPos!=endField; buffPos=NextBufPos(buffPos))
			{
			 charBuffer[buffPos] = charBuffer[fromPos];
			 fromPos = NextBufPos(fromPos);
			}

		  /* Set Final Removed Field Positions to NULLS */
		  for (buffPos=buffPos; buffPos!=endField; buffPos=NextBufPos(buffPos))
			{
			  charBuffer[buffPos] = NULL;
			}
		}

	  /* Set Modified Field Attribute Field On */
	  SetMDTBit(cursorPos);
	  retCode = GetLineBegin(cursorPos);
	 }
	 else return PROTECTEDFIELD;
  }
 else if (option == DELCHAR)
  {
	/* Del Char Must affect only the characters within cursor row */
	int endPos = ((cursorPos/scrLineSize)*scrLineSize)+scrLineSize-1;
        endField = EndOfField(cursorPos);
	if ((endField > endPos)
	 || (endField < cursorPos) )
	 endField = endPos;

	if (IsUnprotField(cursorPos))
	 {
	  /* Del Char Must affect only the characters within cursor row */
	  int endPos = ((cursorPos/scrLineSize)*scrLineSize)+scrLineSize-1;
	  endField = EndOfField(cursorPos);
	  if ((endField > endPos)
		|| (endField < cursorPos) )
		 endField = endPos;

	  /* Before changing 3270 Buffer Undo Field Must Be created */
	  bufferUserModified = true;
	  lastCharUpdated = cursorPos;
	  SetSelection(cursorPos,endPos);
	  AddUndo(SELECTION);
	  SetSelection(-1);   //Remove Selection

	  /* Set Field Modified Bit */
	  buffPos = cursorPos;
	  SetMDTBit(cursorPos);

	  bool endWhile = false;
	  while (!endWhile)
		{
		 if (buffPos != endField)
		  {
			int nextPos = NextBufPos(buffPos);
			charBuffer[buffPos] = charBuffer[nextPos];
			buffPos = NextBufPos(buffPos);
		  }
		  else
			{
			 charBuffer[buffPos] = NULL;
			 retCode = GetLineBegin(buffPos);
			 endWhile = true;
			}
		}
	 }
	 else return PROTECTEDFIELD;
  }
  else return PROTECTEDFIELD; //invalid option;

 return retCode;
}

int
ALFFNvt::DelWord()
{
 /*
  * This Method delete buffer characters from cursor Position to
  * end of word, not including the word delimiter before next word.
  * If the word doesn't end before line end, nothing is done.
  */
 int begLine;
 int begWord;
 int endWord;
 TPoint begWordPos;
 TPoint endWordPos;
 unsigned char charPos;

 if (!IsUnprotField(cursorPos))
  return PROTECTEDFIELD;

 /* Take word begin */
 charPos = charBuffer[cursorPos];
 if (IsWordDelimiter(charPos))
	 return WORDNOTFOUNDTHISLINE;
 begWord = cursorPos;
 begLine = begWord/scrLineSize;

 /* Take word end */
 endWordPos = GetNextWord(begWord);
 endWord = endWordPos.y*scrLineSize + endWordPos.x;
 endWord = PrevBufPos(endWord);

 /*
  * Verify if the word end was found: Char Before Begin of Next word
  * must be an word delimiter. If it is skip back one position to get
  * last buffer position to be deleted.
  */
 charPos = charBuffer[endWord];
 if (!IsWordDelimiter(charPos))
	 return WORDNOTFOUNDTHISLINE;
  else endWord = PrevBufPos(endWord);
 if (endWord <= begWord)
	 return WORDNOTFOUNDTHISLINE;

 /* Word must end in cursor line */
 endWordPos.y = endWord/scrLineSize;
 if (endWordPos.y != begLine)
	  return WORDNOTFOUNDTHISLINE;

 /* Del Word Found from cursor Position to the end of word */
 endWord = NextBufPos(endWord);   //To Position Not Included
 return DelBufferChar(DELTOPOSITION,endWord);
}


/* Search / Insert Methods-Procedures Adapted From TEdit OWL Object
 * Perform a search or replace operation based on information
 * in SearchData
 */
int
ALFFNvt::GetSelection(uint& startPos, uint& endPos) const
{
 if (selStartPos != selEndPos)
  {
	startPos = selStartPos;
	endPos   = selEndPos;
	if (selEndPos > selStartPos)
	  return (selEndPos-selStartPos);
	 else return (sizeNVTBuf-selStartPos+selEndPos);
  }
  else return 0;
}

bool
ALFFNvt::SetSelection(const TPoint startPos, const TPoint endPos)
{
 int bufStartPos;
 int bufEndPos;
 bufStartPos = startPos.y*scrLineSize+startPos.x;
 bufEndPos   = endPos.y*scrLineSize+endPos.x;
 return SetSelection(bufStartPos,bufEndPos);
}

bool
ALFFNvt::SetSelection(const int startPos, const int endPos)
{
 if (( startPos == 0)
  && (endPos == -1))
  {
	/* Do select entire buffer */
	selStartPos = 0;
	lastCharUpdated = selStartPos;
	selEndPos = sizeNVTBuf-1;
	cursorPos = sizeNVTBuf-1;
	return true;
  }
 else if (startPos == -1)
		{
		 /* Remove current selection */
		 lastCharUpdated = selStartPos;
		 selStartPos = cursorPos;
		 selEndPos = cursorPos;
		 return true;
		}
 else if (endPos <= sizeNVTBuf)
		{
		 /* Select supplied buffer range */
		 selStartPos = startPos;
		 selEndPos = endPos;
		 lastCharUpdated = selStartPos;
		 //if (selEndPos > selStartPos)
			//cursorPos = selEndPos;
		  //else cursorPos = selStartPos;
		 return true;
		}
 else return false;
}

//
// Similar to strstr(), but is case sensitive or insensitive, uses Windows
// string functions to work with different language drivers
//
static const char far*
strstrcd(const char far* str1, const char far* str2, bool caseSens)
{
  PRECONDITION(str1 && str2);
  int len2 = strlen(str2);
  char far* p = (char far*)str1;
  const char far* endp = str1 + strlen(str1) - len2 + 1;

  if (caseSens)
	 while (p < endp)
	  {
		char c = p[len2];            // must term p to match str2 len
		p[len2] = 0;                 // for strcmp to work.
		if (strcmp(p, str2) == 0)
		{
		  p[len2] = c;
		  return p;
		}
		p[len2] = c;
		p++;
	 }
  else
	 while (p < endp)
	 {
		char c = p[len2];
		p[len2] = 0;
		if (strcmpi(p, str2) == 0)
		{
		  p[len2] = c;
		  return p;
		}
		p[len2] = c;
		p++;
	 }
  return 0;
}

//
// Similar to strstrcd(), but searches backwards. Needs the length of str1
// to know where to start.
//
static const char far*
strrstrcd(const char far* str1, uint len1, const char far* str2,
			  bool caseSens)
{
  PRECONDITION(str1 && str2);
  int len2 = strlen(str2);
  char far* p = (char far*)(str1 + len1 - len2);

  if (caseSens)
	 while (p >= str1)
	 {
		char c = p[len2];            // must term p to match str2 len
		p[len2] = 0;                 // for strcmp to work.
		if (strcmp(p, str2) == 0)
		{
		  p[len2] = c;
		  return p;
		}
		p[len2] = c;
		p--;
	 }
  else
	 while (p >= str1)
	 {
		char c = p[len2];
		p[len2] = 0;
		if (strcmpi(p, str2) == 0)
		{
		  p[len2] = c;
		  return p;
		}
		p[len2] = c;
		p--;
	 }
  return 0;
}


//
// searchs for and selects the given text and returns the offset of the text
// or -1 if the text is not found
//
// if "startPos" = -1 then it is assumed that the start pos is the
// end/beginning (depending on direction) of the current selection
//
int
ALFFNvt::Search(uint startPos, const char far* text,
								bool caseSensitive, bool wholeWord,
                        bool up, bool select)
{
  int retCode = -1;

  if (!text || !text[0])
	 return retCode;

  if (startPos == (uint)-1)
  {
	 uint sBeg, sEnd;
	 if (!GetSelection(sBeg, sEnd))
		sBeg = sEnd = cursorPos;

	 startPos = up ? sBeg : sEnd;
  }
  int textLen = strlen(text);

  /* Get Access to the NVT text buffer and convert it to windows string */
  char far* buffer = new char[sizeNVTBuf+1];
  int i = 0;
  for (i = 0; i<sizeNVTBuf; i++)
	{
	 buffer[i] = charBuffer[i];
	}
  buffer[i] = NULL; //Should Terminate Buffer as Windows String;

  const char far* pos;
  for (;;)
  {
	 if (up)
		pos = strrstrcd(buffer, startPos, text, caseSensitive);
	 else
		pos = strstrcd(buffer+startPos, text, caseSensitive);

	 //
	 // If whole-word matching is enabled and we have a match so far, then make
	 // sure the match is on word boundaries.
	 //
	 if (wholeWord && pos)
	 {
		if (pos > buffer && isalnum(pos[-1]) || // Match is in preceding word
			 textLen < strlen(pos) && isalnum(pos[textLen]))
		{
		  startPos = (uint)(pos-buffer) + !up;
		  continue;  // Skip this match and keep searching
		}
	 }
	 break;  // Out of for loop
  }

  // If we've got a match, select that text, cleanup & return.
  //
  if (pos)
  {
	 uint sBeg = (uint)(pos - buffer);
    if (select)
	   SetSelection(sBeg, sBeg + textLen);
	 retCode = sBeg;
  }
  delete [] buffer;
  return retCode;
}

int
ALFFNvt::Replace(const char far* str)
{
 int saveCursor;
 /* Insert only operates if there is an Selection */
 uint startPos;
 uint endPos;  //end position is not included in selection range;
 int selLen = GetSelection(startPos,endPos);
 if (selLen)
  {
	if (strlen(str) > selLen)
	 {
	  int count = strlen(str)-selLen;
	  int firstNull = 0;
	  int lastNull = 0;
	  bool nullFound = FindNulls(endPos,firstNull,lastNull,count);
	  if (!nullFound)
		return PROTECTEDFIELD;
	 }

	/* Creating Undo Field To Permit Undo Replace Operation */
	bufferUserModified = true;
	lastCharUpdated = startPos;
	AddUndo(LASTUPDATED,TOENDOFFIELD);

	/* Save Current Cursor Position */
	saveCursor = cursorPos;

	/* Delete Selected Text From the Buffer */
	cursorPos = startPos;

	/* Just Do the Replace Operation */
	if (DelBufferChar(DELTOPOSITION,endPos)!= PROTECTEDFIELD ) //To Position is NOT Included
	 {
	  /* As it is an replace operation we not need intermediate result Undo */
	  RemoveUndoField();

	  /* As it is an Replace Operation Insert Mode MUST be forced */
	  int fdBegin = DataFromKeyboard(str,strlen(str),true);

	  if (fdBegin >= 0)
		{
		 /* As it is an replace operation we not need intermediate result Undo */
		 RemoveUndoField();

		 /* Restore Cursor Position */
		 cursorPos =  saveCursor;
		}
	  return fdBegin;
	 }
	 else
	  {
		/* As the 1st step has not completed, remove undo field from buffer*/
		RemoveUndoField();

		/* Restore Cursor Position */
		cursorPos =  saveCursor;

		/* Return Operation Not Done */
		return PROTECTEDFIELD;  //Protected Field//
	  }
  }
  else
	 {
	  /* Restore Cursor Position */
	  cursorPos =  saveCursor;

	  /* No Replace Operation Done Because There Is No Text Selected to Replace */
	  return PROTECTEDFIELD;  //NO Selection//
	 }
}

/**************************************************************************
* ExecuteUndo: Update NVT Char Buffer Undoing Last Update Done.          *
**-----------------------------------------------------------------------**
* Input   : None.                                                         *
* Process : Get undo Field from Undo Buffer, Update the NVT  Char Buffer  *
*           restoring text in position of the field,and remove the undo   *
*           field from the buffer.                                        *
* Returns : Field begin position for terminal screen updating or NULL     *
*           if Undo Field ins't available.                                *
**************************************************************************/
int
ALFFNvt::ExecuteUndo()
{
 Field* undoField;
 int fdBegin = 0;
 bool endUndo = false;
 while (!endUndo)
 {
  /* Get Next Undo Field */
  undoField = GetUndoField();
  if (undoField)
	{
	 /* Save Undo Field for Returning it */
	 scrField = *undoField;

	 /* Set Char buffer Position to be restored */
	 int buffPos = fdBegin = scrField.fdPosition.y*scrLineSize+
									 scrField.fdPosition.x;
	 lastCharUpdated = fdBegin;

	 /* Restore NVT Char buffer */
	 char* fieldText = scrField.fdText;
	 int textLen = strlen(fieldText);
	 for (int i = 0; i < textLen; i++)
	  {
		if (*fieldText == ASCIINULL)
		 {
		  charBuffer[buffPos] = NULL;
		  *fieldText++;
		 }
		else charBuffer[buffPos] = *fieldText++;
		buffPos = NextBufPos(buffPos);
	  }

	 /* Remove Undo Field From Undo Buffer */
	 RemoveUndoField();

	 if (scrField.cursorPos != UNDOCONTINUE)
	  {
		/* Restore NVT Buffer Cursor Position */
		currentBufPos = cursorPos = scrField.cursorPos;
		endUndo = true;
	  }
	}
  else return NULL;
 }
 return fdBegin+MUSTREPAINT;
}

/**************************************************************************
* AddUndo : Add to Undo Buffer a Field with Buffer Chars Prior to changes.*
**-----------------------------------------------------------------------**
* Input   : fromPos. (NVT  Buffer Reference of Begin of Changed Text      *
* Process : Build a Field with same characteristics of NVT  screen Field  *
*           containing part of it that will be changed and save it on the *
*           Undo Buffer for undoing the changes that will be made.        *
* Returns : true if operations run successfully.                          *
**************************************************************************/
bool
ALFFNvt::AddUndo(const int option, const int subOption)
{
 int fromPos = 0;
 int suboption = subOption;
 bool firstTime = true;
 Field* undoField;
 numUndo = undoBuffer.GetItemsInContainer();

 // Undo field must be in buffer Code Page //
 while (fromPos != -1)
  {
	undoField = DataToScreen(fromPos,option,suboption,UNDOTXT);
	if (firstTime)
	 {
	  undoField->cursorPos = cursorPos;
	  firstTime = false;
	  if (fromPos != -1)
		 suboption = CONTINUE;
	 }
	else undoField->cursorPos = UNDOCONTINUE;

	if (undoField)
	  undoBuffer.Add(*undoField);
	else return false;
  }
 return true;
}

/**************************************************************************
* GetUndoField: Gets First Field From Undo Buffer.                        *
**-----------------------------------------------------------------------**
* Input   : None.                                                         *
* Process : If Undo Buffer has items, first field available (at index 0)  *
*           will be returned, otherwise return NULL.                      *
* Returns : Field* if there is at least one item on Undo Buffer, else     *
*           NULL will be returned.                                        *
**************************************************************************/
Field*
ALFFNvt::GetUndoField()
{
 int undoItems = undoBuffer.GetItemsInContainer();
 if (undoItems)
  {
	return &undoBuffer[undoItems-1];
  }
 else return NULL;
}

/**************************************************************************
* RemoveUndoField: Remove the first Undo Buffer Field.                    *
**-----------------------------------------------------------------------**
* Input   : None.                                                         *
* Process : If Undo Buffer has items, first field available (at index 0)  *
*           will be removed.                                              *
* Returns : true if Undo Field removed successfully.                      *
*           false if there is no Fields on Undo Buffer.                   *
**************************************************************************/
bool
ALFFNvt::RemoveUndoField()
{
 int undoItems = undoBuffer.GetItemsInContainer();
 if (undoItems)
  {
	undoBuffer.RemoveEntry(undoItems-1);
	if (!undoBuffer.GetItemsInContainer())
		bufferUserModified = false;
	return true;
  }
  else return false;
}

/**************************************************************************
* ResetUndo: Empty the Undo Buffer.                                       *
**-----------------------------------------------------------------------**
* Input   : None.                                                         *
* Process : Flush entire Undo Buffer, and set 3270 Buffer Modified Flag   *
*           to false.                                                     *
* Returns : Nothing.                                                      *
**************************************************************************/
void
ALFFNvt::ResetUndo()
{
 undoBuffer.Flush();
 bufferUserModified = false;
}


