/*  Project Tec3270

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

	 OVERVIEW:

    ALFF3270 class implementation. It is used to manage the 3270 terminal
    screen buffer and 3270 printer buffer.

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

    LICENSE:      Tec3270_License (docs/Tec3270_License.txt)
*/
/*----------------------------------------------------------------------------
 Maintenance:
    ============
    Date				Change
    ======        ======
    12/12/2006		Added "break" at end of case QUERYREPLY on SendQueryReply
    					method. It's ausence caused incorrectly execution of next
                  case, creating "protocol violation".

*---------------------------------------------------------------------------*/

#include "alffnall.h"

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

  /* Printer Line Size Controls Initialization */
  wccLineSize = false;
  thisStreamLineSize = connData->printerCharPerLine;

  /* Initialize the 3270 character buffer  */
  charBuffer = new unsigned char[DEFAULT3270BUFSIZE];

  /*
  * Initialize 16 to 12 bit address and vice-versa tables
  */
  char tab1612P00[] = {0x40,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,
				  0xc9,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f};

  char tab1612P10[] = {0x50,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,
				  0xd9,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f};

  char tab1612P20[] = {0x60,0x61,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,
				  0xe9,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f};

  char tab1612P30[] = {0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
				  0xf9,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f};

 /*
  * Initialize 16 to 12 Bits Address Converter Table
  */
  convTab1612 = new char[256];
  memset(convTab1612,0xff,256);
  memcpy(convTab1612+0x00,tab1612P00,16);
  memcpy(convTab1612+0x10,tab1612P10,16);
  memcpy(convTab1612+0x20,tab1612P20,16);
  memcpy(convTab1612+0x30,tab1612P30,16);

  /*
	* Initialize ASCII/EBCDIC & EBCDIC/ASCII Tables
	*/

  /* EBCDIC Code Page 037 to ABNT 9611/ISO 8859 */
  tabEBCtoASC = new char[256];
  char wTabASC[] =
  {0x20,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x20,0x20,0x0E,0x0F,
	0x10,0x11,0x12,0x13,0x14,0x20,0x16,0x17,0x18,0x20,0x1A,0x1B,0x2A,0x19,0x3B,0x1F,
	0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x19,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x20,
	0x20,0xA0,0xE2,0xE4,0xE0,0xE1,0xE3,0xE5,0xE7,0xF1,0xA2,0x2E,0x3C,0x28,0x2B,0x7C,
	0x26,0xE9,0xEa,0xEB,0xE8,0xED,0xEE,0xEF,0xEC,0xDF,0x21,0x24,0x2A,0x29,0x3B,0xAC,
	0x2D,0x2F,0xC2,0xC4,0xC0,0xC1,0xC3,0xC5,0xC7,0xD1,0xA6,0x2C,0x25,0x5F,0x3E,0x3F,
	0xF8,0xC9,0xCA,0xCB,0xC8,0xCD,0xCE,0xCF,0xCC,0x60,0x3A,0x23,0x40,0x27,0x3D,0x22,
	0xD8,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0xAB,0xBB,0xF0,0xFD,0xFE,0xB1,
   0xB0,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,0xAA,0xBA,0xE6,0xB8,0xC6,
   //Euro: CP1140 (old CP037) Pos 0x9F corresponds to Pos 0x80 on Windows Occidental
   0x80,
   /////////////////////////////////////////////////////////////////////
	0xB5,0x7E,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0xA1,0xBF,0xD0,0x5B,0xDE,0xAE,
	0x5E,0xA3,0xA5,0xB7,0xA9,0xA7,0xB6,0xBC,0xBD,0xBE,0x5B,0x5D,0xAF,0x5D,0xB4,0xD7,
	0x7B,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0xAD,0xF4,0xF6,0xF2,0xF3,0xF5,
	0x7D,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0xB9,0xFB,0xFC,0xF9,0xFA,0xFF,
	0x5C,0xF7,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0xB2,0xD4,0xD6,0xD2,0xD3,0xD5,
	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0xB3,0xDB,0xDC,0xD9,0xDA,0x20};
  memcpy(tabEBCtoASC,wTabASC,256);


  /* ABNT 9611/ISO 8859 to EBCDIC Code Page 037 TABLE */
  tabASCtoEBC = new char[256];
  char wTabEBC[] =
  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
	0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d,0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61,
	0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f,
	0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,
	0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xad,0xe0,0xbd,0xb0,0x6d,
	0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96,
	0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0xff,
   //Euro: Windows Occidental Pos 0x80 corresponds to CP1140 (old CP037) Pos 0x9F
   0x9F,
   ///////////////////////////////////////////////////////////////////////////////
	     0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
	0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
	0x41,0xaa,0x4a,0xb1,0x9f,0xb2,0x6a,0xb5,0xbd,0xb4,0x9a,0x8a,0x5f,0xca,0xaf,0xbc,
	0x90,0x8f,0xea,0xfa,0xbe,0xa0,0xb6,0xb3,0x00,0xda,0x9b,0x8b,0xb7,0xb8,0xb9,0xab,
	0x64,0x65,0x62,0x66,0x63,0x67,0x9e,0x68,0x74,0x71,0x72,0x73,0x78,0x75,0x76,0x77,
	0xd0,0x69,0xed,0xee,0xeb,0xef,0xec,0xbf,0x80,0xfd,0xfe,0xfb,0xfc,0xdd,0xde,0x59,
	0x44,0x45,0x42,0x46,0x43,0x47,0x9c,0x48,0x54,0x51,0x52,0x53,0x58,0x55,0x56,0x57,
	0xf0,0x49,0xcd,0xce,0xcb,0xcf,0xcc,0xe1,0x70,0xdd,0xde,0xdb,0xdc,0xfd,0xfe,0xff};
  memcpy(tabASCtoEBC,wTabEBC,256);

  /* Query Reply List Codes For Read Partition Query List */
  queryReplyList = NULL;
  charModeAttrList = NULL; // Only valid when replyMode is CHARMODE

  /*
	* Reset All 3270 Terminal Controls
	*/
  ResetAll();
}

ALFF3270::~ALFF3270 ()
{
  if (charBuffer)
	 delete[] charBuffer;
  delete[] convTab1612;
  delete[] tabEBCtoASC;
  delete[] tabASCtoEBC;
  if (queryReplyList)
   delete [] queryReplyList;
  if (charModeAttrList)
   delete [] charModeAttrList;
}

char*
ALFF3270::GetTabEbcAsc()
{
 return tabEBCtoASC;
}

void
ALFF3270::GetDefaultCharAttr(ScreenPos& pAttribute, int fdBegin,
                                unsigned char fdAttr)
{
 pAttribute.posAttr = ATTRNULL;
 pAttribute.fieldAttr = fdAttr;
 pAttribute.extendedHighLight = defaultHighLight;
 pAttribute.charSet = defaultCharSet;
 pAttribute.charColor = DEFAULTCOLOR;
 pAttribute.bkgdColor = DEFAULTCOLOR;
 pAttribute.bgTransparency = defaultTransparency;
 pAttribute.fieldValidation = defaultValidation;
 pAttribute.fieldOutlining = defaultOutLining;
 pAttribute.fieldBeginAt = fdBegin;
}

void
ALFF3270::ClearBuf()
{
 if (bufferInitialized)
  {
	unsigned int i;
	currChar = NULL;
	int maxSize3270Buf = altScrNumLines*altScrLineSize;

	/* Get Default Char Attributes */
	GetDefaultCharAttr(currCharAttr);

	/* Clear All Char and Screen Attribute Buffers */
   int maxBufIdx = screenBuffer.Limit();
	for (i=0;i<maxSize3270Buf;i++)
	 {
	  charBuffer[i] = currChar;
     if (i <= maxBufIdx)
	    screenBuffer[i] = currCharAttr;
	 }

	/*
	* Reset 3270 Terminal Controls to Initial State
	*/
	cursorPos = 0;
	currentBufPos = 0;
	selStartPos = selEndPos = 0;
  }
}

void
ALFF3270::InitBuf(const short defNumLines, const short defLineSize,
							const short altNumLines, const short altLineSize,
							const bool colorTerm, const bool extendedAttr)
{
 /*
  * Initialize 3270 Terminal Buffer Size that depends
  * upon terminal model
  */
 scrLineSize = defLineSize;
 defScrLineSize = defLineSize;
 altScrLineSize = altLineSize;
 defScrNumLines = defNumLines;
 altScrNumLines = altNumLines;
 size3270Buf    = (int)defLineSize*defNumLines;

 /* Hope that alternate screen is the greater !! */
 int maxSize3270Buf = altScrNumLines*altScrLineSize;

 /*
  * Initialize 3270 Terminal Buffer
  */
 replyMode = FDMODE;

 if (maxSize3270Buf != DEFAULT3270BUFSIZE)
  {
	if (charBuffer)
	 delete [] charBuffer;
	charBuffer = new unsigned char[maxSize3270Buf];
	screenBuffer.Resize(maxSize3270Buf);
  }

 /* Set Terminal Colors and Highlighting Characteristics */
 colorTerminal = colorTerm;
 extendedAttribute = extendedAttr;
 defaultCharColor = DEFAULTCOLOR;
 defaultBkgdColor = DEFAULTCOLOR;

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

 /*
  * Set 3270 Terminal Ready To Receive Data
  */
 printBuffer    = false;
 keyboardRestore = false;
 alternateScreen = false;
 n3270State = n3270_IDLE;
}

void
ALFF3270::ResetAll()
{
  /*
	* Reset All 3270 Terminal Controls
	*/
  cursorPos = 0;
  currentBufPos = 0;
  selStartPos = selEndPos = 0;
  n3270State = n3270_IDLE;
  bufferInitialized = false;
  keyboardRestore = true;
  lastAID = NOAIDGEN;

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

  /* Undo Buffer Controls */
  ResetUndo();

  /* Reset Structured Field Query Reply */
  if (queryReplyList)
	{
	 delete [] queryReplyList;
	 queryReplyList = NULL;
	}
  if (charModeAttrList)
   {
    delete [] charModeAttrList;
    charModeAttrList = NULL;
   }
}


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

int
ALFF3270::Get3270BufSize()
{
 return size3270Buf;
}

void
ALFF3270::Addr16To12Bits(const unsigned short* addr16Bits, char * addr12Bits)
{

 unsigned char address16[3];
 unsigned char address12[3];
 unsigned short shiftAddr16;
 unsigned int byte;

 memset(address12,0,3);

 /*
  * Remember that an short is stored in memory using two bytes and
  *  it uppermost byte is the lowest order byte.
  */
 memcpy (address16, (char*)addr16Bits+1, 1);
 memcpy (address16+1, (char*)addr16Bits, 1);

 shiftAddr16 = *addr16Bits >> 6;

 memcpy (address12, &shiftAddr16, 1);  // Remember short Int Memory Disposition

 /*
  * Reset Firsts 2 Bits of Address 1st Byte
  */
 address12[0] &= 0x3F;
 memcpy (&address12[1], &address16[1], 1);

 /*
  * Reset Firsts 2 Bits of Address 2nd Byte
  */
 address12[1] &= 0x3F;

 /*
  * Translate 1st Byte of 12 Bit Address using 16 To 12 Bit Table Converter
  */
  byte = HEX (address12[0]);
  address12[0] = convTab1612[byte];


 /*
  * Translate 2nd Byte of 12 Bit Address using 16 To 12 Bit Table Converter
  */

  byte = HEX (address12[1]);
  address12[1] = convTab1612[byte];

  memcpy(addr12Bits,address12,2);

}

unsigned short
ALFF3270::Addr12To16Bits(const char* addr12Bits)
{
 unsigned short retAddr16;
 unsigned char address16[3];
 unsigned char address12[3];
 unsigned int byte;

 memset(address16,0,3);
 memcpy (address12,addr12Bits,2);

 /*
  * Translate 1st Byte of 12 Bit Address using 12 To 16 Bit Table Converter
  */

  /* Checking 14 or 16 Bit Addresses */
  if (!(address12[0] & 0xc0))
	{
	 /* This is an 14 Bit Address: Need No Translation */
	 retAddr16 = address12[1] + address12[0]*256;
	 return retAddr16;
	}

  /* 12Bit Address To 16 Bit Translation Process */
  //ignore the firsts two bits of the first byte
  address12[0] = address12[0] & 0x3f;

  //ignore the firsts two bits of the second byte
  address12[1] = address12[1] & 0x3f;

  address16[1] = address12[1];

  if (address12[0] & 0x01)
	 address16[1] |= 0x40;
  if (address12[0] & 0x02)
		 address16[1] |= 0x80;

  byte = HEX (address12[0]);
  byte = byte >> 2;
  address16[0] = byte;

  retAddr16 = address16[1] + address16[0]*256;

  if (retAddr16 > size3270Buf)
	 return INVALIDBUFADDR;
  else return retAddr16;
}

bool
ALFF3270::IsUnprotField(const unsigned int pos, bool checkSF)
{
 int fdBegin = screenBuffer[pos].fieldBeginAt;
 if (screenBuffer[fdBegin].fieldAttr & CHKPROTECTED)
	return false;
  else
	{
	 if (checkSF)
	  {
		if ((charBuffer[pos] == SF)
			||(charBuffer[pos] == SFE))
			  return false;
		 else return true;
	  }
	 else return true;
	}
}

bool
ALFF3270::AutomaticSkip(int pos)
{
 if (screenBuffer[pos].fieldAttr & NUMERIC)
  {
	if (screenBuffer[pos].fieldAttr & PROTECTED)
	  return true;
	else return false;
  }
 else return false;
}

unsigned int
ALFF3270::NextFieldPos(const unsigned int fromPos, bool unProtFd, bool resetPos)
{
 bool endSearch = false;
 bool getUnprotectedField = unProtFd;
 unsigned int  searchPos = fromPos;
 while (!endSearch)
  {
	if ((charBuffer[searchPos] == SF)
	  || (charBuffer[searchPos] == SFE))
	  {
		if (getUnprotectedField)
		 {
		  if (IsUnprotField(searchPos))
			{
			 /* Unprotected Field 1st Position MUST BE an normal char.
				 It cannot be another Start Field !!   */
			 searchPos = NextBufPos(searchPos);
			 if ((charBuffer[searchPos] != SF)
			  || (charBuffer[searchPos] != SFE))
				  endSearch = true;
			 else if (searchPos == fromPos)
					 {
					  /* In This Case the 3270 buffer is all filled with SFs */
					  searchPos = 0;
					  endSearch = true;
					 }
			}
			else
			{
			 searchPos = NextBufPos(searchPos);
			 if (searchPos == fromPos)
			  {
				/* In This Case the 3270 buffer is unformatted */
				searchPos = 0;
				endSearch = true;
			  }
			}
		 }
		 else
		 {
		  if (!AutomaticSkip(searchPos))
			{
			 /* Field 1st Position MUST BE an normal char.
				 It cannot be another Start Field !!   */
			 searchPos = NextBufPos(searchPos);
			 if ((charBuffer[searchPos] != SF)
				 || (charBuffer[searchPos] != SFE))
					 endSearch = true;
			 else if (searchPos == fromPos)
					 {
					  /* In This Case the 3270 buffer is all filled with SFs */
					  searchPos = 0;
					  endSearch = true;
					 }
			}
			else getUnprotectedField = true;
		 }
	  }
	 else
	  {
		if (resetPos)
		 {
		  charBuffer[searchPos]=NULL;
		  screenBuffer[searchPos].extendedHighLight = defaultHighLight;
		  screenBuffer[searchPos].charSet =  defaultCharSet;
		  screenBuffer[searchPos].charColor =  defaultCharColor;
		  screenBuffer[searchPos].bkgdColor =  defaultBkgdColor;
		  screenBuffer[searchPos].bgTransparency = defaultTransparency;
		 }
		searchPos = NextBufPos(searchPos);
		if (searchPos == fromPos)
		 {
		  searchPos = 0;
		  endSearch = true;
		 }
	  }
  }
 return searchPos;
}

TPoint
ALFF3270::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
ALFF3270::GetNextUnprotField(const int fromPos)
{
 return GetCursorPos(NextFieldPos(fromPos,UNPROTFD,NORESET),true);
}

bool
ALFF3270::IsWordDelimiter(unsigned char Char)
{
 if ( (Char == ' ')
// 	 ||(Char == SF )
// 	 ||(Char == SFE)
// SF and SFE are translated from EBC to ASC as EPM....
 	 ||(Char == EPM)
	 ||(Char == '.')
	 ||(Char == ',')
	 ||(Char == ';')
	 ||(Char == ':')
	 ||(Char == '!')
	 ||(Char == '?')
	 ||(Char == '+')
	 ||(Char == '-')
	 ||(Char == '*')
	 ||(Char == '/')
	 ||(Char == '=') )
	 return true;
  else return false;
}

TPoint
ALFF3270::GetEndOfWord(const int fromPos)
{
 unsigned int  searchPos;
 unsigned char thisChar, beforeChar;
 searchPos = fromPos;
 bool endSearch = false;
 while (!endSearch)
  {
	if (searchPos < size3270Buf-1)
	 {
		searchPos += 1;
		if (IsUnprotField(searchPos))
		 {
		  thisChar = ConvertToAscii(charBuffer[searchPos]);
		  beforeChar = ConvertToAscii(charBuffer[searchPos-1]);
		  if (searchPos < size3270Buf-1)
			{
			 if (IsWordDelimiter(thisChar)
				&& !IsWordDelimiter(beforeChar) )
				{ endSearch = true; }
			}
			else
			 {
			  searchPos = fromPos;
			  endSearch = true;
			 }
		 }
	 }
	 else
		{
		 searchPos = fromPos;
		 endSearch = true;
		}
  }
 return GetCursorPos(searchPos,true);
}

TPoint
ALFF3270::GetNextWord(const int fromPos)
{
 unsigned int  searchPos;
 unsigned char thisChar, beforeChar;
 searchPos = fromPos;
 bool endSearch = false;
 while (!endSearch)
  {
	if (searchPos < size3270Buf-1)
	 {
		searchPos += 1;
		if (IsUnprotField(searchPos))
		 {
		  thisChar = ConvertToAscii(charBuffer[searchPos]);
		  beforeChar = ConvertToAscii(charBuffer[searchPos-1]);
		  if (searchPos < size3270Buf-1)
			{
			 if (!IsWordDelimiter(thisChar)
				&& IsWordDelimiter(beforeChar) )
				{ endSearch = true; }
			}
			else
			 {
			  searchPos = fromPos;
			  endSearch = true;
			 }
		 }
	 }
	 else
		{
		 searchPos = fromPos;
		 endSearch = true;
		}
  }
 return GetCursorPos(searchPos,true);
}

int
ALFF3270::GetPrevAttrPos(const int fromPos)
{
 int initPos = NextBufPos(fromPos);
 int sbPos = fromPos;
 bool endLook = false;
 while (!endLook)
  {
	if ( (charBuffer[sbPos] == SF)
		||(charBuffer[sbPos] == SFE)
		||(screenBuffer[sbPos].posAttr == PSEUDOFIELD) )
	  endLook = true;
	else
	 {
	  sbPos = PrevBufPos(sbPos);
	  if (sbPos == initPos)
		{
		 sbPos = 0;
		 endLook = true;
		}
	 }
  }
 return sbPos;
}

TPoint
ALFF3270::GetPrevUnprotField(const int fromPos)
{
 int initPos = screenBuffer[fromPos].fieldBeginAt;
 int sbPos = initPos-1;
 bool endLook = false;
 while (!endLook)
  {
	if (IsUnprotField(sbPos))
	 {
	  sbPos = screenBuffer[sbPos].fieldBeginAt+1;
	  endLook = true;
	 }
	 else
	 {
	  sbPos = screenBuffer[sbPos].fieldBeginAt;
	  if (sbPos == initPos)
		{
		 sbPos = 0;
		 endLook = true;
		}
	  else sbPos = PrevBufPos(sbPos);
	 }
  }
 return GetCursorPos(sbPos,true);
}

TPoint
ALFF3270::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 = ConvertToAscii(charBuffer[searchPos]);
		  beforeChar = ConvertToAscii(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
ALFF3270::EndOfField(const unsigned int fromPos)
{
 unsigned int sbPos = fromPos;
 bool endLook = false;
 bool endBuff = false;
 while (!endLook)
  {
	if ( (charBuffer[sbPos] == SF)
		||(charBuffer[sbPos] == SFE) )
	 {
	  sbPos -=1;
	  endLook = true;
	 }
	 else if (++sbPos > size3270Buf-1)
			 {
			  sbPos = 0;
			  endBuff = true;
			  endLook = true;
			 }
	}

 if (endBuff)
  {
	endLook = false;
	while (!endLook)
	 {
	  if (sbPos < cursorPos)
		{
		 /*
		  * In this case the entire buffer was wrapped and cursor position
		  * is not in the buffer initial position
		  */
		 if ( (charBuffer[sbPos] == SF)
		  ||(charBuffer[sbPos] == SFE) )
		  {
			/*
			 * if the buffer initial position is the field start
			 * and the the buffer was wrapped, so the field ends
			 * at the last buffer position.
			 */
			if (sbPos > 0)
			  sbPos -=1;
			 else	sbPos = size3270Buf - 1;
			endLook = true;
		  }
		  else sbPos++;
		}
		else
		 {
		  /*
			* In this case the 3270 buffer is unformmated, so there is
			* no fields and the entire screen is the "field".
			*/
		  sbPos = size3270Buf-1;
		  endLook = true;
		 }
	 }
  }
 return sbPos;
}

TPoint
ALFF3270::GetBeginOfField(const int fromPos)
{
 int fdBeginPos = screenBuffer[fromPos].fieldBeginAt + 1;
 return GetCursorPos(fdBeginPos,true);
}

TPoint
ALFF3270::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
ALFF3270::IsWithinField(const int initPos, const int increment)
{
 int fieldEnd = EndOfField(initPos);
 int fieldBegin = screenBuffer[initPos].fieldBeginAt;
 int incPos = initPos+increment-1;
 if (fieldBegin <= fieldEnd )
  {
	if (incPos <= fieldEnd)
	  return true;
	 else return false;
  }
  else
	{
	 if (incPos < size3270Buf)
		return true;
	 else
	  {
		incPos -= size3270Buf;
		if (incPos < fieldEnd)
		  return true;
		else return false;
	  }
	}
}

bool
ALFF3270::IsEndOfField()
{
 int fieldEnd = EndOfField(cursorPos);
 int fieldBegin = screenBuffer[cursorPos].fieldBeginAt;
 if (fieldBegin <= fieldEnd )
  {
	if (cursorPos < fieldEnd)
	  return false;
	 else return true;
  }
  else
	{
	 if (cursorPos >= fieldBegin)
		return false;
	 else
	  {
		if (cursorPos < fieldEnd)
			 return false;
		else return true;
	  }
	}
}

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

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

bool
ALFF3270::IsModifiedField(int cursorPos)
{
 int fieldBegin = screenBuffer[cursorPos].fieldBeginAt;
 return (screenBuffer[fieldBegin].fieldAttr & CHKMODIFIED);
}

void
ALFF3270::SetMDTBit(int cursorPos)
{
 int fieldBegin = screenBuffer[cursorPos].fieldBeginAt;
 screenBuffer[fieldBegin].fieldAttr |= CHKMODIFIED;
}

void
ALFF3270::ResetMDTBits()
{
 unsigned int i;
 for (i=0;i<size3270Buf;i++)
  {
	if (((charBuffer[i] == SF)
	  ||(charBuffer[i] == SFE))
	  && IsUnprotField(i) )
	 screenBuffer[i].fieldAttr &= RESETMDT;
  }
}

void
ALFF3270::ProcessWCC(char wcc)
{
 /*********************************************************************
  *   Write Control Character (WCC) Bit Definitions For Displays      *
  *                                                                   *
  *   BIT   Hex  Explanation                                          *
  *                                                                   *
  *    0    0x80 Has no Function.                                     *
  *    1    0x40 If 1 Resets Partitions Characteristics to their      *
  *              System-Defined defaults.                             *
  *    2-3       For Printers. (Line Size)                             *
  *    4    0x08 Start Printer: Do a Local Copy of display surface    *
  *              to printer at completion of write operation.         *
  *              If Printer is not available must return a            *
  *              negative response (0801).                            *
  *    5    0x04 Sound-Alarm Bit. If 1 sounds Alarm when available.   *
  *    6    0x02 Keyboard Restore Bit. If 1 unlocks keyboard.         *
  *    7    0x01 Reset MDT Bits. If 1 all MDT Bits in character       *
  *              buffer are reset before any data is written or       *
  *              orders are performed.                                *
  *********************************************************************/
 if (wcc & 0x40) /* Reset Bit On? */
  {
	/* Perform Reset Partition Operations */
  }
 if (isPrinter)  // Is this an 3270 remote printer session (LU3) ?
  {
    if ((wcc & 0x20) || (wcc & 0x10)) // Are there line print sizes ?
     {
      wccLineSize = true;   // indicates that line print size is set by wcc
      if ((wcc & 0x20) && (wcc & 0x10))
        thisStreamLineSize = 80;
      else if (wcc & 0x20)
             thisStreamLineSize = 64;
      else  thisStreamLineSize = 40;
      connData->printerBreakLine = true;
     }
    else
     {
       wccLineSize = false;
       // It's assumed that this stream line size is 132 bytes or
       //   is defined by print format control orders (FF, NL or CR)
       thisStreamLineSize = 132;
     }
    if (wcc & 0x08) /* Start Printer */
      printBuffer = true;
    else printBuffer = false;
  }
 else printBuffer = false;

 if (wcc & 0x04) /* Sound Alarm   */
  SoundAlarm();
 if (wcc & 0x02) /* Keyboard Restore */
  {
	keyboardRestore = true;
	lastAID = NOAIDGEN;
  }
 if (wcc & 0x01) /* Reset MDT Bits */
  ResetMDTBits();
}

int
ALFF3270::NextBufPos(int bufPos)
{
 if (bufPos < (size3270Buf-1))
  return(++bufPos);
 else return 0;
}

int
ALFF3270::PrevBufPos(int bufPos)
{
 if (bufPos > 0)
  return(--bufPos);
 else return size3270Buf-1;
}

TPoint
ALFF3270::EraseAllUnprot()
{
  int	 firstUnprotPos = -1;
  int	 nextBufPos = 0;

  bool endRepeat = false;
  while (!endRepeat)
	{
	  nextBufPos =  NextFieldPos(nextBufPos,UNPROTFD,NORESET);
	  if (nextBufPos!=firstUnprotPos)
		{
		 /* Store First Unprotected Field Buffer Position */
		 if (firstUnprotPos == -1)
			firstUnprotPos = nextBufPos;

		 /* Create Undo Field For Each Field Erased */
		 lastCharUpdated = nextBufPos;
		 AddUndo(LASTUPDATED,TOENDOFFIELD);

		 /* Set All Field Chars to NULLs */
		 int endField = NextBufPos(EndOfField(nextBufPos));

		 /* Reset Unprot Field MDT Bit to 0 */
		 screenBuffer[PrevBufPos(nextBufPos)].fieldAttr &= RESETMDT;

		 for (nextBufPos=nextBufPos; nextBufPos!=endField;
				nextBufPos=NextBufPos(nextBufPos))
		  {
			charBuffer[nextBufPos] = NULL;
			screenBuffer[nextBufPos].posAttr = ATTRNULL;
		  }
		}
		else endRepeat = true;
	}

  if (firstUnprotPos < 0)
	currentBufPos = 0;
  else currentBufPos = firstUnprotPos;

  /* Update 3270 Cursor Position */
  cursorPos = currentBufPos;

  lastAID = RESETAID;
  bufferUserModified = true;

  return GetCursorPos(0,false); //TPoint format
}

COLORREF
ALFF3270::GetColor(int color3270)
{
 /* 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 (color3270)
  {
	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;
  }
}

short
ALFF3270::ProcessAttr(ScreenPos* pAttribute, char* buffer,
								 int countPairs, int order)
{
 register int index;
 register short bufSize;
 register unsigned char byte;
 bufSize = 0;
 for (index=countPairs; index>0; index--)
  {
	byte = *buffer++; bufSize++;
	switch (byte)
	 {
	  case   ALLATTR: /* All Attribute Types */
		{
		 if (order != SA)
			return INVALIDATTRTYPE;
		  else
			{
			 byte = *buffer++; bufSize++;
			 if (byte == RESETALL)
			  {
            pAttribute->extendedHighLight = defaultHighLight;
				pAttribute->charSet = defaultCharSet;
				pAttribute->charColor = DEFAULTCOLOR;
				pAttribute->bkgdColor = DEFAULTCOLOR;
				pAttribute->bgTransparency = defaultTransparency;
			  }
			  else return INVALIDATTRVALUE;
			}
		 break;
		}

	  case   FA: /* Field Attribute */
		{
		 if (order == SA)
			return INVALIDATTRTYPE;
		  else
			{
			 pAttribute->fieldAttr = *buffer++;
			 bufSize++;
			}
		 break;
		}

	  case   EH: /* Extended Highlighting */
		{
		 /*  Values
		  *
		  * X'00' - Default
		  * X'F0' - Normal (3270 field attr)
		  * X'F1' - Blink
		  * X'F2' - Reverse Video
		  * X'F4' - Underscore
		  *
		  */
		 byte = *buffer++; bufSize++;
		 if ((byte == EHDEFAULT) || (byte == EHNORMAL)
		  || (byte == EHBLINK) || (byte == EHREVERSE)
		  || (byte == EHUNDERSC))
			pAttribute->extendedHighLight=byte;
		  else return INVALIDATTRVALUE;
		 break;
		}

	  case   FC: /* Foreground Color */
		{
		 /* Values
		  *
		  * See GetColor() Procedure
		  *
		  */
		 byte = *buffer++; bufSize++;
		 pAttribute->charColor = byte;
		 break;
		}

	  case   BC: /* Background Color */
		{
		 /* Values
		  *
		  * See GetColor() Procedure
		  *
		  */
		 byte = *buffer++; bufSize++;
		 pAttribute->bkgdColor = byte;
		 break;
		}

	  case   CS: /* Character Set */
		{
		 /* Values
		  *
		  * X'00' - Default character set
		  * X'40' to X'EF' - Local ID for loadable character sets
		  * X'F0' to X'F7' - Local ID for nonloadable character sets
		  * X'F8' to X'FE' - Local ID for 2-byte codec char sets
		  *                  (Double-Byte Coded Character Set (DBCS)
		  *                    ASIA).
		  */
		 byte = *buffer++; bufSize++;
		 if ((byte > 0x3F) && (byte < 0xFF))
			pAttribute->charSet = byte;
		  else return INVALIDATTRVALUE;
		 break;
		}

	  case   TP: /* Transparency */
		{
		 /* Values
		  *
		  * X'00' - Default
		  * X'F0' - Background is transparent (OR)
		  * X'F1' - Background is transparent (XOR)
		  * X'FF' - Background is opaque(non-transparent)
		  */
		 pAttribute->bgTransparency = *buffer++;
		 bufSize++;
		 break;
		}

	  case   FV: /* Field Validation */
		{
		 /* Bit Values
		  *
		  * 0-4 - B'0000' - Must be zeros
		  * 5   - B'1'    - Mandatory Fill
		  * 6   - B'1'    - Mandatory entry
		  * 7   - B'1'    - Trigger
		  */
		 if (order == SA)
			return INVALIDATTRTYPE;
		  else
			{
			 byte = *buffer++; bufSize++;
			 if (byte > (FVFILL & FVENTRY & FVTRIGG))
				return INVALIDATTRVALUE;
			  else pAttribute->fieldValidation = byte;
			}
		 break;
		}

	  case   FO: /* Field Outlining */
		{
		 /* Bit Values
		  *
		  * B'00000000' - No outlining lines
		  * B'00000001' - Underline only
		  * B'00000010' - Right Vertical line only
		  * B'00000100' - Overline only
		  * B'00001000' - Left Vertical Line only
		  * B'00000011' - Underline & right vertical line
		  * B'00000101' - Underline & overline
		  * B'00001001' - Underline & left vertical line
		  * B'00000110' - Right Vertical line & overline
		  * B'00001010' - Right & Left vertical lines
		  * B'00001100' - Overline & left vertical line
		  * B'00000111' - Rectangle minus left vertical line
		  * B'00001011' - Rectangle minus overline
		  * B'00001101' - Rectangle minus right vertical line
		  * B'00001110' - Rectangle minus underline
		  * B'00001111' - Rectangle
		  *
		  */
		 if (order == SA)
			return INVALIDATTRTYPE;
		 else
			{
			 byte = *buffer++; bufSize++;
			 if ( byte > FORECT )
				return INVALIDATTRVALUE;
			  else pAttribute->fieldOutlining = byte;
			}
		 break;
		}

	  default: /* Invalid Attribute Type */
		{
		 return INVALIDATTRTYPE;
		}

	 } // end switch

  } // end for

  return bufSize;
}

int
ALFF3270::DataFromNetwork(LPALFFBUF pNetInBuf)
{
 register int byte;
 register int streamSize;
 char* stream3270;
 int saveStreamSize,retCode, i;
 char pos;
 unsigned char beginendofjob = 0x00;

 if (!bufferInitialized)
  return BUFFERNOTAVAIL;

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

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

 /*
  * Scan Data Received for parsing 3270 controls
  */
 while ((streamSize) && (stream3270[0] != EM))
 {
  pos  = *stream3270;
  byte = HEX (*stream3270++); streamSize--;
  switch (n3270State)
	{
	/* 3270 Idle: No operation being executed */
	case  n3270_IDLE:
		{
		 switch (byte)
		  {
			case WRITESTRFIELDREM: /* Write Structured Field Remote Command */
			case WRITESTRFIELD:    /* Write Structured Field Command */
										  stream3270--; // for pointing to 1st strf len
										  streamSize++;
										  n3270State = n3270_WRITESF;
										  break;

			case WRITEBUFLOC:    /* Write Operation Local Command  */
			case WRITEBUFREM:    /* Write Operation Remote Command */
										n3270State = n3270_WRITE;
										break;

			case ERASEWRITELOC:  /* Erase/Write Operation Local Command */
			case ERASEWRITEREM:  /* Erase/Write Operation Remote Command */
										n3270State = n3270_ERASEWRITE;
										break;

			case ERASEWRITEALTLOC : /* Erase/Write Alternate Operation Local Command */
			case ERASEWRITEALTREM : /* Erase/Write Alternate Operation Remote Command */
										n3270State = n3270_ERASEWRITEALT;
										break;

			case ERASEALLUNPROTLOC: /* Erase All Unprotected Operation Local Command */
			case ERASEALLUNPROTREM: /* Erase All Unprotected Operation Remote Command */
										if (*stream3270 == EM)
										 {
										  pNetInBuf->ring_consumed(2);
										  n3270State = n3270_ERASEALLUNPROT;
										  break;
										 }
										 else
										  {
											pNetInBuf->ring_consumed(saveStreamSize);
											n3270State = n3270_IDLE;
											return DATAFOLLOWEAUREAD;
										  }

			case READBUFFERLOC : /* Read Buffer Operation Local Command */
			case READBUFFERREM : /* Read Buffer Operation Remote Command */
                              if (isPrinter)
                               {
                                /* Invalid Command Code */
										  n3270State = n3270_IDLE;
										  pNetInBuf->ring_consumed(saveStreamSize);
										  return INVALIDCOMMAND;
                               }
										else if (*stream3270 == EM)
										 {
										  pNetInBuf->ring_consumed(saveStreamSize);
										  n3270State = n3270_IDLE;
										  return READBUFFERCOMMAND;
										 }
										else
										 {
											pNetInBuf->ring_consumed(saveStreamSize);
											n3270State = n3270_IDLE;
											return DATAFOLLOWEAUREAD;
										 }

			case READMODIFIEDLOC:/* Read Modified Operation Local Command */
			case READMODIFIEDREM:/* Read Modified Operation Remote Command */
                              if (isPrinter)
                               {
                                /* Invalid Command Code */
										  n3270State = n3270_IDLE;
										  pNetInBuf->ring_consumed(saveStreamSize);
										  return INVALIDCOMMAND;
                               }
										else if (*stream3270 == EM)
										 {
										  pNetInBuf->ring_consumed(2);
										  n3270State = n3270_IDLE;
										  return READMODIFIEDCOMMAND;
										 }
										else
										 {
											pNetInBuf->ring_consumed(saveStreamSize);
											n3270State = n3270_IDLE;
											return DATAFOLLOWEAUREAD;
										 }

			case NOPCOMMAND    : /* No Operation */
										n3270State = n3270_IDLE;
										break;

			default            : /* Invalid Command Code */
										n3270State = n3270_IDLE;
										pNetInBuf->ring_consumed(saveStreamSize);
										return INVALIDCOMMAND;
		  }

		 break;

		}   /* End of n3270_IDLE State */

	/* 3270 Erase All Unprotected Fields  */
	case  n3270_ERASEALLUNPROT:
		{
		 EraseAllUnprot();
		 n3270State = n3270_IDLE;
       if (isPrinter && printBuffer)
        return STARTPRINTING;
       else return KEYBOARDRESTORE;
		}

	/* 3270 Erase/Write Alternate: Select Alternate Screen and do same
		operations as is done within Erase/Write */
	case  n3270_ERASEWRITEALT:
		{
		 ClearBuf();
		 scrLineSize = altScrLineSize;
		 size3270Buf = altScrLineSize*altScrNumLines;
		 alternateScreen = true;
		 ProcessWCC(pos);  /* pos is byte in char format */
		 retCode = WriteBuffer(&stream3270,streamSize);
		 if (retCode)
		  {
			pNetInBuf->ring_consumed(saveStreamSize);
			return retCode;
		  }
		 n3270State = n3270_IDLE;
		 break;
		}

	/* 3270 EraseWrite: Select Default Screen and Erase All Buffer and
		Write Data ... */
	case  n3270_ERASEWRITE:
		{
		 ClearBuf();
		 scrLineSize = defScrLineSize;
		 size3270Buf = defScrLineSize*defScrNumLines;
		 alternateScreen = false;
		 ProcessWCC(pos);  /* pos is byte in char format */
		 retCode = WriteBuffer(&stream3270,streamSize);
		 if (retCode)
		  {
			pNetInBuf->ring_consumed(saveStreamSize);
			return retCode;
		  }
		 n3270State = n3270_IDLE;
		 break;
		}

	/* 3270 Write: Just write data to buffer .... */
	case  n3270_WRITE:
		{
		 ProcessWCC(pos);  /* pos is byte in char format */
		 retCode = WriteBuffer(&stream3270,streamSize);
		 if (retCode)
		  {
			pNetInBuf->ring_consumed(saveStreamSize);
			return retCode;
		  }
		 n3270State = n3270_IDLE;
		 break;
		}

	/* 3270 Write Structured Field: Process Only SAA Compatibility Fields */
	case  n3270_WRITESF:
		{
		 while (streamSize)
		 {
		  /* Structured Fields Implemented Just for SAA Compatibility */
		  short strfSize, saveStrfSize;
        unsigned char cmnd;

		  /* Build Str Field Length */
		  memcpy((char*)(&strfSize)+1,&*stream3270++,1);
		  memcpy(&strfSize,&*stream3270++,1);
		  streamSize -= 2;
		  strfSize -= 2;

		  /* Get Str Field ID (SFID) */;
		  byte = HEX (*stream3270++); streamSize--; strfSize--;

		  /* Handle Str Order and Process Al Acceptable */
		  switch (byte)
			{
			 case OUTBOUND3270DS:  /* SKIP Partition ID: It Must be Always 0x00 (No Partitions) */
										  stream3270++; streamSize--; strfSize--;
										  /* Get Outbound 3270DS Command: */
										  cmnd = *stream3270++;
										  streamSize--;  strfSize--;
										  switch (cmnd)
											{
											 case ERASEWRITEREM:
											 case ERASEWRITEALTREM:
													{
													 /* Screen Alternate Size Must be
														 selected by ERASE/RESET command */
													 ClearBuf();
													 /* Should Write Data as WriteBuffer */
													}
											 case WRITEBUFREM:
													{
													 ProcessWCC(*stream3270++);
													 streamSize--; strfSize--;
													 saveStrfSize = strfSize;
													 if (strfSize)
													  {
														 int writeSize = strfSize;
														 retCode =
														 WriteBuffer(&stream3270,writeSize);
														 if (retCode)
														  {
															pNetInBuf->ring_consumed(saveStreamSize);
															n3270State = n3270_IDLE;
															return retCode;
														  }
														 else streamSize -= saveStrfSize;
													  }
													 break;
													}

											 case ERASEALLUNPROTREM:
													{
													 EraseAllUnprot();
													 break;
													}

											 case COPYBUF:
													{
													 /* This Function is supplied by Tec3270 Print Screen.
														 So we should Skip Copy Buffer Data. */
													 stream3270 +=3;
													 streamSize -=3;
													 strfSize   -=3;
													 break;
													}

											 default: /* Invalid Command Code */
													 {
													  n3270State = n3270_IDLE;
													  pNetInBuf->ring_consumed(saveStreamSize);
													  return INVALIDOUT3270CMND;
													 }
											}
										  break;

			 case  READPARTITION:  /* SKIP Partition ID: It Must be 0xFF for
											  Queries  or 00-7E for Read Operations */
										  stream3270++; streamSize--; strfSize--;

										  /* Get ReadPartition Type: */
										  cmnd = *stream3270++;
										  streamSize--;  strfSize--;
										  switch (cmnd)
											{
											 /* Read Buffer Operation Remote Command */
											 case READBUFFERREM :
												  {
													if (*stream3270 == EM)
													 {
													  pNetInBuf->ring_consumed(saveStreamSize);
													  n3270State = n3270_IDLE;
													  return READBUFFERCOMMAND;
													 }
													 else
													  {
														pNetInBuf->ring_consumed(saveStreamSize);
														n3270State = n3270_IDLE;
														return DATAFOLLOWEAUREAD;
													  }
												  }
											 /* Read Modified All Command */
											 case READMODIFIEDALL:
											 /* Read Modified Command     */
											 case READMODIFIEDREM:
												  {
													if (*stream3270 == EM)
													 {
													  pNetInBuf->ring_consumed(saveStreamSize);
													  n3270State = n3270_IDLE;
													  return READMODIFIEDCOMMAND;
													 }
													 else
													 {
													  pNetInBuf->ring_consumed(saveStreamSize);
													  n3270State = n3270_IDLE;
													  return DATAFOLLOWEAUREAD;
													 }
												  }

											 /* Query Reply All Supported Functions */
											 case   READQRYREPLY:
												  {
													n3270State = n3270_IDLE;
													if (*stream3270 == EM)
													 {
													  pNetInBuf->ring_consumed(saveStreamSize);
													  return QUERYREPLY;
													 }
													 else
													 {
													  pNetInBuf->ring_consumed(saveStreamSize);
													  return DATAFOLLOWEAUREAD;
													 }
													}

											 /* Query Reply Listed Functions */
											 case READQRYREPLYLIST:
												  {
													/* Create Query Reply list Preceded By ReqType */
                                       if (queryReplyList)
                                         delete [] queryReplyList;
													queryReplyList = new char[strfSize*2];

													/* Store REQTYP at first Query List Byte      */
													memcpy(queryReplyList,stream3270,strfSize);

													/* Terminate Query Reply List */
													memset(queryReplyList+strfSize,0xFF,2);

													/* Skip To First Byte After Struct Field */
													streamSize -= strfSize;
													stream3270 += strfSize;
													n3270State = n3270_IDLE;

													if (*stream3270 == EM)
													 {
													  pNetInBuf->ring_consumed(saveStreamSize);
													  return QUERYREPLYLIST;
													 }
													else
													 {
													 pNetInBuf->ring_consumed(saveStreamSize);
													 return DATAFOLLOWEAUREAD;
													 }
												  }

											 default: /* Invalid Read Partition Type */
													 {
													  n3270State = n3270_IDLE;
													  pNetInBuf->ring_consumed(saveStreamSize);
													  return INVALIDREADPARTYPE;
													 }

											}
                                //break;  Unreachable Code !!

			 case     ERASERESET:  /* This is ERASERESET Function */
										  if (*stream3270 & 0x01)
											{
											 /* Set Alternate Screen Size */
											 scrLineSize = altScrLineSize;
											 size3270Buf = altScrLineSize*altScrNumLines;
											 alternateScreen = true;
											}
										  else
											{
											 /* Set Default Screen Size */
											 scrLineSize = defScrLineSize;
											 size3270Buf = defScrLineSize*defScrNumLines;
											 alternateScreen = false;
											}
										  stream3270++; streamSize--; strfSize--;
                                keyboardRestore = true;
										  break;

			 case   SETREPLYMODE:  /* SKIP Partition ID: It Must be Always 0x00 (No Partitions) */
										  stream3270++; streamSize--; strfSize--;
										  if ((*stream3270 == FDMODE)
											 ||(*stream3270 == EXTFDMODE)
                                  ||(*stream3270 == CHARMODE))
											{
											 replyMode = *stream3270++;
											 streamSize--; strfSize--;
                                  if (replyMode == CHARMODE)
                                   {
                                    if (charModeAttrList)
                                      delete [] charModeAttrList;
                                    charModeAttrList = new unsigned char[strfSize+1];
                                    i = 0;
                                    while (strfSize)
                                     {
                                      charModeAttrList[i++] = *stream3270++;
                                      streamSize--; strfSize--;
                                     }
                                     charModeAttrList[i] = 0x00;
                                   }
											}
										  else
											{
											 pNetInBuf->ring_consumed(saveStreamSize);
											 return INVALIDREPLYMODE;
											}

                                keyboardRestore = true;
										  break;

			 case   EXTENDEDSTRFD:  /* This is an extended  structured field */
                               {
                                /* For this version processing BEGIN/END
                                 * of Printer JOB, just for printers, obviously.
                                 */
										  if ((*stream3270 == BEGINENDFILE) && isPrinter)
											{
											 /* This is an Begin/End of File STR Field */
                                  stream3270 += 2;  // Skip identifier and PID
                                  streamSize -=2;
                                  /* Check Begin/End of File Flag */
                                  if ((*stream3270 & BEGIN_OF_FILE)
                                   &&(!*stream3270 & END_OF_FILE ) )
                                   {
                                    // BEGIN OF PRINTER JOB
                                    beginendofjob &= BEGIN_OF_FILE;
                                   }
                                  if (!(*stream3270 & BEGIN_OF_FILE)
                                   &&(*stream3270 & END_OF_FILE ) )
                                   {
                                    // END OF PRINTER JOB
                                    beginendofjob &= END_OF_FILE;
                                   }
                                  else
                                   {
											   /* Incorrect Begin/End of File STR Field */
                                    pNetInBuf->ring_consumed(saveStreamSize);
                                    return INVALIDSTRFIELD;
                                   }
											}
										  else
											{
											 /* Unsupported (other then BEGINENDFILE)
                                   *  STR Field                              */
                                  pNetInBuf->ring_consumed(saveStreamSize);
                                  return UNSUPPORTEDSTRFIELD;
											}
                                // Must skip Flag1 and Flag 2 of BeginEnd Str Fd
										  stream3270 += 2; streamSize -=2; strfSize -=2;
										  break;
                               }
			 default: /* Structured Field Function Not Supported */
										  {
											n3270State = n3270_IDLE;
											pNetInBuf->ring_consumed(saveStreamSize);
											return UNSUPPORTEDSTRFIELD;
										  }
			} // switch (.....)

		  /* Check for end of structured field message before end of
			  entire message */
		  if (*stream3270 == EM)
			{
			 stream3270++;
			 streamSize--;
			 break;
			}
		 } // while (streamSize)
		 n3270State = n3270_IDLE;
       break;
		}
    default: /* Invalid State - Internal Error */
				 n3270State = n3270_IDLE;
				 pNetInBuf->ring_consumed(saveStreamSize);
				 return INVALIDCOMMAND;

	} // end switch (n3270State)

 }  // end while (streamSize)

 /* Termination of this 3270 stream message 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();
 n3270State = n3270_IDLE;

 /* Check  entire 3270 buffer for correcting unfilled positions and
	 references to field begin                                       */
 int fieldBegin = 0;
 int firstField = 0;
 int pseudoPos  = 0;
 bool firstTime = true;
 for (int sbPos = 0; sbPos < size3270Buf; sbPos++)
  {
	pScreenBuffer = &screenBuffer[sbPos];
	if ((charBuffer[sbPos] == SF)
	 ||(charBuffer[sbPos] == SFE))
	 {
	  fieldBegin = sbPos;
     pseudoPos  = sbPos;
	  pScreenBuffer->posAttr = ATTRNULL;
	  pScreenBuffer->fieldBeginAt = fieldBegin;
	  if (firstTime)
		{
		 firstField = fieldBegin;
		 firstTime = false;
		}
	 }
	else
	 {
	  char posChar = charBuffer[sbPos];
	  if ((sbPos>0) && (posChar != FF) && (posChar != NL) && (posChar != CR)
      && (IsCharAttrEqual(sbPos,pseudoPos)))
		 pScreenBuffer->posAttr = ATTRNULL;
	  else
		 {
		  pseudoPos = sbPos;
		  pScreenBuffer->posAttr = PSEUDOFIELD;
		 }
	  pScreenBuffer->fieldBeginAt = fieldBegin;
	  pScreenBuffer->fieldAttr = screenBuffer[fieldBegin].fieldAttr;
	 }
  }

  /* If First Field Do Not Begin On First Buffer Position We Must Complete
	  Screen Buffer Formatting From First Buffer Pos to Field Begin Pos */
  if (firstField > 0)
	{
	 for (int sbPos = 0; sbPos < firstField; sbPos++)
	  {
		screenBuffer[sbPos].fieldBeginAt = fieldBegin;
	  }
	}

 /*
  * Restore Keyboard Operation if WCC asks for ...
  */
 retCode = 0;
 if (alternateScreen)
  retCode |= SETALTERNATESCREEN;

 if (keyboardRestore)
  {
	keyboardRestore = false;
	retCode |= KEYBOARDRESTORE;
  }
 else retCode |= NOKEYBOARDRESTORE;

 if (isPrinter && printBuffer)
  retCode |= STARTPRINTING;

 if (beginendofjob)
   retCode |= beginendofjob;

 return retCode;
}

int
ALFF3270::WriteBuffer(char** stream3270, int& streamSize)
{
 register unsigned char byte = 0x00;
 unsigned int nextBufPos;
 unsigned char countPairs;
 short addr16Bits, attrSize;
 bool lastProcessWasControl, lastProcessWasPT;
 bool endRepeat;

 /* Get Current Char Attribute Information From 3270 Buffer */
 currentBufPos = cursorPos;
 currChar     =  charBuffer[currentBufPos];
 GetDefaultCharAttr(currCharAttr);
 lastProcessWasControl = false;
 lastProcessWasPT = false;

 /*
  * Scan Data Received for parsing 3270 orders and data
  */
 while ((streamSize) && (*stream3270[0] != EM))
 {
  byte = **stream3270; *stream3270+=1; streamSize--;

  /* Writing 3270 Buffer after receiving EW or W Command */
  switch (byte)
	{
	 case SBA: /* Set Buffer Address
					* Next two bytes are 12 Bit Address pointer
					* to a buffer position: must be within buffer
					* limits...
					*/
				  addr16Bits = Addr12To16Bits(*stream3270);
				  if (addr16Bits != INVALIDBUFADDR)
					 currentBufPos = addr16Bits;
				  else return INVALIDBUFADDR;

				  /* Skip Addr 12 Bits already processed */
				  *stream3270+=2;
				  streamSize-=2;

				  /* Should Mark The New Buffer Position Because It May Have
					  Char Attributes different from buffer positions before it */
				  currCharAttr.posAttr = PSEUDOFIELD;

				  lastProcessWasControl = true;
				  break;

	 case  SF: /* Start Field */
				  charBuffer[currentBufPos] = SF;
				  pScreenBuffer =	&screenBuffer[currentBufPos];

				  /* Reset All Associated Extended Field Attribute
					  To Its Default Set Field Attribute To Its
					  Supplied Value */
				  GetDefaultCharAttr(*pScreenBuffer,currentBufPos,
											**stream3270);
				  *stream3270+=1; streamSize--;

				  /* Set Field Begin To Current Buffer Position */
				  pScreenBuffer->fieldBeginAt =  currentBufPos;

				  /* Set Current Buffer Position To Next Buffer Position */
				  currentBufPos = NextBufPos(currentBufPos);

				  lastProcessWasControl = true;
				  break;

	 case SFE: /* Start Field Extended */
				  charBuffer[currentBufPos] = SFE;
				  pScreenBuffer =	&screenBuffer[currentBufPos];

				  /* Set Field Attributes To Its Default For Assigning
					  Unespecified Attributes To Its Default */
				  GetDefaultCharAttr(*pScreenBuffer,currentBufPos);

				  /* Set Field Begin To Current Buffer Position */
				  pScreenBuffer->fieldBeginAt =  currentBufPos;

				  /* Process Extended Attribute Supplied, If Any Exists */
				  countPairs = **stream3270;
				  *stream3270+=1; streamSize--;
				  attrSize = ProcessAttr(pScreenBuffer, *stream3270, countPairs, SFE);
				  if (attrSize > 0)
					{
					 *stream3270+=attrSize;
					 streamSize-=attrSize;
					}
				  else return attrSize; /* INVALIDATTRTYPE/VALUE */;

				  /* Set Current Buffer Position To Next Buffer Position */
				  currentBufPos = NextBufPos(currentBufPos);

				  lastProcessWasControl = true;
				  break;

	 case  SA: /* Set Attribute */
				  currCharAttr.posAttr = PSEUDOFIELD;
				  attrSize = ProcessAttr(&currCharAttr, *stream3270, 1, SA);
				  if (attrSize > 0)
					{
					 *stream3270+=attrSize;
					 streamSize-=attrSize;
					}
				  else return attrSize; /* INVALIDATTRTYPE/VALUE */;

				  screenBuffer[currentBufPos] = currCharAttr;

				  lastProcessWasControl = true;
				  break;

	 case  MF: /* Modify Field */
				  if (( charBuffer[currentBufPos] != SF)
					 && (charBuffer[currentBufPos] != SFE) )
					 return INVALIDATTRTYPE;
				  else
					{
					 countPairs = **stream3270;
					 *stream3270+=1; streamSize--;
					 attrSize = ProcessAttr(&screenBuffer[currentBufPos],*stream3270,
					                        countPairs, SFE);
					 if (attrSize > 0)
					  {
						currentBufPos = NextBufPos(currentBufPos);
						*stream3270+=attrSize;
						streamSize-=attrSize;
					  }
					 else	return attrSize; /* INVALIDATTRTYPE/VALUE */;
					}
				  lastProcessWasControl = true;
				  break;

	 case  IC: /* Insert Cursor */
				  cursorPos = currentBufPos;
				  lastProcessWasControl = true;
				  break;

	 case  PT: /* Program Tab */
				  if ((!lastProcessWasControl)
					|| ((lastProcessWasPT) && currentBufPos == 0))
					  nextBufPos = NextFieldPos(currentBufPos,UNPROTFD,RESET);
				  else nextBufPos = NextFieldPos(currentBufPos,UNPROTFD,NORESET);
				  currentBufPos = nextBufPos;
				  lastProcessWasControl = true;
				  lastProcessWasPT = true;
				  break;

	 case  RA: /* Repeat To Address */
				  addr16Bits = Addr12To16Bits(*stream3270);
				  if (addr16Bits == INVALIDBUFADDR)
				     break;
				  else
					{
					 /* Skip Addr 12 Bits already processed */
					 *stream3270+=2;
					 streamSize-=2;

					 /* Get Character to be repeated */
					 byte = **stream3270;
					 *stream3270+=1; streamSize--;
					 if (byte != GE)
					  {
						if ((byte < 64) && (byte != NULL))
						  /* Not a valid graphic representation */
						  return INVALIDATTRVALUE;
						else
						 {
						  endRepeat = false;
						  while (!endRepeat)
							{
							 screenBuffer[currentBufPos] = currCharAttr;
							 charBuffer[currentBufPos] = byte;
							 currentBufPos = NextBufPos(currentBufPos);
							 if (currentBufPos == addr16Bits)
								endRepeat = true;
							}
						 }
					  }
					 else
					  {
						/* Graphic Escape Sequence (GE) */
						byte = **stream3270;
						*stream3270+=1; streamSize--;
						/* GE is not supported by this version */
                  return INVALIDORDER;
					  }
					}
				  lastProcessWasControl = true;
				  break;

	 case EUA: /* Erase Unprotected To Address */
				  addr16Bits = Addr12To16Bits(*stream3270);
				  if (addr16Bits == INVALIDBUFADDR)
					 return INVALIDBUFADDR;
				  else
					{
					 /* Skip Addr 12 Bits already processed */
					 *stream3270+=2;
					 streamSize-=2;
					 endRepeat = false;
					 int fdBegin;
					 while (!endRepeat)
					  {
						if (IsUnprotField(currentBufPos))
						 {
						  charBuffer[currentBufPos] = NULL;
						  fdBegin = screenBuffer[currentBufPos].fieldBeginAt;
						  GetDefaultCharAttr(screenBuffer[currentBufPos],
													fdBegin,
													screenBuffer[fdBegin].fieldAttr);
						 }
						currentBufPos = NextBufPos(currentBufPos);
						if (currentBufPos == addr16Bits)
						 endRepeat = true;
					  }
					}
				  lastProcessWasControl = true;
				  break;

	 case  GE: /* Graphic Escape */
				  /* This version does not support Graphic Escape
               * as it is indicated on Charset Query Reply.
               *
               * Its implementation is under evaluation as GE codepoints
               * refers to APL symbols,as stated on page
               * http://x3270.bgp.nu/Charset.html
               *
               * May be on version 4 it will be available.
               */
				  lastProcessWasControl = false;
              return INVALIDORDER;

				  /*---------------------------------------------------
               * The Code below is the first approach for
               * implementing GE support. It must be verified
               * before doing any implementation.
               *---------------------------------------------------
				  if (screenBuffer[currentBufPos].charSet != CSDEFAULT)
					 return INVALIDORDER;
				  else
					{
					 // Get char to be interpreted from alternate Charset
                // Assume Charset is APL charset as GE code points to
                // APL symbols.
					 byte = **stream3270;
					 *stream3270+=1; streamSize--;
					 if ( (byte>0x3F) && (byte < 0xFF))
                 {
					   screenBuffer[currentBufPos] = currCharAttr;
					   charBuffer[currentBufPos] = byte;
					   currCharAttr.posAttr = ATTRNULL;
                  // The charset for APL symbols must be set for
                  // having its correct translation on DataToScreen Method.
                  screenBuffer[currentBufPos].charSet = ?????? //APL Internal Charset
  					   currentBufPos = NextBufPos(currentBufPos);
                 }
					 else	return INVALIDORDER;
					 }
					lastProcessWasControl = false;
					break;
               //-----*/

/////////////////////// Format-Control Orders - Printers Only //////////////////

	 case  FF: /* Printer Form Feed:
               * - Moves the print position to the top and left margin of next page
               */
              charBuffer[currentBufPos] = byte;
              screenBuffer[currentBufPos] = currCharAttr;
              if (isPrinter)
               {
                /* Should Mark this position because it must be processed
					    as an format control order on buffer printing */
                screenBuffer[currentBufPos].posAttr == PSEUDOFIELD;
                lastProcessWasControl = true;
               }
              else
               {
                currCharAttr.posAttr = ATTRNULL;
                lastProcessWasControl = false;
               }

              /* Set Current Buffer Position To Next Buffer Position */
				  currentBufPos = NextBufPos(currentBufPos);
				  break;
    /*
     * These format control orders are valid only if encountered in a print
     *    field during a printout that does not have a line length format
     *    specified by the WCC.
     */
	 case  NL: /* Printer New  Line:
               * - Moves the print position horizontally to the left margin and
               *   vertically down to the next line
               */
	 case  CR: /* Printer Carriage Return:
               * - Moves the print position horizontally to the left margin
               */
              charBuffer[currentBufPos] = byte;
              screenBuffer[currentBufPos] = currCharAttr;
              if (isPrinter && !IsWCCLineFormatted())
               {
                /* Should Mark this position because it must be processed
					    as an format control order on buffer printing */
                screenBuffer[currentBufPos].posAttr == PSEUDOFIELD;
                lastProcessWasControl = true;
               }
              else
               {
                currCharAttr.posAttr = ATTRNULL;
                lastProcessWasControl = false;
               }

              /* Set Current Buffer Position To Next Buffer Position */
				  currentBufPos = NextBufPos(currentBufPos);
				  break;

	 default : /* Other Characters ... */
				  /* Insert character at currentBufPos
					* on screenBuffer
					*/
				  if ((byte >= 0x40)
					 ||(byte == NULL)
					 ||(byte == DUP)
					 ||(byte == FM)
					 ||(byte == EPM)
					 ||(byte == EO)
					 ||(byte == SUB))
					{
					 lastProcessWasControl = false;
					 screenBuffer[currentBufPos] = currCharAttr;
					 charBuffer[currentBufPos] = byte;
					 currCharAttr.posAttr = ATTRNULL;
					 currentBufPos = NextBufPos(currentBufPos);
					}
				  else return INVALIDORDER;
				  break;
	}
 }
 return 0;
}

unsigned char
ALFF3270::Get3270SenseCode(int retCode)
{
 unsigned char byteError;
 switch (retCode)
  {
   case INVALIDCOMMAND:
   case INVALIDORDER:
   case UNSUPPORTEDSTRFIELD:
   case INVALIDOUT3270CMND:
   case INVALIDREADPARTYPE:
   case COMMAND_REJECTED: byteError =  COMMAND_REJECT;
                          break;
   case INTERVENTION_REQ: byteError =  INTERV_REQD;
                          break;
   case BUFFERNOTAVAIL:
   case COMP_DISCONNECTED:byteError =  COMPONENT_DISCONN;
                          break;
   case INVALIDATTRTYPE:
   case INVALIDATTRVALUE:
   case INVALIDBUFADDR:
   case DATAFOLLOWEAUREAD:
   case INVALIDREPLYMODE:
   case  OPERATION_CHECK: byteError =  OPERATION_CHECK;
                          break;
                default : byteError =  COMMAND_REJECT;
                          break;
  }
 return byteError;
}


unsigned char
ALFF3270::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_PF13        : return AIDPF13;
	case IDS_PF14        : return AIDPF14;
	case IDS_PF15        : return AIDPF15;
	case IDS_PF16        : return AIDPF16;
	case IDS_PF17        : return AIDPF17;
	case IDS_PF18        : return AIDPF18;
	case IDS_PF19        : return AIDPF19;
	case IDS_PF20        : return AIDPF20;
	case IDS_PF21        : return AIDPF21;
	case IDS_PF22        : return AIDPF22;
	case IDS_PF23        : return AIDPF23;
	case IDS_PF24        : return AIDPF24;
	case IDS_CLEAR       : return AIDCLEAR;
	case IDS_PA1         : return AIDPA1;
	case IDS_PA2         : return AIDPA2;
	case IDS_PA3         : return AIDPA3;
	case IDS_ATTN        : return AIDPA1;
   case IDS_SYSREQ      : return AIDSYSREQ;
	default              : return NOAIDGEN;
  }
}

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

int
ALFF3270::DataToNetwork(LPALFFBUF pNetOutBuf, int mode)
{
 int netCount=0, netOutMax=0,
	  firstField=-1, numFields=0;
 unsigned short fromPos=0, begField=0;
 unsigned char numPairs = 0;
 char *netBufPtr, *netBufSave, *pNumPairs;
 bool endSearch = false, fieldInited = false, firstTime = true;
 /*
  *  Set Network Output Buffer Controls
  */
 netBufSave = netBufPtr = pNetOutBuf->supply;
 netOutMax = pNetOutBuf->ring_empty_consecutive();
 netBufSave = netBufSave;
 netCount = 0;

 /*
  * Set Inbound 3270 Fields according to mode supplied
  */
 switch (mode)
  {
	case ALLBUFFER: /* Read Buffer Command Received From Host
							 It may be done in one of three reply modes available:
									  - Field Mode
									  - Extended Field Mode
									  - Character Mode.
							 See Set Reply Mode Structured Field Function on
							 Manual GA23-0059-05 Page 5-63 and Read Buffer Command
							 on same Manual at Page 3-11 for more information.    */

						 /* Data Transfer Must Begin on Buffer Location 0 */
						 fromPos = 0;
						 /*
						  * Set InBound 3270 Stream Header (AID,Cursor Position,..)
						  */
						 if ((netOutMax-netCount) > 2 )
						  {
                    	*netBufPtr++ = NOAIDGEN; netCount++;
							unsigned short posCursor = (unsigned short)cursorPos;
							Addr16To12Bits(&posCursor,netBufPtr);
							netBufPtr +=2; netCount+=2;
						  }
						 else
						  {
							pNetOutBuf->ring_supplied(netOutMax-2);
							return IDS_RINGBUFFERFULL;
						  }

						 /* Insert All 3270 Buffer into Output Buffer */
						 firstField = -1;
						 fieldInited = false;
						 endSearch   = false;
						 numFields = 0;
						 for (fromPos=0; fromPos<size3270Buf;fromPos++)
						 {
						  if ((charBuffer[fromPos] == SF)
							 ||(charBuffer[fromPos] == SFE))
							{
							 switch (replyMode)
							  {
								case    FDMODE: /* Only Start Field Orders */
													 *netBufPtr++ = SF;
													 *netBufPtr++ = screenBuffer[fromPos].fieldAttr;
													 netCount+=2;
													 break;

								case  CHARMODE:
								case EXTFDMODE: *netBufPtr++ = SFE;
													 pNumPairs = netBufPtr++;
													 numPairs  = 1;
													 *netBufPtr++ = FA; //Field Attribute
													 *netBufPtr++ = screenBuffer[fromPos].fieldAttr;
													 netCount+=4;
													 if (screenBuffer[fromPos].extendedHighLight
														 != defaultHighLight)
													  {
														*netBufPtr++ = EH;
														*netBufPtr++ = screenBuffer[fromPos].extendedHighLight;
														netCount+=2;
														numPairs++;
													  }
													 if (screenBuffer[fromPos].charSet
														 != defaultCharSet)
													  {
														*netBufPtr++ = CS;
														*netBufPtr++ = screenBuffer[fromPos].charSet;
														netCount+=2;
														numPairs++;
													  }
													 if (screenBuffer[fromPos].charColor
														 != defaultCharColor)
													  {
														*netBufPtr++ = FC;
														*netBufPtr++ = screenBuffer[fromPos].charColor;
														netCount+=2;
														numPairs++;
													  }
													 if (screenBuffer[fromPos].bkgdColor
														 != defaultBkgdColor)
													  {
														*netBufPtr++ = BC;
														*netBufPtr++ = screenBuffer[fromPos].bkgdColor;
														netCount+=2;
														numPairs++;
													  }
													 if (screenBuffer[fromPos].bgTransparency
														 != defaultTransparency)
													  {
														*netBufPtr++ = TP;
														*netBufPtr++ = screenBuffer[fromPos].bgTransparency;
														netCount+=2;
														numPairs++;
													  }
													 if (screenBuffer[fromPos].fieldValidation
														 != defaultValidation)
													  {
														*netBufPtr++ = FV;
														*netBufPtr++ = screenBuffer[fromPos].fieldValidation;
														netCount+=2;
														numPairs++;
													  }
													 if (screenBuffer[fromPos].fieldOutlining
														 != defaultOutLining)
													  {
														*netBufPtr++ = FO;
														*netBufPtr++ = screenBuffer[fromPos].fieldOutlining;
														netCount+=2;
														numPairs++;
													  }
													 if ((netOutMax-netCount) < 2 )
													  {
														pNetOutBuf->ring_supplied(netOutMax-2);
														return IDS_RINGBUFFERFULL;
													  }
													 *pNumPairs = numPairs;
													 break;

								default:        return IDS_INVALIDREPLYMODE;
							  }
							}
							else
							{
							  if (charBuffer[fromPos] != NULL)
								{
								 if ((netOutMax-netCount) < 2 )
								  {
									pNetOutBuf->ring_supplied(netOutMax-2);
									return IDS_RINGBUFFERFULL;
								  }
								 else
								  {
									*netBufPtr++ = charBuffer[fromPos];
									netCount++;
								  }
								}
								else
								{
								  /* If Yale Null Process Option is Set then
									  Should transform all nulls to blank chars */
								  if ((netOutMax-netCount) < 2 )
									{
									 pNetOutBuf->ring_supplied(netOutMax-2);
									 return IDS_RINGBUFFERFULL;
									}
								  else
									{
									 if (connData->actYale)
										*netBufPtr++ = EBCDICBLANK;
									 else *netBufPtr++ = NULL;
									 netCount++;
									}
								}
							}
						 }
						 break;

	case MODIFIED : /* If Read Modified is unchained or is chained from a Copy,
						  * Select, Sense, or No Operation commands the search begins
						  * at buffer address 0, otherwise must begin at current address.
						  */
						 fromPos = 0;
						 /*
						  * Set InBound 3270 Stream Header (AID,Cursor Position,..)
						  */
						 if ((netOutMax-netCount) > 2 )
						  {
							*netBufPtr++ = lastAID; netCount++;
							unsigned short posCursor = (unsigned short)cursorPos;
							Addr16To12Bits(&posCursor,netBufPtr);
							netBufPtr +=2; netCount+=2;
						  }
						 else return false;
						 /* Insert Modified Fields into Output Buffer */
						 firstField = -1;
						 fieldInited = false;
						 endSearch   = false;
						 numFields = 0;
						 while (!endSearch)
						 {
						  if ((charBuffer[fromPos] == SF)
							 ||(charBuffer[fromPos] == SFE))
							{
							 numFields+=1;
							 if (fieldInited)
							  fieldInited = false;

							 /* Check for entire buffer searched condition */
							 if (firstTime)
							  {
								firstTime=false;
								firstField=fromPos;
							  }
							 else if (fromPos == firstField)
									 {
									  endSearch = true;
									  break;
									 }

							 /* If Modified Field it should be sent */
							 if (IsModifiedField(fromPos))
							  {
								 fieldInited = true;
								 if ((netOutMax-netCount) > 3 )
								  {
									*netBufPtr++ = SBA; netCount++;
									begField = fromPos+1;
									Addr16To12Bits(&begField,netBufPtr);
									netBufPtr +=2; netCount+=2;
								  }
								  else return IDS_RINGBUFFERFULL;
							  }
							}
							else if (fieldInited)
							 {
							  if (charBuffer[fromPos] != NULL)
								{
								 if ((netOutMax-netCount) > 2 )
								  {
									*netBufPtr++ = charBuffer[fromPos];
									netCount++;
								  }
								  else return IDS_RINGBUFFERFULL;
								}
								else
								 {
								  /* If Yale Null Process Option is Set then
									  Should transform all nulls to blank chars */
								  if (connData->actYale)
									{
									 if ((netOutMax-netCount) > 2 )
									  {
										*netBufPtr++ = EBCDICBLANK;
										netCount++;
									  }
									  else return IDS_RINGBUFFERFULL;
									 }
								 }
							 }
						  fromPos = NextBufPos(fromPos);
						  if (fromPos == 0)
							{
							 if (!fieldInited)
							  {
								/*
								 * Entire buffer was searched and there is no
								 * field inited and modified in transfer.
								 */
								if (numFields)
								  /* Some fields were found and examined */
								  endSearch = true;
								 else
								  {
									/* The screen buffer is unformatted: we must
									 * transfer entire buffer (check for Yale NULL
									 * processing */
									for (fromPos=0; fromPos<size3270Buf;fromPos++)
									 {
									  if (charBuffer[fromPos] != NULL)
										{
										 if ((netOutMax-netCount) > 2 )
										  {
											*netBufPtr++ = charBuffer[fromPos];
											netCount++;
										  }
										  else return IDS_RINGBUFFERFULL;
										}
										else
										 {
										  /* If Yale Null Process Option is Set then
											  Should transform all nulls to blank chars */
										  if (connData->actYale)
											{
											 if ((netOutMax-netCount) > 2 )
											  {
												*netBufPtr++ = EBCDICBLANK;
												netCount++;
											  }
											  else return IDS_RINGBUFFERFULL;
											}
										 }
									 }
									endSearch = true;
								  }
							  }
							  /* else the search must continue until first field
								* processed is reached */
							}
						 }
						 break;
	case SHORTREAD: /* Short Read Operation: Supply only the AID Byte */
						 if ((netOutMax-netCount) > 1)
						  {
							*netBufPtr++ = lastAID;
							netCount++;
						  }
						  else return IDS_RINGBUFFERFULL;
						 break;

	case  QUERYREPLY: /* Query Reply Data as Answer of Read Partition */
							/* Check For Query Reply or Query Reply List */
                     {
                      char* qReplyList = queryReplyList;
                      int rCode;
                      if (!qReplyList)
                       {
                        rCode = SendQueryReply(&netBufPtr, &netCount, netOutMax, QUERYREPLY);
                        if (rCode != DATASENT)
                          return rCode;
                        break;
                       }
                      else
                       {
                        /* This an Query Reply List:
                         * Check REQTYP on 1st queryReplyList Byte */
                        if (!(*qReplyList & 0xc0))   // Test for B'00' ReqType
                         {
                          // QCODE List - List of Query Replies to send
                          int qCount = 0;
                          bool alreadySent = false;
                          char qReplySent[128];
                          qReplyList++;
                          rCode = SendQueryReply(&netBufPtr, &netCount, netOutMax, QUERYREPLYHDR);
                          while ((*qReplyList != 0xFF) && (rCode == DATASENT))
                           {
                            // Verify if query reply has already sent
                            for (int i=0; i < qCount; i++)
                             {
                              if (*qReplyList == qReplySent[i])
                               {
                                alreadySent = true;
                                break;
                               }
                             }
                            // if it was not yet sent try to send it .....
                            if (!alreadySent)
                             {
                              rCode = SendQueryReply(&netBufPtr, &netCount, netOutMax, *qReplyList);
                              if (rCode == DATASENT)
                               {
                                qReplySent[qCount] = *qReplyList;
                                qCount++;
                                qReplyList++;
                               }
                             }
                            else
                             {
                              alreadySent = false;
                              qReplyList++;
                             }
                           } // while ///

                          if (qCount == 0)
                            rCode = SendQueryReply(&netBufPtr, &netCount, netOutMax, QUERYREPLYNULL);

                          if (rCode != DATASENT)
                           return rCode;
                         }
                        else if ((*qReplyList & 0x40) // Test for B'01' ReqType - // EQUIVALENT - Same as Query Reply
                               ||(*qReplyList & 0x80)) // Test for B'10' ReqType - // ALL - All query replies supported
                         {
                          // EQUIVALENT - Same as Query Reply
                          rCode = SendQueryReply(&netBufPtr, &netCount, netOutMax, QUERYREPLY);
                          if (rCode != DATASENT)
                            return rCode;
                         }
                        else
                         {
                          rCode = SendQueryReply(&netBufPtr, &netCount, netOutMax, QUERYREPLYNULL);
                          if (rCode != DATASENT)
                            return rCode;

                         }
                        break;
                       }
                     }

	case SENSE1003: /* Sense X'1003' -> Command Reject */
                   {
						  if ((netOutMax-netCount) > 3)
						   {
							 *netBufPtr++ = NOAIDGEN;
							 *netBufPtr++ = 0x10;
							 *netBufPtr++ = 0x03;
							 netCount+=3;
						   }
						  else return IDS_RINGBUFFERFULL;
						  break;
                   }

	default      : /* Nothing to do: ignore command */
						return IDS_INVALIDTONETMODE;
  }
 /* Update Buffer With Network Stream Data To Send */
 pNetOutBuf->ring_supplied(netCount);
 return DATASENT;
}

int
ALFF3270::SendQueryReply(char** netBufPtr, int* netCount,
                            const int netOutMax, const int qCode)
{
 /*
  * LU2 Query Replies (LU1 and LU3 are processed in ALFFRemotePrt Class)
  */
 /*-----------------------------------------------------------------------*/
 unsigned char replySummary[14] =
 {
  /*Summary (Query Reply Codes Accepted)
							 Summary (SAA Support)
							 |    Usable Area (SAA Support)
							 |	  	|    Character Sets (SAA Support)
							 |	   |    |    Colors
							 |    |    |    |    HighLighting
							 |		| 	  |    |	   |	  Reply Modes
				Summary   |    |    |    |	   |	  |	 Field Validation
				|         |    |    |    |    |    |    |    Dist Data Manag (DDM)
  Length    |      	 |		|    |    |	   |	  |	 |    |    Data Chaining
  |			|			 |		|    |    |	   |    |    |	   |    |	 Implicit Partitions (SAA Support) */
  0x00,0x0E,0x81,0x80,0x80,0x81,0x85,0x86,0x87,0x88,0x8A,0x95,0x98,0xA6
  };

 /*-----------------------------------------------------------------------*/
  unsigned char replyUsable[23] =
  {
  /* Usable Area Query Reply Base
									Flag                     Units
							 Flag |A   |Area     |Area     |A
							 |12  |l   |Width    |Height   |l   Points
							 |-   |w   |(+6)     |(+8)     |w   |Al
				Usable    |14  |a   |         |         |a   | wa
  Length    Area      |Bit |y   |         |         |y   |   ys
  |         |         |Adr |s   |         |         |s   |         */
  0x00,0x17,0x81,0x81,0x01,0x00,0x00,0x50,0x00,0x18,0x00,0x00,0x0A,

  /*                                      BuffSize (+21)
  |  Cell Points Sizes...     | Cell Cell | Mod2 (24*80)  = 0x07,0x80
  |     A l                   | X    Y    | Mod3 (32*80)  = 0x0a,0x00
  |          w a              | UnitsUnits| Mod4 (43*80)  = 0x0d,0x07
  |               y s         | |    |    | Mod5 (27*132) = 0x0d,0xec  */
  0x02,0xE5,0x00,0x02,0x00,0x6F,0x09,0x0C,0x07,0x80
  };

  /*-----------------------------------------------------------------------*/
  unsigned char replyCharSet[20] =
  {
  /*        Character Sets      Default Char Slot
  Length    |      	 Flags     |    Height                   |Symbol set
  |			|			 |         |Width    |Load PS            |Descriptor
  |         |         |         |         |(not supported)    |Length      */
  0x00,0x14,0x81,0x85,0x02,0x00,0x09,0x0C,0x00,0x00,0x00,0x00,0x07,
  /*           *      |
               *      This version does not support Graphic Escape (GE)
               *      as it is indicated on Flags field above.
               *      When support to GE is added the Flag value MUST be
               *      changed from '0x02,0x00' to '0x82,0x00'.
               *      Its implementation is under evaluation as GE codepoints
               *      refers to APL symbols,as stated on page
               *      http://x3270.bgp.nu/Charset.html
               *      May be on version 4 it will be available.
               */
  /*   Flag      | ---- CGCSGID ---- |
  Set  |    LCID |CECP     |Code Page
  | Id |    |    |695      |1140 (Old CP037 + Euro Sign)            */
  0x00,0x00,0x00,0x02,0xb7,0x04,0x74
  /* On next version, when GE is ready to be accepted, we must supply
   * following descriptor for APL Character Set:
   *
   *     Flag      | ---- CGCSGID ---- |
    Set  |    LCID |CECP     |Code Page
    | Id |    |    |963      | 310 (APL)
    0x01,0x00,0xF1,0x03,0xc3,0x01,0x36                            */
  };

 /*-----------------------------------------------------------------------*/
  unsigned char replyNoColors[38] =
  {
  /* Colors Supported Query Reply
									List |- C o l o r s ...
									|L   | A  D    |         |
							 Flag |e   | c  i    |         |
							 |    |n   | c  s    |         |
							 |    |g   | e  p    |         |
  Length    Colors    |    |t   | p  l    |A   D    |A   D
  |         |         |    |h   | t  y    |c   s    |c   s         */
  0x00,0x26,0x81,0x86,0x00,0x10,0x00,0xf4,0xf1,0x00,0xf2,0x00,
/*| C o l o r s (contd.)
  |A   D    |A   D    |A   D    |A   D    |A   D    |A   D
  |c   s    |c   s    |c   s    |c   s    |c   s    |c   s    */
  0xf3,0x00,0xf4,0x00,0xf5,0x00,0xf6,0x00,0xf7,0x00,0xf8,0x00,
/*|A   D    |A   D    |A   D    |A   D    |A   D    |A   D
  |c   s    |c   s    |c   s    |c   s    |c   s    |c   s    */
  0xf9,0x00,0xfa,0x00,0xfb,0x00,0xfc,0x00,0xfd,0x00,0xfe,0x00,
/*
  |A   D
  |c   s  */
  0xff,0x00
  };

 /*-----------------------------------------------------------------------*/
  unsigned char replyColors[42] =
  {
  /* Colors Supported Query Reply
									List |- C o l o r s ...
									|L   | A  D    |         |
							 Flag |e   | c  i    |         |
							 |    |n   | c  s    |         |
							 |    |g   | e  p    |         |
  Length    Colors    |    |t   | p  l    |A   D    |A   D
  |         |         |    |h   | t  y    |c   s    |c   s         */
  0x00,0x2A,0x81,0x86,0x00,0x10,0x00,0xf4,0xf1,0xf1,0xf2,0xf2,
/*| C o l o r s (contd.)
  |A   D    |A   D    |A   D    |A   D    |A   D    |A   D
  |c   s    |c   s    |c   s    |c   s    |c   s    |c   s    */
  0xf3,0xf3,0xf4,0xf4,0xf5,0xf5,0xf6,0xf6,0xf7,0xf7,0xf8,0xf8,
/*|A   D    |A   D    |A   D    |A   D    |A   D    |A   D
  |c   s    |c   s    |c   s    |c   s    |c   s    |c   s    */
  0xf9,0xf9,0xfa,0xfa,0xfb,0xfb,0xfc,0xfc,0xfd,0xfd,0xfe,0xfe,
/*          Self Defining Background Color
				|    DBg	 Bkgd Color
  |A   D    Len  Id   Def  Color
  |c   s    |    |    |Id  |Val  */
  0xff,0xff,0x04,0x02,0x00,0xf0
  };

  unsigned char replyHighLight[15] =
  {
  /* HighLighting Supported Query Reply
							 List |- E f f e c t s ...
							 |L   | A  E    |         |         |
							 |e   | c  f    |         |         |
							 |n   | c  f    |         |         |
							 |g   | e  e    |         |         |
  Length    HighLght  |t   | p  c    |A   E    |A   E    |A   E
  |         |         |h   | t  t    |c   f    |c   f    |c   f     */
  0x00,0x0f,0x81,0x87,0x05,0x00,0xf0,0xf1,0xf1,0xf2,0xf2,0xf4,0xf4,
/*|A   E
  |c   f     */
  0xf8,0xf8
  };

  unsigned char replyModes[6] =
  {
  /* Reply Modes
									Extended Field Mode
				Summary        |
  Length    |      	 Field|      Character Mode
  |			|			 |Mode|      |                             */
  0x00,0x06,0x81,0x88,0x00,0x01 //,0x02,
  };

  unsigned char replyFdValidation[5] =
  {
  /*        Field Validation
  Length    |      	 Types(Mandatory Fill Not Supported)
  |			|			 |    (Mandatory Entry    "        )
  |         |         |    (Trigger            "        )       */
  0x00,0x05,0x81,0x8A,0x00
  };

  unsigned char replyDDM[12] =
  {
  /*        Distributed Data Management             DDMSS
  Length    |      	 Flag      |   L i m i t s     |N   DDM Subset IDs
  |			|			 |(Zeroes) | Max     | Max     |u   |
  |         |         |         | Inbound |Outbound |m   |          */
  0x00,0x0c,0x81,0x95,0x00,0x00,0x20,0x00,0x20,0x00,0x01,0x01
  };

  unsigned char replyChaining[6] =
  {
  /*        Data Chaining
  Length    |      	 DIRection
  |			|			 |(To Device Only)
  |         |         |    | Flags(Always zeroes) */
  0x00,0x06,0x81,0x98,0x80,0x00
  };

  unsigned char replyImplicitPart[17] =
  {
  /*        Implicit            Self-Defining Parameter
  Length    |Parti-   Flags     |    For  |F   |- Default Screen -|
  |			| tion	 |Always   |    Part |l   |Chars(+9)|Chars(+11)
  |         |         |Zeroes   |    Size |a   |Width    |Height  |
  |         |         |         |    |    |g   | (80)    | (24)   |	*/
  0x00,0x11,0x81,0xa6,0x00,0x00,0x0b,0x01,0x00,0x00,0x50,0x00,0x18,  /*
  |- Altern. Screen -|
  |Chars(+13)Chars(+15)
  |Width   | Height | */
  0x00,0x84,0x00,0x1b
  };

  unsigned char replyNull[4] =
  {
  /*        Field Validation
  Length    |
  |			|
  |         |    |  Null (No features queried supported)  */
  0x00,0x04,0x81,0xFF
  };

 /*
  *  Set Network Output Buffer Controls
  */

#define QUERYREPLYLU2LENGTH    142     // =  10+23+20+13+5+40

/* Check For Query Reply or Query Reply List */
 switch (qCode)
  {
    case QUERYREPLY:
      {
       if (netOutMax > QUERYREPLYLU2LENGTH)
        {
			 /* Set Structured Field Reply AID */
		    **netBufPtr = AIDSTRFIELD;
          *netBufPtr +=1;
		    *netCount+=1;

  		    /* Send Query Reply Summary Structured Field */
			 memcpy(*netBufPtr,replySummary,14);
			 *netBufPtr+=14;
			 *netCount+=14;

			 /* Send Query Reply Usable Area Structured Field */
			 memcpy(*netBufPtr,replyUsable,23);
			 //Set Width
			 memcpy(*netBufPtr+6,(char*)(&altScrLineSize)+1,1);
			 memcpy(*netBufPtr+7,&altScrLineSize,1);
			 //Set Height
			 memcpy(*netBufPtr+8,(char*)(&altScrNumLines)+1,1);
			 memcpy(*netBufPtr+9,&altScrNumLines,1);
			 //Set BufferSize
			 unsigned short sizeBuf = altScrLineSize*altScrNumLines;
			 memcpy(*netBufPtr+21,(char*)(&sizeBuf)+1,1);
			 memcpy(*netBufPtr+22,&sizeBuf,1);
			 *netBufPtr+=23;
			 *netCount+=23;

			 /* Send Query Reply Character Set (SAA Support) */
			 memcpy(*netBufPtr,replyCharSet,20);
			 *netBufPtr+=20;
			 *netCount+=20;

			 /* Send Query Reply Colors Structured Field */
			 if (colorTerminal)
			  {
			 	memcpy(*netBufPtr,replyColors,42);
			 	*netBufPtr+=42;
			 	*netCount+=42;
			  }
          else
           {
  			 	memcpy(*netBufPtr,replyNoColors,38);
			 	*netBufPtr+=38;
			 	*netCount+=38;
           }

			 /* Send Query Reply HighLight Structured Field */
			 if (extendedAttribute)
			  {
			 	memcpy(*netBufPtr,replyHighLight,15);
			 	*netBufPtr+=15;
			 	*netCount+=15;
			  }

			 /* Send Query Reply Modes Structured Field */
			 memcpy(*netBufPtr,replyModes,6);
			 *netBufPtr+=6;
			 *netCount+=6;

			 /* Send Query Reply Field Validation Structured Field */
			 memcpy(*netBufPtr,replyFdValidation,5);
			 *netBufPtr+=5;
			 *netCount+=5;

			 /* Send Query Reply DDM Structured Field */
			 memcpy(*netBufPtr,replyDDM,12);
			 *netBufPtr+=12;
			 *netCount+=12;

			 /* Send Query Reply Chaining Structured Field */
			 memcpy(*netBufPtr,replyChaining,6);
			 *netBufPtr+=6;
			 *netCount+=6;

			 /* Send Query Reply Implicit Partition Structured Field */
			 memcpy(*netBufPtr,replyImplicitPart,17);
			 //Set Default Scr Width
			 memcpy(*netBufPtr+9,(char*)(&defScrLineSize)+1,1);
			 memcpy(*netBufPtr+10,&defScrLineSize,1);
			 //Set Default Scr Height
			 memcpy(*netBufPtr+11,(char*)(&defScrNumLines)+1,1);
			 memcpy(*netBufPtr+12,&defScrNumLines,1);
			 //Set Alternate Scr Width
			 memcpy(*netBufPtr+13,(char*)(&altScrLineSize)+1,1);
			 memcpy(*netBufPtr+14,&altScrLineSize,1);
			 //Set Alternate Scr Height
			 memcpy(*netBufPtr+15,(char*)(&altScrNumLines)+1,1);
			 memcpy(*netBufPtr+16,&altScrNumLines,1);
          *netBufPtr+=17;
			 *netCount+=17;
          break;
		  }
       else return IDS_RINGBUFFERFULL;
		}

    case QUERYREPLYHDR:
     {
		/* Set Structured Field Reply AID */
		**netBufPtr = AIDSTRFIELD;
      *netBufPtr +=1;
		*netCount+=1;
      break;
     }

    case QUERYSUMMARY:
     {
      /* Send LU2 Query Reply Summary Structured Field */
	   memcpy(*netBufPtr,replySummary,14);
	   *netBufPtr+=14;
	   *netCount+=14;
      break;
     }

    case QUERYUSABLE:
     {
		memcpy(*netBufPtr,replyUsable,23);
		//Set Width
		memcpy(*netBufPtr+6,(char*)(&altScrLineSize)+1,1);
		memcpy(*netBufPtr+7,&altScrLineSize,1);
		//Set Height
		memcpy(*netBufPtr+8,(char*)(&altScrNumLines)+1,1);
		memcpy(*netBufPtr+9,&altScrNumLines,1);
		//Set BufferSize
		unsigned short sizeBuf = altScrLineSize*altScrNumLines;
		memcpy(*netBufPtr+21,(char*)(&sizeBuf)+1,1);
		memcpy(*netBufPtr+22,&sizeBuf,1);
		*netBufPtr+=23;
		*netCount+=23;
      break;
     }

    case QUERYCHARACTERSET:  // Same for LU1 and LU3
     {
		/* Send Query Reply Character Set (SAA Support) */
		memcpy(*netBufPtr,replyCharSet,20);
		*netBufPtr+=20;
		*netCount+=20;
      break;
     }

    case QUERYCOLORS:
     {
      /* Send Query Reply Colors Structured Field */
		if (colorTerminal)
		 {
		  memcpy(*netBufPtr,replyColors,42);
		  *netBufPtr+=42;
		  *netCount+=42;
        break;
		 }
      else return DATANOTSENT;
     }

    case QUERYHIGHLIGHTING:  // Same for LU1, LU2 and LU3
     {
		/* Send Query Reply HighLight Structured Field */
		if (extendedAttribute)
		 {
		  memcpy(*netBufPtr,replyHighLight,15);
		  *netBufPtr+=15;
		  *netCount+=15;
        break;
		 }
      else return DATANOTSENT;
     }

    case QUERYREPLYMODES:  // LU3 Only
     {
		/* Send Query Reply Modes Structured Field */
		memcpy(*netBufPtr,replyModes,6);
		*netBufPtr+=6;
		*netCount+=6;
      break;
     }

    case QUERYFIELDVALIDAT:
     {
		/* Send Query Reply Field Validation Structured Field */
		memcpy(*netBufPtr,replyFdValidation,5);
		*netBufPtr+=5;
		*netCount+=5;
      break;
     }

    case QUERYDDM:
     {
		/* Send Query Reply DDM Structured Field */
		memcpy(*netBufPtr,replyDDM,12);
		*netBufPtr+=12;
		*netCount+=12;
      break;
     }

    case QUERYDATACHAINING:
     {
		/* Send Query Reply Chaining Structured Field */
		memcpy(*netBufPtr,replyChaining,6);
		*netBufPtr+=6;
		*netCount+=6;
      break;
     }

    case QUERYIMPLICITPART:
     {
		/* Send Query Reply Implicit Partition Structured Field */
		memcpy(*netBufPtr,replyImplicitPart,17);
		//Set Default Scr Width
		memcpy(*netBufPtr+9,(char*)(&defScrLineSize)+1,1);
		memcpy(*netBufPtr+10,&defScrLineSize,1);
		//Set Default Scr Height
		memcpy(*netBufPtr+11,(char*)(&defScrNumLines)+1,1);
		memcpy(*netBufPtr+12,&defScrNumLines,1);
		//Set Alternate Scr Width
		memcpy(*netBufPtr+13,(char*)(&altScrLineSize)+1,1);
		memcpy(*netBufPtr+14,&altScrLineSize,1);
		//Set Alternate Scr Height
		memcpy(*netBufPtr+15,(char*)(&altScrNumLines)+1,1);
		memcpy(*netBufPtr+16,&altScrNumLines,1);
      *netBufPtr+=17;
		*netCount+=17;
      break;
     }

    case QUERYREPLYNULL:
      {
       /*  Send Query Reply Null */
       memcpy(*netBufPtr,replyNull,4);
       netBufPtr+=4;
       netCount+=4;
      }

    default:  return DATANOTSENT;
  }
 return DATASENT;
}

COLORREF
ALFF3270::SetTextColor(unsigned char fdAttr)
{
 if (fdAttr & 0x20) /* Is it protected */
  {
   if ((fdAttr & 0x08) && (!(fdAttr & 0x04)) ) /* Is it high intensity */
	   return connData->scrHighlightProtTextColor;
	else return connData->scrNormalProtTextColor;
  }
 /* Unprotected Fields */
 else if ((fdAttr & 0x08) && (!(fdAttr & 0x04)) ) /* Is it high intensity */
		  return connData->scrHighlightUnprotTextColor;
 else return connData->scrNormalUnprotTextColor;
}

unsigned char
ALFF3270::ConvertToAscii(unsigned char pos)
{
 return tabEBCtoASC[pos];
}

unsigned char
ALFF3270::ConvertToEBCDIC(unsigned char pos)
{
 return tabASCtoEBC[pos];
}

bool
ALFF3270::SetExtendedAttr(Field& field, ScreenPos& pos, const int code)
{
 /* Copy field specific attributes not related to char attrs */
 field.fdBkgdTransparency = pos.bgTransparency;
 field.fdValidation = pos.fieldValidation;
 field.fdOutlining = pos.fieldOutlining;
 int fieldBegin = pos.fieldBeginAt;

 if (pos.posAttr == PSEUDOFIELD)
  {
	/* Set Extended HighLight Attribute                  */
	if (pos.extendedHighLight != defaultHighLight)
	  field.fdEffects = pos.extendedHighLight;
	else field.fdEffects = screenBuffer[fieldBegin].extendedHighLight;

	/* Set Extended Pseudo Field Text and BackGround Colors */
	if (code == UNDOTXT)
	 {
	  field.fdTextColor = pos.charColor;
	  field.fdBkgdColor = pos.bkgdColor;
	 }
	else
	 {
	  /* Not an UNDOTXT Field So We MUST check defaults */

	  // BackGround Color //
	  if (pos.bkgdColor != DEFAULTCOLOR)
		 field.fdBkgdColor  = GetColor(pos.bkgdColor);
	  else
		{
		 unsigned char color = screenBuffer[fieldBegin].bkgdColor;
		 if (color != DEFAULTCOLOR)
			field.fdBkgdColor  = GetColor(color);
		 else field.fdBkgdColor = connData->scr3270BkgdColor;
		}
	  // Char Color //
	  if (pos.charColor != DEFAULTCOLOR)
		field.fdTextColor  = GetColor(pos.charColor);
	  else
		{
		 unsigned char color = screenBuffer[fieldBegin].charColor;
		 if (color != DEFAULTCOLOR)
			field.fdTextColor  = GetColor(color);
		 else field.fdTextColor = SetTextColor(screenBuffer[fieldBegin].fieldAttr);
		}
	 }

	return true;
  }
  else  // It is an regular field (SF or SFE) //
	{
	 /* Set Extended HighLight Attribute                  */
	 field.fdEffects = pos.extendedHighLight;

	 if (code == UNDOTXT)
	  {
		field.fdTextColor = pos.charColor;
		field.fdBkgdColor = pos.bkgdColor;
	  }
	 else
	  {
		/* Set Extended Pseudo Field Bkgd Color              */
		unsigned char color = screenBuffer[fieldBegin].bkgdColor;
		if (color != DEFAULTCOLOR)
			field.fdBkgdColor  = GetColor(color);
		else field.fdBkgdColor = connData->scr3270BkgdColor;

		/* Set Extended Pseudo Field Text Color              */
		color = screenBuffer[fieldBegin].charColor;
		if (color != DEFAULTCOLOR)
		  field.fdTextColor  = GetColor(color);
		else field.fdTextColor = SetTextColor(screenBuffer[fieldBegin].fieldAttr);

	  }
	 return false;
	}
}

bool
ALFF3270::SetIgnoreAttr(Field& field, int fieldBeginAt)
{
 /* Copy field specific attributes not related to char attrs */
 field.fdBkgdTransparency = TPDEFAULT;
 field.fdValidation = FVNONE;
 field.fdOutlining = FONOOUTLINE;
 int fieldBegin = fieldBeginAt;

 field.fdEffects = EHDEFAULT;
 field.fdTextColor  = TColor::Black;
 field.fdBkgdColor = TColor::White;
 return true;
}

Field*
ALFF3270::DataToScreen(int& fromPos, const int option,
								  const int suboption, const int code,
                          bool noAttrb, bool eabXlat, bool noDisplay)
{
 char *fieldText = NULL;
 char *fieldTextBeg = NULL;
 char posChar;
 bool  fieldInited = false;
 bool  endField = false;
 bool  bufferFormatted = true;
 unsigned char fieldAttr;
 bool  fdNodisp = false;
 int   initPos = 0;

 /* Prepare Buffer searching end position */
 int endPos = 0;
 if (fromPos != 0)
	 endPos = fromPos-1;
  else endPos = size3270Buf-1;

 if (scrField.fdText)
  {
	delete [] scrField.fdText;
	scrField.fdText = NULL;
  }

 /* Create Text Field To Store Buffer Characters */
 fieldTextBeg = fieldText = new char[size3270Buf+(altScrNumLines*2)+1];
 memset(fieldText,NULL,size3270Buf+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 */
	screenPos = screenBuffer[GetPrevAttrPos(initPos)];

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

	/* Set Extended Field Attributes         */
   // WHLLAPI
   if (!eabXlat)
     // Extended attribute bytes are copied as received from host.
     SetExtendedAttr(scrField, screenPos, UNDOTXT);
   else
     // Extended attribute bytes are copied and translated into CGA colors,
     // depending upon "code". When called from WHLLAPI code is always "ASCII",
     // and needed translation is done.
	  SetExtendedAttr(scrField, screenPos, code);

	/* Get Actual Field Attribute Nondisplayable Status */
	fieldAttr = screenBuffer[screenPos.fieldBeginAt].fieldAttr;
	fdNodisp = ((fieldAttr & 0x08) && (fieldAttr & 0x04));

////////////////////////////////////////////////////////////////////////////

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

	  if (code == UNDOTXT)
		{
		 if (posChar == NULL)
			posChar = EBCDICNULL;
		 *fieldText++ = posChar;
		}
		else *fieldText++ = ConvertToAscii(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)
		 {
		  if (!fdNodisp)
			  posChar = charBuffer[initPos];
		  else  posChar = EBCDICBLANK;
		  if (code == UNDOTXT)
			 {
			  if (posChar == NULL)
				posChar = EBCDICNULL;
			  *fieldText++ = posChar;
			 }
			else *fieldText++ = ConvertToAscii(posChar);
		  *fieldText = NULL;
		  if (initPos == endPos)
			{
			 endWhile = true;
			 fromPos = -1;
			}
		  else
			{
			 initPos = NextBufPos(initPos);

			 /* If next position has Char attributes screen field is ended */
			 if (screenBuffer[initPos].posAttr == PSEUDOFIELD)
			  {
				fromPos = initPos;
				endWhile = true;
			  }
			}
		 }
	  }
	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" */
	screenPos = screenBuffer[GetPrevAttrPos(initPos)];

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

	/* Set Extended Field Attributes                 */
	SetExtendedAttr(scrField, screenPos, code);

   /* Get Actual Field Attribute Nondisplayable Status */
	fieldAttr = screenBuffer[screenPos.fieldBeginAt].fieldAttr;
	fdNodisp = ((fieldAttr & 0x08) && (fieldAttr & 0x04));


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

       *fieldText++ = ConvertToAscii(posChar);
      }
	  *fieldText = NULL;

	  if (initPos < endPos)
		{
		 initPos = NextBufPos(initPos);
		 /* If next position has Char attributes screen field is ended */
		 if ( (screenBuffer[initPos].posAttr == PSEUDOFIELD)
		  && (suboption != JUSTTEXT) )
		  {
			fromPos = initPos;
			endWhile = true;
		  }
		 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).
	 */
	fieldInited = false;
	endField    = false;
	while (!endField)
	 {
	  if ((fromPos == endPos)
			|| (charBuffer[fromPos] == SF)
			|| (charBuffer[fromPos] == SFE)
			|| (screenBuffer[fromPos].posAttr == PSEUDOFIELD))
		{
		 if (fieldInited)
		  {
			if (fromPos == endPos)
			 {
			  if (!fdNodisp)                         
				 posChar = charBuffer[fromPos];
			  else  posChar = EBCDICBLANK;
			  *fieldText++ = ConvertToAscii(posChar);
			  /* All Buffer Was searched: fromPos must have first field position */
			  fromPos = NextBufPos(fromPos);
			 }
			*fieldText = NULL;
			endField = true;
			fieldInited=false;
		  }
		 else
		  {
			if (fromPos == endPos)
			 {
			  /* 3270 buffer isn't formatted. Entire buffer will be the field */
			  fromPos = initPos;
			  endPos = size3270Buf-1;
			  bufferFormatted = fdNodisp = false;
			 }
			 else endPos = PrevBufPos(fromPos);

			fieldInited=true;
			posChar   = charBuffer[fromPos];
			screenPos = screenBuffer[fromPos];
			scrField.fdPosition.y = fromPos / scrLineSize;
			scrField.fdPosition.x = fromPos - (scrField.fdPosition.y*scrLineSize);

			/* Set Extended Field Attributes                 */
			SetExtendedAttr(scrField, screenPos, code);

         /* Get Actual Field Attribute Nondisplayable Status */
			fieldAttr = screenPos.fieldAttr;
			fdNodisp = ((fieldAttr & 0x08) && (fieldAttr & 0x04));

         /* Check for intense field attr for setting highlight effect
          * for using on PrintField method of ALFFPrintout and
          * DisplayField method of ALFFVirtualTerm.
          */
         if ((fieldAttr & 0x08) && (!(fieldAttr & 0x04)) )
            scrField.fdEffects |= EHHIGHLIGHT;

			if (!bufferFormatted)
			 {
			  scrField.fdFormatted=false;
			  *fieldText++ = ConvertToAscii(posChar);
			 }
			else
			 {
			  if (screenPos.posAttr == PSEUDOFIELD)
				 {
				  scrField.fdFormatted=false;
              if (isPrinter)
               {
                // Note:  EPM is the 3270 printer EM control code
                if ((posChar == FF) || (posChar == NL)
                  ||(posChar == CR) || (posChar == EPM) )
                  *fieldText++ = posChar;
                else *fieldText++ = ConvertToAscii(posChar);
               }
              else *fieldText++ = ConvertToAscii(posChar);
				 }
			  else scrField.fdFormatted=true;
			 }
			fromPos = NextBufPos(fromPos);
		  }
		}
		else
		{
		 if (fieldInited)
		  {
			if (!fdNodisp)
				posChar = charBuffer[fromPos];
			else posChar = EBCDICBLANK;
			*fieldText++ = ConvertToAscii(posChar);
			fromPos = NextBufPos(fromPos);
		  }
		 else 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
ALFF3270::DataToPrinter(ALFFPrinterBuffer* printerBuf)
{
 char  *fieldText = NULL;
 char  *fieldTextBeg = NULL;
 char  posChar;
 bool  fieldInited = false;
 bool  endField = false;
 unsigned char fieldAttr;
 bool  fdNodisp = false;

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

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

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

 /* Set the correct page line size:
  *   if wcc set the line size it must be used
  *   else 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 defined.
  */
 int streamLineSize;
 if (IsWCCLineFormatted())
    streamLineSize = GetStreamLineSize();
 else if (connData->printerCharPerLine)
   streamLineSize = connData->printerCharPerLine;
 else streamLineSize = GetStreamLineSize();

 int addRC = 0;   // ALFFPrinterBuffer StoreField Return Code
 int currentCol = 0, fromBufPos = 0;

 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] == SF)
		|| (charBuffer[fromBufPos] == SFE)
		|| (screenBuffer[fromBufPos].posAttr == PSEUDOFIELD)

      // Valid End of Printing Buffer
      // Note:  EPM is the 3270 printer EM control code
      || ((charBuffer[fromBufPos] == EPM) && (!IsWCCLineFormatted()))

      || (fromBufPos == endBufPos)
      || ((connData->printerBreakLine) && (currentCol > streamLineSize)) )
      /* When the streamLineSize is set by WCC connData->printerBreakLine is
       * set to true by ProcessWCC method */
		{
		 if (fieldInited)
		  {
			if (fromBufPos == endBufPos)
			 {
			  /* All Buffer Was searched:
              No More fields available to print   */
			  if (!fdNodisp)
				 posChar = charBuffer[fromBufPos];
			  else  posChar = EBCDICBLANK;

           //Checking for null as space option
           if ((connData->printerNullAsSpace)
             &&(posChar == NULL) )
               *fieldText++ = ASCIIBLANK;
           else *fieldText++ = ConvertToAscii(posChar);

			  endStoring = true;
			 }
         // Note:  EPM is the 3270 printer EM control code
         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 // !fieldInited
		  {
			posChar   = charBuffer[fromBufPos];
			screenPos = screenBuffer[fromBufPos];

			if ( (fromBufPos == 0)
           && (posChar != SF)
			  && (posChar != SFE) )
          {
           // First Field always begin on buffer position 0
           screenBuffer[fromBufPos].posAttr = PSEUDOFIELD;
          }

         // Init this field
			fieldInited=true;

         /* Set Extended Field Attributes                 */
         if (!connData->printerIgnoreAttr)
			   SetExtendedAttr(fdStore, screenPos, ASCII);
         else SetIgnoreAttr(fdStore, screenPos.fieldBeginAt);

         /* Get Actual Field Attribute & Nondisplayable Status */
			fieldAttr = screenPos.fieldAttr;
			fdNodisp = ((fieldAttr & 0x08) && (fieldAttr & 0x04));

         /* Check for intense field attr for setting bold effect */

         if (!connData->printerIgnoreAttr)
          {
           if ((fieldAttr & 0x08) && (!(fieldAttr & 0x04)) )
              fdStore.fdEffects |= EHHIGHLIGHT;
          }

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

         // Update Current column control
         currentCol = fdStore.fdPosition.x;

         // Checking for pseudoFields ....
			if (screenPos.posAttr == PSEUDOFIELD)
			 {
           /*  NOT FORMATTED PRINTING:
            *  On DataFromNetwork method, NL and CR orders are handled as
            *  PseudoFields, and set as it, but only when they are valid,
            *  that is, when line size wasn't set by WCC. */
           fdStore.fdFormatted=false;
           if (  (posChar == FF)
            || (((posChar == NL)
            || (posChar == CR)) && (!IsWCCLineFormatted()) ) )
            {
             // 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"
             switch (posChar)
              {
               case CR:  /* Negative or Positive Print Offset, depending upon
                          * user defined option.
                          * Checking if CR is on MPP+1, for adding, or not,
                          * the line break, depending upon user defined option,
                          * connData->printerEndLineCR
                          */
                         if  ((connData->printerBreakLine)
                           && (currentCol > streamLineSize))
                           {
                            //Checking for endline suppressing when its first pos is CR
                            if (!connData->printerEndLineCR)
                              fdStore.fdPosition.y += 1;
                           }
                         /* (fromBufPos+1) means that order will not be printed as space */
                         printFormatOffset = (fdStore.fdPosition.y*streamLineSize)-(fromBufPos+1);

                         fdStore.fdPosition.x = 0;
                         currentCol = 0;
                         break;
               case NL:  /* Positive Print Offset:
                          *
                          * Checking if CR is on MPP+1, for adding, or not,
                          * the line break, depending upon user defined option,
                          * connData->printerEndLineNL
                          */
                         // At least 1 line will be added
                         addedLines = 1;
                         if  ((connData->printerBreakLine)
                           && (currentCol > streamLineSize))
                           {
                            //Checking for endline suppressing when its first pos is CR
                            if (!connData->printerEndLineNL)
                             {
                              //fdStore.fdPosition.y += 1;
                              addedLines++;
                             }
                           }

                         if (printFormatOffset == 0)
                           printFormatOffset = ((fdStore.fdPosition.y+addedLines)*streamLineSize)-fromBufPos-1;
                         else printFormatOffset += (streamLineSize*addedLines)-fdStore.fdPosition.x-1;

                         /* New horizontal offset will be 0 (new Line) */
                         fdStore.fdPosition.x = 0;
                         currentCol = 0;
                         fdStore.fdPosition.y += addedLines;
                         if (fdStore.fdPosition.y > (connData->printerLinePerPage-1))
                           {
                            printFormatOffset = -(fromBufPos+1);
                            pageNumber += 1;
                           }
                         break;

               case FF:  if ((connData->printerIgnoreFF)
                           && (fromBufPos == 0) )
                          {
                           /* Ignore FF on page first print position if it was set */
                           break;
                          }

                         /* If is out of column 1 of current line and
                          * FF at any Position was not set, so FF will be processed
                          * as an blank char and will not skip to next page */
                         if ((!connData->printerFFAnyPos)
                           && (currentCol != 0) )
                          {
                           *fieldText++ = ASCIIBLANK;
                           currentCol++;
                           break;
                          }

                         /* If the option print FF as Space is on then FF position
                          * will be printed as Space and will take one print position */
                         if (connData->printerFFAsSpace)
								  fdStore.fdPosition.x = 1;
                         else fdStore.fdPosition.x = 0;
                         currentCol = fdStore.fdPosition.x;
                         
                         // Do  Processing FF
                         fdStore.fdPosition.y = 0;
                         pageNumber += 1;

                         /* On new page fromBufPos will be "zero" offset */
                         /* (fromBufPos+1) means that order will not be printed as space */
                         printFormatOffset = -(fromBufPos+1);

                         break;
               // Something was wrong .....
               default:  fdStore.fdPosition.x = -1;
                         fdStore.fdPosition.y = -1;
                         break;
              } // switch (posChar)

             currentCol = fdStore.fdPosition.x;

            } // if (posChar == FF) || ...... || .....
           else
            {
             // "Regular"  Pseudo Field:  No coordinates adjust is needed
             //Checking for null as space option
             if ((connData->printerNullAsSpace)
               &&(posChar == NULL) )
                *fieldText++ = ASCIIBLANK;
             else *fieldText++ = ConvertToAscii(posChar);
             currentCol++;
            }
          }
			else
          {
           // This an "real" field so it is "formatted"
           fdStore.fdFormatted=true;
          }

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

			fromBufPos = NextBufPos(fromBufPos);
		  } // ! fieldInited

		} // if ((fromBufPos == 0) || .... || .... || ......
		else
		{
       // It's sure that the field was inited because at least pos 0 is
       //    the first field (or pseudofield)
		 if (!fdNodisp)
		 	posChar = charBuffer[fromBufPos];
		 else if (connData->printerNullLine)
             posChar = NULL;
       else posChar = EBCDICBLANK;

       //Checking for null as space option
       if ((connData->printerNullAsSpace)
         &&(posChar == NULL) )
           *fieldText++ = ASCIIBLANK;
       else *fieldText++ = ConvertToAscii(posChar);

       currentCol++;
		 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
ALFF3270::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 = initPos;
	 int nullCount = count;
	 int endFor = NextBufPos(EndOfField(initPos));
	 bool nullFound = false;
	 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;
}

bool
ALFF3270::IsCharAttrEqual(const int thisPos,const int compPos)
{
 ScreenPos& pos = screenBuffer[thisPos];
 ScreenPos& compare = screenBuffer[compPos];
 if ((pos.extendedHighLight == compare.extendedHighLight)
	&&(pos.charColor == compare.charColor)
	&&(pos.bkgdColor == compare.bkgdColor)
	&&(pos.bgTransparency == compare.bgTransparency)
	&&(pos.charSet == compare.charSet))
  return true;
 else return false;
}

int
ALFF3270::DataFromKeyboard(const char* buffer, int count, bool insertMode)
{
 int initPos = cursorPos;
 int attrPos = 0;
 int rePaint = 0;
 keyCount = 0;
 if (IsUnprotField(cursorPos, CHECKSF))
  {
	int fdBegin = screenBuffer[cursorPos].fieldBeginAt;
	if (!insertMode)
	 {
	  bufferUserModified = true;
	  lastCharUpdated = initPos;
	  if (IsWithinField(initPos,count))
		{
		 SetSelection(initPos,initPos+count);
		 AddUndo(SELECTION);
		}
	  else  AddUndo(LASTUPDATED,TOENDOFFIELD);
	  while (count)
		{
		 if ((screenBuffer[cursorPos].fieldAttr & NUMERIC)
			&& (!isdigit(*buffer)) )
		  return NUMERICFIELD;
		 charBuffer[cursorPos] = ConvertToEBCDIC(*buffer++);
       keyCount++;

		 /* Check For "Blinking" PSEUDO Field Overlapping */
		 attrPos = GetPrevAttrPos(cursorPos);
		 if ((screenBuffer[attrPos].posAttr == PSEUDOFIELD)
			&&(screenBuffer[attrPos].extendedHighLight == EHBLINK))
			  rePaint = MUSTREPAINT;

		 /* Update ScreenBuffer To Keyboard Char Attributes */
		 GetDefaultCharAttr(screenBuffer[cursorPos],fdBegin,
								  screenBuffer[fdBegin].fieldAttr);
		 SetMDTBit(cursorPos);
		 count--;
		 if (!IsEndOfField())
			cursorPos = NextBufPos(cursorPos);
		 else
		  {
			cursorPos = NextFieldPos(cursorPos,ANYFIELD,NORESET);
			if (count)
			 {
			  if (!IsUnprotField(cursorPos, CHECKSF))
				return PROTECTEDFIELD;
			  if (IsWithinField(cursorPos,count))
				{
				 SetSelection(cursorPos,cursorPos+count);
				 AddUndo(SELECTION);
				}
			  else
				{
				 int saveLastChUpd = lastCharUpdated;
				 lastCharUpdated = cursorPos;
				 AddUndo(LASTUPDATED,TOENDOFFIELD);
             lastCharUpdated = saveLastChUpd;
				}
			 }
		  }
		}
	 }
	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 ((screenBuffer[cursorPos].fieldAttr & NUMERIC)
			&& (!isdigit(*buffer)) )
			return NUMERICFIELD;
		 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];
			  screenBuffer[toPos] = screenBuffer[pos];
			  toPos = PrevBufPos(toPos);
			 }
         int nexFdPos = NextBufPos(lastNull);
         if (screenBuffer[NextBufPos(lastNull)].posAttr == ATTRDEFAULT)
			   screenBuffer[NextBufPos(lastNull)].posAttr = PSEUDOFIELD;
		  }

		 while (count)
		  {
			charBuffer[cursorPos] = ConvertToEBCDIC(*buffer++);
         keyCount++;
			GetDefaultCharAttr(screenBuffer[cursorPos],fdBegin,
									 screenBuffer[fdBegin].fieldAttr);
			count--;
			if (!IsEndOfField())
			  cursorPos = NextBufPos(cursorPos);
			 else return PROTECTEDFIELD;  //Under Insertion we cannot go thru eof
		  }
		  rePaint = MUSTREPAINT;
		}
	  else return PROTECTEDFIELD;
	 }
  }
  else return PROTECTEDFIELD;

 /* Check If Buffer Position After Cursor Position Has Char
	 Attributes Different from it and set an Pseudo Field if
	 necessary */
 int beforePos = PrevBufPos(cursorPos);
 if (!IsCharAttrEqual(cursorPos,beforePos))
	screenBuffer[cursorPos].posAttr = PSEUDOFIELD;

 /* Check If Buffer Position before initial Cursor Position
	 Has Char Attributes Different from it and set an
	 Pseudo Field if necessary */
 beforePos = PrevBufPos(initPos);
 if (!IsCharAttrEqual(initPos,beforePos))
  {
	screenBuffer[initPos].posAttr = PSEUDOFIELD;
	return (initPos+rePaint);
  }
 else return  (screenBuffer[initPos].fieldBeginAt+rePaint);
}

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

 if (option == DELTOPOSITION)
  {
	if (IsUnprotField(cursorPos,CHECKSF))
	 {
	  int fdBegin = screenBuffer[cursorPos].fieldBeginAt;
	  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);
		 int firstNull = cursorPos;
		 for (buffPos=cursorPos; buffPos!=endField; buffPos=NextBufPos(buffPos))
		 {
		  charBuffer[buffPos] = NULL;
		  GetDefaultCharAttr(screenBuffer[buffPos],
									fdBegin,
									screenBuffer[fdBegin].fieldAttr);
		 }
		 screenBuffer[firstNull].posAttr = PSEUDOFIELD;
		}
	  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 3270 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];
			 screenBuffer[buffPos] = screenBuffer[fromPos];
			 fromPos = NextBufPos(fromPos);
			}

		  /* Set Final Removed Field Positions to NULLS */
		  int firstNull = buffPos;
		  int fdBegin = screenBuffer[buffPos].fieldBeginAt;
		  for (buffPos=buffPos; buffPos!=endField; buffPos=NextBufPos(buffPos))
			{
			  charBuffer[buffPos] = NULL;
			  GetDefaultCharAttr(screenBuffer[buffPos],
										fdBegin,
										screenBuffer[fdBegin].fieldAttr);
			}
		  screenBuffer[firstNull].posAttr = PSEUDOFIELD;
        int beforePos = PrevBufPos(cursorPos);
		  if (!IsCharAttrEqual(cursorPos,beforePos))
			 screenBuffer[cursorPos].posAttr = PSEUDOFIELD;
		}

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

	if (IsUnprotField(cursorPos,CHECKSF))
	 {
	  /* 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);

	  unsigned char delPosAttr = screenBuffer[cursorPos].posAttr;
	  bool endWhile = false;
	  while (!endWhile)
		{
		 if (buffPos != endField)
		  {
			int nextPos = NextBufPos(buffPos);
			charBuffer[buffPos] = charBuffer[nextPos];
			screenBuffer[buffPos] = screenBuffer[nextPos];
			buffPos = NextBufPos(buffPos);
		  }
		  else
			{
			 int fdBegin = screenBuffer[buffPos].fieldBeginAt;
			 charBuffer[buffPos] = NULL;
			 GetDefaultCharAttr(screenBuffer[buffPos],
									  fdBegin,
									  screenBuffer[fdBegin].fieldAttr);
			 retCode = screenBuffer[buffPos].fieldBeginAt;
			 endWhile = true;
			}
		}
	  if (delPosAttr == PSEUDOFIELD)
		 screenBuffer[cursorPos].posAttr = PSEUDOFIELD;

	  /* Next Position After Row Ending MUST Be Set To PseuDoField */
	  int beforePos = PrevBufPos(buffPos);
	  if (!IsCharAttrEqual(buffPos,beforePos))
		  screenBuffer[buffPos].posAttr = PSEUDOFIELD;
	 }
	 else return PROTECTEDFIELD;
  }
  else return PROTECTEDFIELD; //invalid option;

 return retCode;

}

int
ALFF3270::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 = 0;
 int begWord = 0;
 int endWord = 0;
 TPoint begWordPos;
 TPoint endWordPos;
 unsigned char charPos;

 if (!IsUnprotField(cursorPos,CHECKSF))
  return PROTECTEDFIELD;

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

 /* Take word end delimiter position*/
 endWordPos = GetEndOfWord(begWord);
 endWord = endWordPos.y*scrLineSize + endWordPos.x;

 /*
  * Verify if the word end was found: Char after its end
  * must be an word delimiter. If it is skip back one position to get
  * last buffer position to be deleted.
  */
 charPos = ConvertToAscii(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
ALFF3270::GetSelection(uint& startPos, uint& endPos) const
{
 if (selStartPos != selEndPos)
  {
	startPos = selStartPos;
	endPos   = selEndPos;
	if (selEndPos > selStartPos)
	  return (selEndPos-selStartPos);
	 else return (size3270Buf-selStartPos+selEndPos);
  }
  else return 0;
}

bool
ALFF3270::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
ALFF3270::SetSelection(const int startPos, const int endPos)
{
 if (( startPos == 0)
  && (endPos == -1))
  {
	/* Do select entire buffer */
	selStartPos = 0;
	lastCharUpdated = selStartPos;
	selEndPos = size3270Buf-1;
	cursorPos = size3270Buf-1;
	return true;
  }
 else if (startPos == -1)
		{
		 /* Remove current selection */
		 lastCharUpdated = selStartPos;
		 selStartPos = cursorPos;
		 selEndPos = cursorPos;
		 return true;
		}
 else if (endPos <= size3270Buf)
		{
		 /* 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
ALFF3270::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 3270 text buffer and convert it to ascii */
  char far* buffer = new char[size3270Buf+1];
  int i = 0;
  for (i = 0; i<size3270Buf; i++)
	{
	 if ((charBuffer[i] == SF)
		||(charBuffer[i] == SFE) )
		buffer[i] = 0xff;
	 else buffer[i] = ConvertToAscii(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
ALFF3270::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 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 3270 Char Buffer Undoing Last Update Done.          *
**-----------------------------------------------------------------------**
* Input   : None.                                                         *
* Process : Get undo Field from Undo Buffer, Update the 3270 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
ALFF3270::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;
	 if (scrField.fdFormatted)
	  {
		screenPos = screenBuffer[buffPos];
		buffPos = NextBufPos(buffPos);
	  }
	 else
	  {
		screenPos.fieldBeginAt = screenBuffer[buffPos].fieldBeginAt;
		screenPos.posAttr = PSEUDOFIELD;
		screenPos.fieldAttr = screenBuffer[screenPos.fieldBeginAt].fieldAttr;
		screenPos.extendedHighLight = scrField.fdEffects;
		screenPos.charColor = (unsigned char)scrField.fdTextColor;
		screenPos.bkgdColor = (unsigned char)scrField.fdBkgdColor;
		screenPos.charSet   = defaultCharSet;
		screenPos.bgTransparency = scrField.fdBkgdTransparency;
		screenPos.fieldValidation = scrField.fdValidation;
		screenPos.fieldOutlining = scrField.fdOutlining;
	  }

	 /* Restore 3270 Char buffer */
	 char* fieldText = scrField.fdText;
	 int textLen = strlen(fieldText);
	 for (int i = 0; i < textLen; i++)
	  {
		screenBuffer[buffPos] = screenPos;
		screenPos.posAttr = ATTRNULL;
		if (*fieldText == EBCDICNULL)
		  charBuffer[buffPos] = NULL;
		else charBuffer[buffPos] = *fieldText;
		*fieldText++ = ConvertToAscii(*fieldText);  //Convert to Screen Format
		buffPos = NextBufPos(buffPos);
	  }

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

	 if (scrField.cursorPos != UNDOCONTINUE)
	  {
		/* Restore 3270 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. (3270 Buffer Reference of Begin of Changed Text      *
* Process : Build a Field with same characteristics of 3270 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
ALFF3270::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 3270 buffer EBCDIC //
 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*
ALFF3270::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
ALFF3270::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
ALFF3270::ResetUndo()
{
 undoBuffer.Flush();
 bufferUserModified = false;
}


