tn5250j/src/org/tn5250j/framework/tn5250 Screen5250.java,NONE,1.1 Stream5250.java,NONE,1.1 DataStreamProducer.java,NONE,1.1 DataStreamQueue.java,NONE,1.1 ScreenFields.java,NONE,1.1 tnvt.java,NONE,1.1 WTDSFParser.java,NONE,1.1 ScreenOIA.java,NONE,1.1 ScreenPlanes.java,NONE,1.1 ScreenField.java,NONE,1.1

"Kenneth J. Pouncey" <[email protected]> Mon, 26 Jul 2004 19:23:02 +0000
Newsgroups gmane.comp.java.tn5250j.cvs
Message-ID <[email protected]>
Update of /cvsroot/tn5250j/tn5250j/src/org/tn5250j/framework/tn5250
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11632/src/org/tn5250j/framework/tn5250

Added Files:
	Screen5250.java Stream5250.java DataStreamProducer.java 
	DataStreamQueue.java ScreenFields.java tnvt.java 
	WTDSFParser.java ScreenOIA.java ScreenPlanes.java 
	ScreenField.java 
Log Message:
Added tn5250 package to framwork to start work on the interfaces

--- NEW FILE: DataStreamProducer.java ---
package org.tn5250j.framework.tn5250;

import java.io.*;
import java.net.*;

import org.tn5250j.tools.logging.*;
import org.tn5250j.encoding.CodePage;

public class DataStreamProducer implements Runnable {

   private BufferedInputStream bin;
   private ByteArrayOutputStream baosin;
   private Thread me;
   private byte[] saveStream;
   private DataStreamQueue dsq;
   private tnvt vt;
   private byte[] abyte2;
   private FileOutputStream fw;
   private BufferedOutputStream dw;
   private boolean dumpBytes = false;
   private CodePage codePage;

   private TN5250jLogger  log = TN5250jLogFactory.getLogger (this.getClass());

   public DataStreamProducer(tnvt vt, BufferedInputStream in, DataStreamQueue queue, byte[] init) {
      bin = in;
      this.vt = vt;
      baosin = new ByteArrayOutputStream();
      dsq = queue;
      abyte2 = init;
   }

   public void setInputStream(ByteArrayOutputStream is) {

      baosin = is;

   }

   public void setQueue( DataStreamQueue queue) {

      dsq = queue;

   }

   public final void run() {

      boolean done = false;

      me = Thread.currentThread();

      // load the first response screen
      try {
         loadStream(abyte2, 0);
      }
      catch (IOException ioef) {
         log.warn(" run() " + ioef.getMessage());
      }
      while (!done) {
		  try {

			  byte[] abyte0 = readIncoming();

			  // WVL - LDC : 17/05/2004 : Device name negotiations send TIMING MARK
			  // Restructured to the readIncoming() method to return null
			  // on TIMING MARK. Don't process in that case (abyte0 == null)!
			  if (abyte0 != null)
			  {
				  // WVL - LDC : 16/07/2003 : TR.000345
				  // When the socket has been closed, the reading returns
				  // no bytes (an empty byte arrray).
				  // But the loadStream fails on this, so we check it here!
				  if (abyte0.length > 0)
				  {
					  loadStream(abyte0, 0);
				  }
				  // WVL - LDC : 16/07/2003 : TR.000345
				  // Returning no bytes means the input buffer has
				  // reached end-of-stream, so we do a disconnect!
				  else
				  {
					  done = true;
					  vt.disconnect();
				  }
			  }

         }

		 catch (SocketException se) {
            log.warn("   DataStreamProducer thread interrupted and stopping " + se.getMessage());
            done = true;
         }

         catch (IOException ioe) {

		   log.warn(ioe.getMessage());
           if (me.isInterrupted())
              done = true;

         }
         catch (Exception ex) {

           log.warn(ex.getMessage());
           if (me.isInterrupted())
              done = true;

         }
      }
    }

   private final void loadStream(byte abyte0[], int i)
     throws IOException {

      int j = 0;
      int size = 0;
      if (saveStream == null) {
         j = (abyte0[i] & 0xff) << 8 | abyte0[i + 1] & 0xff;
         size = abyte0.length;
      }
      else {
         size = saveStream.length + abyte0.length;
         byte[] inter = new byte[size];
         System.arraycopy(saveStream, 0, inter, 0, saveStream.length);
         System.arraycopy(abyte0, 0, inter, saveStream.length, abyte0.length);
         abyte0 = new byte[size];
         System.arraycopy(inter, 0, abyte0, 0, size);
         saveStream = null;
         inter = null;
         j = (abyte0[i] & 0xff) << 8 | abyte0[i + 1] & 0xff;
		 log.debug("partial stream found");
      }

      if (j > size) {
         saveStream = new byte[abyte0.length];
         System.arraycopy(abyte0, 0, saveStream, 0, abyte0.length);
		 log.debug("partial stream saved");
      }
      else {
         byte abyte1[];
         try {
            abyte1 = new byte[j + 2];

            System.arraycopy(abyte0, i, abyte1, 0, j + 2);
            dsq.put(new Stream5250(abyte1));
            if(abyte0.length > abyte1.length + i)
                loadStream(abyte0, i + j + 2);
         }
         catch (Exception ex) {

           log.warn("load stream error " + ex.getMessage());
   //        ex.printStackTrace();
   //        dump(abyte0);

         }
      }
   }

   public final byte[] readIncoming()
        throws IOException {

      boolean done = false;
      boolean negotiate = false;

      baosin.reset();
      int j = -1;
      int i = 0;

      while(!done) {
         i = bin.read();

         // WVL - LDC : 16/07/2003 : TR.000345
         // The inStream return -1 when end-of-stream is reached. This
         // happens e.g. when the connection is closed from the AS/400.
         // So we stop in this case!
         // ==> an empty byte array is returned from this method.
         if (i == -1) // nothing read!
         {
           done = true;
            vt.disconnect();
           continue;
         }

         // We use the values instead of the static values IAC and EOR
         //    because they are defined as bytes.
         //
         // The > if(i != 255 || j != 255)  < is a hack for the double FF FF's
         // that are being returned.  I do not know why this is like this and
         // can not find any documentation for it.  It is also being returned
         // on my Client Access tcp dump as well so they are handling it.
         //
         // my5250
         // 0000:  00 50 DA 44 C8 45 42 00 00 00 00 24 08 00 45 00 .P.D.EB....$..E.
         // 0010:  04 2A BC F9 00 00 40 06 D0 27 C1 A8 33 04 C1 A8 .*....@..'..3...
         // 0020:  33 58 00 17 04 18 6F A2 83 CB 00 1E D1 BA 50 18 3X....o.......P.
         // 0030:  20 00 8A 9A 00 00 03 FF FF 12 A0 00 00 04 00 00  ...............
         // --------------------------- || || -------------------------------------
         // 0040:  03 04 40 04 11 00 20 01 07 00 00 00 18 00 00 10 ..@... .........

         if(j == 255 && i == 255) {
            j = -1;
            continue;
         }
         else {
            baosin.write(i);
            // check for end of record EOR and IAC  - FFEF
            if(j == 255 && i == 239)
               done = true;

            // This is to check for the TELNET TIMING MARK OPTION
            // rfc860 explains this in more detail.  When we receive it
            // we will negotiate with the server by sending a WONT'T TIMING-MARK
            // This will let the server know that we processed the information
            // and are just waiting for the user to enter some data so keep the
            // socket alive.   This is more or less a AYT (ARE YOU THERE) or not.
            if(i == 253 && j == 255) {
               done = true;
               negotiate = true;
            }
            j = i;
         }
     }

     // after the initial negotiation we might get other options such as
     //    timing marks ??????????????  do we ???????????? look at telnet spec
     // yes we do. rfc860 explains about timing marks.

     	 // WVL - LDC : 17/05/2004 : Device name negotiations send TIMING MARK
     	 //                          to existing device!
     	 // Handled incorrectly: we cannot continue processing the TIMING MARK DO
     	 // after we have handled it in the vt.negotiate()
     	 // We should not return the bytes;
     	 // ==> restructured to return null after negotiation!
     	 //     Impacts the run method! Added the null check.
     	 byte[] rBytes = baosin.toByteArray();

		 if (dumpBytes) {
			dump(rBytes);
		 }

         if (negotiate) {
            // get the negotiation option
            baosin.write(bin.read());
            vt.negotiate(rBytes);

            return null;
         }
         else
         {
			 return rBytes;
		 }
	}

   protected final void toggleDebug (CodePage cp) {

      if (codePage == null)
         codePage = cp;

      dumpBytes = !dumpBytes;
      if (dumpBytes) {

         try {
            if (fw == null) {
               fw = new FileOutputStream("log.txt");
               dw = new BufferedOutputStream(fw);
            }
         }
         catch (FileNotFoundException fnfe) {
            log.warn(fnfe.getMessage());
         }

      }
      else {

         try {

            if (dw != null)
               dw.close();
            if (fw != null)
               fw.close();
            dw = null;
            fw = null;
            codePage = null;
         }
         catch(IOException ioe) {

            log.warn(ioe.getMessage());
         }
      }

      log.info("Data Stream output is now " + dumpBytes);
   }

   public void dump (byte[] abyte0) {
      try {

         log.info("\n Buffer Dump of data from AS400: ");
         dw.write("\r\n Buffer Dump of data from AS400: ".getBytes());

         StringBuffer h = new StringBuffer();
         for (int x = 0; x < abyte0.length; x++) {
            if (x % 16 == 0) {
               System.out.println("  " + h.toString());
               dw.write(("  " + h.toString() + "\r\n").getBytes());

               h.setLength(0);
               h.append("+0000");
               h.setLength(5 - Integer.toHexString(x).length());
               h.append(Integer.toHexString(x).toUpperCase());

               System.out.print(h.toString());
               dw.write(h.toString().getBytes());

               h.setLength(0);
            }
            char ac = codePage.ebcdic2uni(abyte0[x]);
            if (ac < ' ')
               h.append('.');
            else
               h.append(ac);
            if (x % 4 == 0) {
               System.out.print(" ");
               dw.write((" ").getBytes());

            }

            if (Integer.toHexString(abyte0[x] & 0xff).length() == 1){
               System.out.print("0" + Integer.toHexString(abyte0[x] & 0xff).toUpperCase());
               dw.write(("0" + Integer.toHexString(abyte0[x] & 0xff).toUpperCase()).getBytes());

            }
            else {
               System.out.print(Integer.toHexString(abyte0[x] & 0xff).toUpperCase());
               dw.write((Integer.toHexString(abyte0[x] & 0xff).toUpperCase()).getBytes());
            }

         }
         System.out.println();
         dw.write("\r\n".getBytes());

         dw.flush();
      }
      catch(EOFException _ex) { }
      catch(Exception _ex) {
         log.warn("Cannot dump from host\n\r");
      }

   }

//      public void dumpBytes() {
//         byte shit[] = bk.buffer;
//         for (int i = 0;i < shit.length;i++)
//            System.out.println(i + ">" + shit[i] + "< - ascii - >" + getASCIIChar(shit[i]) + "<");
//      }
//
//      public void dumpHexBytes(byte[] abyte) {
//         byte shit[] = abyte;
//         for (int i = 0;i < shit.length;i++)
//            System.out.println(i + ">" + shit[i] + "< hex >" + Integer.toHexString((shit[i] & 0xff)));
//      }

}
--- NEW FILE: tnvt.java ---
/**
 * Title: tnvt.java
 * Copyright: Copyright (c) 2001 Company:
 *
 * @author Kenneth J. Pouncey
 * @version 0.5
 *
 * Description:
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
[...3281 lines suppressed...]
	private static final byte TRANSMIT_BINARY = (byte) 0; // 0
	private static final byte QUAL_IS = (byte) 0; // 0
	private static final byte TIMING_MARK = (byte) 6; // 6
	private static final byte NEW_ENVIRONMENT = (byte) 39; // 27
	private static final byte IS = (byte) 0; // 0
	private static final byte SEND = (byte) 1; // 1
	private static final byte INFO = (byte) 2; // 2
	private static final byte VAR = (byte) 0; // 0
	private static final byte VALUE = (byte) 1; // 1
	private static final byte NEGOTIATE_ESC = (byte) 2; // 2
	private static final byte USERVAR = (byte) 3; // 3

	// miscellaneous
	private static final byte ESC = 0x04; // 04

	private static final char char0 = 0;

	//   private static final byte CMD_READ_IMMEDIATE_ALT = (byte)0x83; // 131

}

--- NEW FILE: WTDSFParser.java ---
/**
 * Title: tn5250J
 * Copyright:   Copyright (c) 2001
 * Company:
 * @author  Kenneth J. Pouncey
 * @version 0.5
 *
 * Description:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307 USA
 *
 */
package org.tn5250j.framework.tn5250;

import org.tn5250j.encoding.CodePage;
import org.tn5250j.framework.tn5250.Screen5250;
import org.tn5250j.TN5250jConstants;

/**
 *
 * Write To Display Structured Field:
 *
 * This module will parse the Structrued Field information for enhanced
 * emulation mode.
 *
 */
public class WTDSFParser implements TN5250jConstants {

   private Screen5250 screen52;
   private Stream5250 bk;
   private tnvt vt;
   private CodePage codePage;
   int pos;
   byte[] segment;
   int length;
   boolean error;

   WTDSFParser (tnvt vt) {

      this.vt = vt;
      screen52 = vt.screen52;
      bk = vt.bk;
      codePage = vt.codePage;

   }

   protected boolean parseWriteToDisplayStructuredField(byte[] seg) {

//      bk = vt.bk;

      error = false;
      boolean done = false;
      boolean windowDefined = false;
//      int nextone;
      pos = 0;
      segment = seg;

//      try {
         length = (( segment[pos++] & 0xff )<< 8 | (segment[pos++] & 0xff));

         while (!done) {
            int s =    segment[pos++] & 0xff;
            switch (s) {

               case 0xD9:     // Class Type 0xD9 - Create Window

                  switch (segment[pos++]) {
                     case 0x50:      // Define Selection Field

                        defineSelectionField(length);
                        done = true;
                        break;
                     case 0x51:      // Create Window

                        boolean cr = false;
                        int rows = 0;
                        int cols = 0;
                        // pull down not supported yet
                        if ((segment[pos++] & 0x80) == 0x80)
                           cr = true;  // restrict cursor
                        pos++; // get reserved field pos 6
                        pos++; // get reserved field pos 7
                        rows = segment[pos++]; // get window depth rows pos 8
                        cols = segment[pos++]; // get window width cols pos 9
                        length -= 9;
                        if (length == 0) {
                           done = true;
//                           System.out.println("Create Window");
//                           System.out.println("   restrict cursor " + cr);
//                           System.out.println(" Depth = " + rows + " Width = " + cols);
                           screen52.createWindow(rows,cols,1,true,32,58,
                                             '.',
                                             '.',
                                             '.',
                                             ':',
                                             ':',
                                             ':',
                                             '.',
                                             ':');
                           windowDefined = true;
                           break;
                        }

                        // pos 10 is Minor Structure
                        int ml = 0;
                        int type = 0;
                        int lastPos = screen52.getLastPos();
//                        if (cr)
//                           screen52.setPendingInsert(true,
//                                          screen52.getCurrentRow(),
//                                          screen52.getCurrentCol());
                        int mAttr = 0;
                        int cAttr = 0;

                        while (length > 0) {

                           // get minor length
                           ml = ( segment[pos++] & 0xff );
                           length -= ml;

                           // only normal windows are supported at this time
                           type = segment[pos++];

                           switch (type) {

                              case 0x01 : // Border presentation
                                 boolean gui = false;
                                 if ((segment[pos++] & 0x80) == 0x80)
                                    gui = true;
                                 mAttr = segment[pos++];
                                 cAttr = segment[pos++];

                                 char ul = '.';
                                 char upper = '.';
                                 char ur = '.';
                                 char left = ':';
                                 char right = ':';
                                 char ll = ':';
                                 char bottom = '.';
                                 char lr = ':';

                                 // if minor length is greater than 5 then
                                 //    the border characters are specified
                                 if (ml > 5) {
                                    ul = codePage.ebcdic2uni(segment[pos++]);
//                                    ul = getASCIIChar(segment[pos++]);
                                    if (ul == 0)
                                       ul = '.';

                                    upper = codePage.ebcdic2uni(segment[pos++]);
//                                    upper = getASCIIChar(segment[pos++]);
                                    if (upper == 0)
                                       upper = '.';

                                    ur = codePage.ebcdic2uni(segment[pos++]);
//                                    ur = getASCIIChar(segment[pos++]);
                                    if (ur == 0)
                                       ur = '.';

                                    left = codePage.ebcdic2uni(segment[pos++]);
//                                    left = getASCIIChar(segment[pos++]);
                                    if (left == 0)
                                       left = ':';

                                    right = codePage.ebcdic2uni(segment[pos++]);
//                                    right = getASCIIChar(segment[pos++]);
                                    if (right == 0)
                                       right = ':';

                                    ll = codePage.ebcdic2uni(segment[pos++]);
//                                    ll = getASCIIChar(segment[pos++]);
                                    if (ll == 0)
                                       ll = ':';

                                    bottom = codePage.ebcdic2uni(segment[pos++]);
//                                    bottom = getASCIIChar(segment[pos++]);
                                    if (bottom == 0)
                                       bottom = '.';

                                    lr = codePage.ebcdic2uni(segment[pos++]);
//                                    lr = getASCIIChar(segment[pos++]);
                                    if (lr == 0)
                                       lr = ':';
                                 }

//                                 System.out.println("Create Window");
//                                 System.out.println("   restrict cursor " + cr);
//                                 System.out.println("   Depth = " + rows + " Width = " + cols);
//                                 System.out.println("   type = " + type + " gui = " + gui);
//                                 System.out.println("   mono attr = " + mAttr + " color attr = " + cAttr);
//                                 System.out.println("   ul = " + ul + " upper = " + upper +
//                                                         " ur = " + ur +
//                                                         " left = " + left +
//                                                         " right = " + right +
//                                                         " ll = " + ll +
//                                                         " bottom = " + bottom +
//                                                         " lr = " + lr
//                                                         );
                                 screen52.createWindow(rows,cols,type,gui,mAttr,cAttr,
                                                      ul,
                                                      upper,
                                                      ur,
                                                      left,
                                                      right,
                                                      ll,
                                                      bottom,
                                                      lr);
                                 windowDefined = true;
                              break;
         //
         //  The following shows the input for window with a title
         //
         //      +0000 019A12A0 00000400 00020411 00200107  .?.?..?...?..?.
         //      +0010 00000018 00000011 06131500 37D95180  ........?.?..R??
         //      +0020 00000A24 0D018023 23404040 40404040  ..??..???
         //      +0030 40211000 000000D7 C2C1D9C4 C5D4D67A   \uFFFD.....PBARDEMO:
         //      +0040 40D79996 879985A2 A2408281 99408485   Progress bar de
         //      +0050 94961108 1520D5A4 94828599 40968640  mo.???Number of
         //      +0060 8595A399 8985A24B 4B4B4B4B 4B7A2011  entries......:?.
         //      +0070 082E2040 404040F5 F0F06BF0 F0F02011  ?.?    500,000?.
         //      +0080 091520C3 A4999985 95A34085 95A399A8  \uFFFD??Current entry
         //      +0090 4095A494 8285994B 4B4B7A20 11092E20   number...:?.\uFFFD.?
         //      +00A0 40404040 4040F56B F0F0F020 110A1520        5,000?.???
         //      +00B0 D9859481 89958995 87408595 A3998985  Remaining entrie
         //      +00C0 A24B4B4B 4B4B4B7A 20110A2E 20404040  s......:?.?.?
         //      +00D0 40F4F9F5 6BF0F0F0 20110C15 20E2A381   495,000?..??Sta
         //      +00E0 99A340A3 8994854B 4B4B4B4B 4B4B4B4B  rt time.........
         //      +00F0 4B4B4B4B 7A20110C 2F2040F7 7AF5F37A  ....:?...? 7:53:

                              case 0x10 : // Window title/footer
                                 if (!windowDefined) {
                                    screen52.createWindow(rows,cols,1,true,32,58,
                                                         '.',
                                                         '.',
                                                         '.',
                                                         ':',
                                                         ':',
                                                         ':',
                                                         '.',
                                                         ':');
                                    windowDefined = true;
                                 }

                                 byte orientation = segment[pos++];
                                 mAttr = segment[pos++];
                                 cAttr = segment[pos++];

                                 //reserved
                                 pos++;
                                 ml -= 6;

                                 StringBuffer hfBuffer = new StringBuffer(ml);
                                 while (ml-- > 0) {
                                    //LDC - 13/02/2003 - Convert it to unicode
                                    hfBuffer.append(codePage.ebcdic2uni(segment[pos++]));
//                                    hfBuffer.append(getASCIIChar(segment[pos++]));

                                 }

                                 System.out.println(
                                    " orientation " + Integer.toBinaryString(orientation) +
                                    " mAttr " + mAttr +
                                    " cAttr " + cAttr +
                                    " Header/Footer " + hfBuffer);
                                 screen52.writeWindowTitle(lastPos,
                                                            rows,
                                                            cols,
                                                            orientation,
                                                            mAttr,
                                                            cAttr,
                                                            hfBuffer);
                                 break;
                              default:
                                 System.out.println("Invalid Window minor structure");
                              length = 0;
                              done = true;
                           }

                        }

                        done = true;

                        break;

                     case 0x53:      // Scroll Bar
                        int sblen = 15;
                        byte sbflag = segment[pos++];  // flag position 5

                        pos++;  // reserved position 6

                        // position 7,8
                        int totalRowScrollable =  (( segment[pos++] & 0xff )<< 8
                                                | (segment[pos++] & 0xff));

                        // position 9,10
                        int totalColScrollable =  (( segment[pos++] & 0xff )<< 8
                                                | (segment[pos++] & 0xff));

                        // position 11,12
                        int sliderRowPos =  (( segment[pos++] & 0xff )<< 8
                                                | (segment[pos++] & 0xff));

                        // position 13,14
                        int sliderColPos =  (( segment[pos++] & 0xff )<< 8
                                                | (segment[pos++] & 0xff));

                        // position 15
                        int sliderRC = segment[pos++];

                        screen52.createScrollBar(sbflag,totalRowScrollable,
                                                   totalColScrollable,
                                                   sliderRowPos,
                                                   sliderColPos,
                                                   sliderRC);
                        length -= 15;

                        done = true;

                        break;

                     case 0x5B:      // Remove GUI ScrollBar field

                        pos++; // reserved must be set to off pos 5
                        pos++; // reserved must be set to zero pos 6

                        done = true;
                        break;

                     case 0x5F:      // Remove All GUI Constructs
//                        System.out.println("remove all gui contructs");
                        int len = 4;
                        int d = 0;
                        length -= s;
                        while (--len > 0)
                           d = segment[pos++];
//                        if (length > 0) {
//                           len = (segment[pos++] & 0xff )<< 8;
//
//                           while (--len > 0)
//                              d = segment[pos++];
//                        }

                        screen52.clearGuiStuff();
                        // per 14.6.13.4 documentation we should clear the
                        //    format table after this command
                        screen52.clearTable();
                        done = true;
                        break;

                     case 0x60:      // Erase/Draw Grid Lines - not supported
                                    // do not know what they are
                                    // as of 03/11/2002 we should not be getting
                                    // this anymore but I will leave it here
                                    //  just in case.
//                        System.out.println("erase/draw grid lines " + length);
                        len = 6;
                        d = 0;
                        length -= 9;
                        while (--len > 0)
                           d = segment[pos++];
                           if (length > 0) {
                              len = (segment[pos++] & 0xff )<< 8;

                           while (--len > 0) {
                              d = segment[pos++];
                           }
                        }
                        done = true;
                        break;
                     default:
                        vt.sendNegResponse(NR_REQUEST_ERROR,0x03,0x01,0x01,"invalid wtd structured field sub command "
                                                   + ( pos - 1));
//                                                   + bk.getByteOffset(-1));
                        error = true;
                        break;
                  }
                  break;

               default:
                  vt.sendNegResponse(NR_REQUEST_ERROR,0x03,0x01,0x01,
                              "invalid wtd structured field command "
                               + (pos - 1));
//                               + bk.getByteOffset(-1));
                  error = true;
                  break;
            }

            if (error)
               done = true;

         }
//      }
//      catch (Exception e) {};

      return error;

   }

   private void defineSelectionField(int majLen) {

      //   0030:  20 00 2C 3E 00 00 00 69 12 A0 00 00 04 00 00 03  .,>...i........
      //   0040:  04 40 04 11 00 28 01 07 00 00 00 19 00 00 04 11 .@...(..........
      //   0050:  14 19 15 00 48 D9 50 00 60 00 11 01 84 84 00 00 ....H.P.`.......
      //   0060:  05 03 01 01 00 00 00 13 01 E0 00 21 00 21 00 3B ...........!.!.;
      //   0070:  22 20 20 20 20 3A 24 20 20 3A 0B 10 08 00 E0 00 "    :$  :......
      //   0080:  D6 95 85 40 40 0B 10 08 00 E0 00 E3 A6 96 40 40 ...@@.........@@
      //   0090:  0B 10 08 00 E0 00 E3 88 99 85 85 04 52 00 00 FF ............R...
      //   00A0:  EF                                              .
      try {
         int flag1 = segment[pos++];    // Flag byte 1 - byte 5
         int flag2 = segment[pos++];    // Flag byte 2 - byte 6
         int flag3 = segment[pos++];    // Flag byte 3 - byte 7
         int typeSelection = segment[pos++];    // Type of selection Field - byte 8

         // GUI Device Characteristics:
         //    This byte is used if the target device is a GUI PWS or a GUI-like
         //    NWS.  If neigher of these WS are the targets, this byte is ignored
         int guiDevice = segment[pos++];    // byte 9
         int withMnemonic = segment[pos++];    //  byte 10
         int noMnemonic = segment[pos++];    // byte 11

         pos++;    // Reserved - byte 12
         pos++;    // Reserved - byte 13

         int cols = segment[pos++];    // Text Size - byte 14
         int rows = segment[pos++];    // Rows - byte 15

         int maxColChoice = segment[pos++];    // byte 16 num of column choices
         int padding = segment[pos++];    // byte 17
         int numSepChar = segment[pos++];    // byte 18
         int ctySepChar = segment[pos++];    // byte 19
         int cancelAID = segment[pos++];    // byte 20

         int cnt = 0;
         int minLen = 0;
         majLen -= 21;
         System.out.println(" row: " + screen52.getCurrentRow()
                              + " col: " + screen52.getCurrentCol()
                              + " type " + typeSelection
                              + " gui " + guiDevice
                              + " withMnemonic " + withMnemonic
                              + " noMnemonic " + Integer.toHexString(noMnemonic)
                              + " noMnemonic " + Integer.toBinaryString(noMnemonic)
                              + " noMnemonicType " + Integer.toBinaryString((noMnemonic & 0xf0))
                              + " noMnemonicSel " + Integer.toBinaryString((noMnemonic & 0x0f))
                              + " cols " + cols
                              + " rows " + rows);
         int rowCtr = 0;
         int chcRowStart = screen52.getCurrentRow();
         int chcColStart = screen52.getCurrentCol();

         screen52.addField(0x20,1,0,0,0,0);
         screen52.getScreenFields().getCurrentField().setFieldChar((char)0x20);

         screen52.getScreenFields().getCurrentField().setMDT();
//0000:  00 04 AC 9E B9 35 00 01 02 32 BB 4E 08 00 45 00 .....5...2.N..E.
//0010:  00 3C 82 C1 40 00 80 06 00 00 C1 A8 33 58 C1 A8 .<[email protected]..
//0020:  33 01 04 F6 00 17 92 68 71 34 00 02 31 F9 50 18 3......hq4..1.P.
//0030:  FD F0 E9 D8 00 00 00 12 12 A0 00 00 04 00 80 03 ................
//0040:  10 05 F1 11 0C 05 00 24 FF EF                   .......$..

         int colAvail = 0x20;
         int colSelAvail = 0x20;
         int fld = 0;
         do {
            minLen = segment[pos++];    // Minor Length byte 21

            int minType = segment[pos++];    // Minor Type

            switch (minType) {

               case 0x01:  // Choice Presentation Display

                  // flag
                  int flagCP1 = segment[pos++];

                  pos++; // mon select cursor avail emphasis - byte4
                  colSelAvail = segment[pos++];  // -byte 5

                  pos++; // mon select cursor - byte 6
                  int colSelCur = segment[pos++];  // -byte 7

                  pos++; // mon select cursor not avail emphasis - byte 8
                  int colSelNotAvail = segment[pos++];  // -byte 9

                  pos++; // mon avail emphasis - byte 10
                  colAvail = segment[pos++];  // -byte 11

                  pos++; // mon select emphasis - byte 12
                  int colSel = segment[pos++];  // -byte 13

                  pos++; // mon not avail emphasis - byte 14
                  int colNotAvail = segment[pos++];  // -byte 15

                  pos++; // mon indicator emphasis - byte 16
                  int colInd = segment[pos++];  // -byte 17

                  pos++; // mon indicator not avail emphasis - byte 18
                  int colNotAvailInd = segment[pos++];  // -byte 19

                  break;

               case 0x10:  // Choice Text minor structure

                  screen52.goto_XY(chcRowStart++,chcColStart);
                  cnt = 5;
                  int flagCT1 = segment[pos++];
                  int flagCT2 = segment[pos++];
                  int flagCT3 = segment[pos++];
                  int mnemOffset = 0;
                  boolean aid = false;
                  boolean selected = false;

                  // is mnemonic offset specified
                  if ((flagCT1 & 0x40) == 0x40) {
                     System.out.println(" selected ");
                     selected = true;
                  }

                  // is mnemonic offset specified
                  if ((flagCT1 & 0x08) == 8) {
                     System.out.println(" mnemOffset " + mnemOffset);
                     mnemOffset = segment[pos++];
                     cnt++;
                  }

                  // is aid key specified
                  if ((flagCT1 & 0x04) == 4) {

                     aid = true;
                     System.out.println(" aidKey " + aid);
//                     cnt++;
                  }

                  // is single digit number specified
                  if ((flagCT1 & 0x01) == 0x01) {
                     System.out.println(" single digit " );
                     pos++;
                     cnt++;
                  }

                  // is double digint number specified
                  if ((flagCT1 & 0x02) == 0x02) {
                     System.out.println(" double digit " );

                     pos++;
                     cnt++;
                  }

                  String s = "";
                  byte byte0 = 0;
//                  if (fld++ == 2)
//                  screen52.addField(colAvail,cols,0x0,0,0,0);
//                  else
//                  screen52.addField(colAvail,cols,0x20,0,0,0);
                  for (;cnt < minLen; cnt++) {

                     byte0 = segment[pos++];
                     s += vt.ebcdic2uni(byte0);
                     screen52.setChar(vt.ebcdic2uni(byte0));

                  }
                  screen52.addChoiceField(s);
                  System.out.println(s + " selected " + selected);
                  break;
               default:
                  for (cnt = 2;cnt < minLen; cnt++) {

                     pos++;
                  }

            }

            majLen -= minLen;

         }  while (majLen > 0);
      }
      catch (Exception exc) {
         System.out.println(" defineSelectionField :" + exc.getMessage());
         exc.printStackTrace();
      }
   }

   // negotiating commands
//   private static final byte IAC = (byte)-1; // 255  FF
//   private static final byte DONT = (byte)-2; //254  FE
//   private static final byte DO = (byte)-3; //253    FD
//   private static final byte WONT = (byte)-4; //252  FC
//   private static final byte WILL = (byte)-5; //251  FB
//   private static final byte SB = (byte)-6; //250 Sub Begin  FA
//   private static final byte SE = (byte)-16; //240 Sub End   F0
//   private static final byte EOR = (byte)-17; //239 End of Record  EF
//   private static final byte TERMINAL_TYPE = (byte)24;     // 18
//   private static final byte OPT_END_OF_RECORD = (byte)25;  // 19
//   private static final byte TRANSMIT_BINARY = (byte)0;     // 0
//   private static final byte QUAL_IS = (byte)0;             // 0
//   private static final byte TIMING_MARK = (byte)6;         // 6
//   private static final byte NEW_ENVIRONMENT = (byte)39;         // 27
//   private static final byte IS = (byte)0;         // 0
//   private static final byte SEND = (byte)1;         // 1
//   private static final byte INFO = (byte)2;         // 2
//   private static final byte VAR = (byte)0;         // 0
//   private static final byte VALUE = (byte)1;         // 1
//   private static final byte NEGOTIATE_ESC = (byte)2;         // 2
//   private static final byte USERVAR = (byte)3;         // 3

   // miscellaneous
//   private static final byte ESC = 0x04; // 04
//   private static final char char0 = 0;

//   private static final byte CMD_READ_IMMEDIATE_ALT = (byte)0x83; // 131


}
--- NEW FILE: ScreenField.java ---
/**
 * Title: tn5250J
 * Copyright:   Copyright (c) 2001
 * Company:
 * @author  Kenneth J. Pouncey
 * @version 0.4
 *
 * Description:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307 USA
 *
 */
package org.tn5250j.framework.tn5250;

public class ScreenField {

   protected ScreenField(Screen5250 s) {

      this.s = s;

   }

   protected ScreenField setField(int attr, int len, int ffw1, int ffw2,
                     int fcw1, int fcw2) {

      return setField(attr,
               s.getCurrentRow() - 1,
               s.getCurrentCol() - 1,
               len,
               ffw1,
               ffw2,
               fcw1,
               fcw2);
   }

   protected ScreenField setField(int attr, int row, int col, int len, int ffw1, int ffw2,
                     int fcw1, int fcw2) {

//      startRow = row;
//      startCol = col;
      startPos = (row * s.getCols()) + col;
      endPos = startPos + length -1;
      cursorProg = 0;
      fieldId = 0;
      length = len;
      endPos = startPos + length -1;
      this.attr = attr;
      setFFWs(ffw1,ffw2);
      setFCWs(fcw1,fcw2);

      next = null;
      prev = null;

      return this;

   }

   public int getAttr(){
      return attr;
   }

   public int getHighlightedAttr(){
      return (fcw2 & 0x0f) | 0x20;
   }

   public int getLength(){
      return length;
   }

   protected boolean setFFWs(int ffw1, int ffw2) {

      this.ffw1 = ffw1;
      this.ffw2 = ffw2;

      int adj = getAdjustment();

      if (adj  > 0) {
         checkCanSend = true;

         switch (adj) {

            case 5:
            case 6:
               rightAdjd = false;
               break;
            case 7:
               manditoried = false;
               break;
         }

      }
      mdt = (ffw1 & 0x8 ) == 0x8;
//      if (mdt)
//         s.masterMDT = true;
      return mdt;
   }


   public int getFFW1(){
      return ffw1;
   }
   public int getFFW2(){
      return ffw2;
   }

   protected void setFCWs(int fcw1, int fcw2) {

      this.fcw1 = fcw1;
      this.fcw2 = fcw2;

//      if ((fcw1 & 0x88) == 0x88) {
      if (fcw1 == 0x88) {

         cursorProg = fcw2;
      }
   }

   public int getFCW1(){
      return fcw1;
   }

   public int getFCW2(){
      return fcw2;
   }

   public int getFieldLength(){
      return length;
   }

   public int getCursorProgression() {
      return cursorProg;
   }

   public int getFieldId() {
      return fieldId;
   }

   protected void setFieldId(int fi) {
      fieldId = fi;
   }

   public int getCursorRow() {

      return cursorPos / s.getCols();
   }

   public int getCursorCol() {

      return cursorPos % s.getCols();
   }

   protected void changePos(int i) {

      cursorPos += i;

   }

   public String getText() {


      StringBuffer text = new StringBuffer();
      getKeyPos(endPos);
      int x = length;
      text.setLength(x);
      int nc = s.getCols();
      while (x-- > 0) {

         // here we manipulate the unicode characters a little for attributes
         //    that are imbedded in input fields.  We will offset them by unicode
         //    \uff00.   All routines that process these fields will have to
         //    return them to their proper offsets.
         //    example:
         //    if we read an attribute byte of 32 for normal display the unicode
         //       character for this is \u0020 and the unicode character for
         //       a space is also \u0020 thus the offset.
//         if (s.screen[cursorPos].attributePlace) {
         if (s.planes.isAttributePlace(cursorPos)) {
//            text.setCharAt(x,(char)('\uff00' + s.screen[cursorPos].attr));
            text.setCharAt(x,(char)('\uff00' + s.planes.getCharAttr(cursorPos)));
         }
         else {
//            text.setCharAt(x,s.screen[cursorPos].getChar());
            text.setCharAt(x,s.planes.getChar(cursorPos));
         }
         changePos(-1);

      }

      // Since only the mdt of the first continued field is set we will get
      //    the text of the next continued field if we are dealing with continued
      //    fields.  See routine setMDT for the whys of this.  This is only
      //    executed if this is the first field of a continued field.
      if (isContinued() && isContinuedFirst()) {
         ScreenField sf = this;
         do {
            sf = sf.next;
            text.append(sf.getText());
         }
         while (!sf.isContinuedLast());

         sf = null;
      }

      return text.toString();

   }

   public void setFieldChar(char c) {

      int x = length;
      cursorPos = startPos;
      while (x-- > 0) {
//         s.screen[cursorPos].setChar(c);
         s.planes.setChar(cursorPos,c);
         changePos(1);
      }

   }

   public void setFieldChar(int lastPos, char c) {

      int x = endPos - lastPos + 1;
      cursorPos = lastPos;
      while (x-- > 0) {
//         s.screen[cursorPos].setChar(c);
         s.planes.setChar(cursorPos,c);
         s.setDirty(cursorPos);
         changePos(1);
      }
   }

   protected void setRightAdjusted() {
      rightAdjd = true;
   }

   protected void setManditoryEntered() {

      manditoried = true;
   }

   protected void resetMDT() {
      mdt = false;

   }

   protected void setMDT() {

      //  get the first field of a continued edit field if it is continued
      if (isContinued() && !isContinuedFirst()) {
         ScreenField sf = prev;
         while (sf.isContinued() && !sf.isContinuedFirst()) {

            sf = sf.prev;

         }
         sf.setMDT();
         sf = null;
      }
      else {
         mdt = true;
      }

   }

   public boolean isBypassField() {

      return (ffw1 & 0x20) == 0x20;

   }

   public int getAdjustment () {

      return (ffw2 & 0x7);
   }

   // is field exit required
   public boolean isFER () {

      return (ffw2 & 0x40) == 0x40;
   }

   // is field manditory enter
   public boolean isMandatoryEnter() {

      return (ffw2 & 0x8) == 0x8;

   }

   public boolean isToUpper() {

      return (ffw2 & 0x20) == 0x20;

   }

   // bits 5 - 7
   public int getFieldShift () {

      return (ffw1 & 0x7);

   }

   public boolean isHiglightedEntry() {

      return (fcw1 == 0x89);

   }

   public boolean isAutoEnter() {

      return (ffw2 & 0x80) == 0x80;

   }

   public boolean isSignedNumeric () {

      return (getFieldShift() == 7);

   }

   public boolean isNumeric () {

      return (getFieldShift() == 3);

   }

   public boolean isDupEnabled() {

      return (ffw1 & 0x10) == 0x10;

   }

   public boolean isContinued() {

      return (fcw1 & 0x86) == 0x86 && (fcw2 >= 1 && fcw2 <= 3) ;

   }

   public boolean isContinuedFirst() {

      return (fcw1 & 0x86) == 0x86 && (fcw2 == 1);

   }

   public boolean isContinuedMiddle() {

      return (fcw1 & 0x86) == 0x86 && (fcw2 == 3);

   }

   public boolean isContinuedLast() {

      return (fcw1 & 0x86) == 0x86 && (fcw2 == 2);

   }

   protected boolean isCanSend() {

      int adj = getAdjustment();

      // here we need to check the Field Exit Required value first before checking
      //   the adjustments.  If the last character has been entered and we are
      //   now setting past the last position then we are allowed to process the
      //   the field without continuing.
      if (isFER() && cursorPos > endPos) {
         return true;
      }

      // signed numeric fields need to be checked as well.
      if (isSignedNumeric() && cursorPos < endPos - 1) {
         return false;
      }

      if (adj  > 0) {

         switch (adj) {

            case 5:
            case 6:
               return rightAdjd;
            case 7:
               return manditoried;
            default:
               return true;
         }

      }
      return true;
   }

   protected int getKeyPos(int row1, int col1) {

      int x = ((row1 * s.getCols()) + col1);
      int y = x - startPos();
      cursorPos = x;

      return y;
   }

   protected int getKeyPos(int pos) {

      int y = pos - startPos();
      cursorPos = pos;

      return y;
   }

   public int getCurrentPos() {

      return cursorPos;
   }

   public boolean withinField (int pos) {

      if (pos >= startPos && pos <= endPos)
            return true;
      return false;

   }

   public int startPos() {

      return startPos;
   }

   /**
    * Get the starting row of the field.  Offset is 0 so row 6 returned
    *    is row 7 mapped to screen
    * @return int starting row of the field offset 0
    */
   public int startRow() {

      return startPos / s.getCols();

   }

   /**
    * Get the starting column of the field.  Offset is 0 so column 6 returned
    *    is column 7 mapped to screen
    * @return int starting column of the field offset 0
    */
   public int startCol() {

      return startPos % s.getCols();

   }

   public int endPos() {

      return endPos;

   }

   public String toString() {
      int fcw = (fcw1 & 0xff) << 8 | fcw2 & 0xff;
      return "startRow = " + startRow() + " startCol = " + startCol() +
            " length = " + length + " ffw1 = (0x" + Integer.toHexString(ffw1) +
            ") ffw2 = (0x" + Integer.toHexString(ffw2) +
            ") fcw1 = (0x" + Integer.toHexString(fcw1) +
            ") fcw2 = (0x" + Integer.toHexString(fcw2) +
            ") fcw = (" + Integer.toBinaryString(fcw) +
            ") fcw hex = (0x" + Integer.toHexString(fcw) +
            ") is bypass field = " + isBypassField() +
            ") is autoenter = " + isAutoEnter() +
            ") is manditoryenter = " + isMandatoryEnter() +
            ") is field exit required = " + isFER() +
            ") is Numeric = " + isNumeric() +
            ") is Signed Numeric = " + isSignedNumeric() +
            ") is cursor progression = " + (fcw1 == 0x88) +
            ") next progression field = " + fcw2 +
            ") field id " + fieldId +
            " continued edit field = " + isContinued() +
            " first continued edit field = " + isContinuedFirst() +
            " middle continued edit field = " + isContinuedMiddle() +
            " last continued edit field = " + isContinuedLast() +
            " mdt = " + mdt;
   }

   int startPos = 0;
   int endPos = 0;
   boolean mdt = false;
   protected boolean checkCanSend;
   protected boolean rightAdjd;
   protected boolean manditoried;
   boolean canSend = true;
   int attr = 0;
   int length = 0;
   int ffw1 = 0;
   int ffw2 = 0;
   int fcw1 = 0;
   int fcw2 = 0;
   int cursorPos = 0;
   Screen5250 s;
   int cursorProg = 0;
   int fieldId = 0;
   ScreenField next = null;
   ScreenField prev = null;

}
--- NEW FILE: Screen5250.java ---
/**
 * Title: Screen5250.java
 * Copyright:   Copyright (c) 2001 - 2004
 * Company:
 * @author  Kenneth J. Pouncey
 * @version 0.5
 *
 * Description:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
[...4594 lines suppressed...]
//				numRows, Color.black, defaultPrinter, (Session) gui);
//
//		printerThread.start();
//
//	}

//	// ADDED BY BARRY
//	public ScreenChar[] getCharacters() {
//		return this.screen;
//	}
	// ADDED BY BARRY - changed by Kenneth to use the character plane
   //  This should be replaced with the getPlane methods when they are implemented
	public char[] getCharacters() {
		return planes.screen;
	}

//	public Gui5250 getGui() {
//		return this.gui;
//	}
}

--- NEW FILE: ScreenPlanes.java ---
/**
 * Title: ScreenPlanes.java
 * Copyright:   Copyright (c) 2001
 * Company:
 * @author  Kenneth J. Pouncey
 * @version 0.5
 *
 * Description:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
[...1056 lines suppressed...]
	      hs = false;
	   // now lets make sure there are no more than numSuff spaces after option
	   while (hs && (++sp < lenScreen && screen[sp] <= ' '
	                  || screen[sp] == suff )) {
	      if (sp - x >= numSuff || screen[sp] == suff ||
	                  screen[sp] == '.' ||
	               screen[sp] == '*') {
	         hs =false;
	         break;
	      }
	   }
	   if (hs && !Character.isLetterOrDigit(screen[sp]))
	      hs = false;
	   if (hs) {
	      return os;
	   }
	   return -1;
	}

}
--- NEW FILE: ScreenOIA.java ---
/**
 * <p>Title: ScreenOIA.java</p>
 * <p>Description: Main interface to control Operator information area screen</p>
 * <p>Copyright: Copyright (c) 2000 - 2002</p>
 * <p>
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307 USA
 * </p>
 * @author Kenneth J. Pouncey
 * @version 0.5
 */
package org.tn5250j.framework.tn5250;

import java.util.*;

import org.tn5250j.event.ScreenOIAListener;
import org.tn5250j.framework.tn5250.*;

/**
 * The operator information area of a host session. This area is used to provide
 * status information regarding the state of the host session and location of
 * the cursor.  A ScreenOIA object can be obtained using the GetOIA() method on
 * an instance of Screen5250.
 *
 *
 */
public class ScreenOIA
  {
   // OIA_LEVEL
   public static final int OIA_LEVEL_INPUT_INHIBITED   =  1;
   public static final int OIA_LEVEL_NOT_INHIBITED   =  2;
   public static final int OIA_LEVEL_MESSAGE_LIGHT_ON  =  3;
   public static final int OIA_LEVEL_MESSAGE_LIGHT_OFF  =  4;
   public static final int OIA_LEVEL_AUDIBLE_BELL  =  5;
   public static final int OIA_LEVEL_INSERT_MODE  =  6;
   public static final int OIA_LEVEL_KEYBOARD  =  7;
   public static final int OIA_LEVEL_CLEAR_SCREEN  =  8;
   public static final int OIA_LEVEL_SCREEN_SIZE  =  9;
   public static final int OIA_LEVEL_INPUT_ERROR   =  10;
   public static final int OIA_LEVEL_KEYS_BUFFERED   =  11;
   public static final int OIA_LEVEL_SCRIPT   =  12;

   // INPUTINHIBITED
   public static final int INPUTINHIBITED_NOTINHIBITED   =  0;
   public static final int INPUTINHIBITED_SYSTEM_WAIT   =  1;
   public static final int INPUTINHIBITED_COMMCHECK   =  2;
   public static final int INPUTINHIBITED_PROGCHECK   =  3;
   public static final int INPUTINHIBITED_MACHINECHECK   =  4;
   public static final int INPUTINHIBITED_OTHER   =  5;

   public ScreenOIA (Screen5250 screen) {

      source = screen;

   }

   public boolean isInsertMode() {

      return insertMode;
   }

   protected void setInsertMode(boolean mode) {

      level = OIA_LEVEL_INSERT_MODE;
      insertMode = mode;
      fireOIAChanged(ScreenOIAListener.OIA_CHANGED_INSERT_MODE);
   }

   public int getCommCheckCode() {

      return commCheck;
   }

   public int getInputInhibited() {

      return inputInhibited;
   }

   public int getMachineCheckCode() {

      return machineCheck;
   }

   public int getOwner() {
      return owner;
   }

   public int getProgCheckCode() {
      return 0;
   }

	/**
	 * Is the keyboard locked or not
	 *
	 * @return locked or not
	 */
   public boolean isKeyBoardLocked() {
      return locked;
   }

   public boolean isKeysBuffered() {
      return keysBuffered;
   }

   public void setKeysBuffered(boolean kb) {
      level = OIA_LEVEL_KEYS_BUFFERED;
      boolean oldKB = keysBuffered;
      keysBuffered = kb;
      if (keysBuffered != oldKB)
         fireOIAChanged(ScreenOIAListener.OIA_CHANGED_KEYS_BUFFERED);
   }

   protected void setKeyBoardLocked(boolean lockIt) {
      level = OIA_LEVEL_KEYBOARD;
      boolean oldLocked = locked;
      locked = lockIt;
		if (!lockIt) {

			if (isKeysBuffered()) {
				source.sendKeys("");
			}
		}

      if (locked != oldLocked)
         fireOIAChanged(ScreenOIAListener.OIA_CHANGED_KEYBOARD_LOCKED);
   }

   public boolean isMessageWait() {
      return messageWait;
   }

   protected void setMessageLightOn() {
      level = OIA_LEVEL_MESSAGE_LIGHT_ON;
      messageWait = true;
      fireOIAChanged(ScreenOIAListener.OIA_CHANGED_MESSAGELIGHT);
   }

   protected void setMessageLightOff() {
      level = OIA_LEVEL_MESSAGE_LIGHT_OFF;
      messageWait = false;
      fireOIAChanged(ScreenOIAListener.OIA_CHANGED_MESSAGELIGHT);
   }

   public void setScriptActive(boolean running) {
      level = OIA_LEVEL_SCRIPT;
      scriptRunning = running;
      fireOIAChanged(ScreenOIAListener.OIA_CHANGED_SCRIPT);
   }

   public boolean isScriptActive() {
      return scriptRunning;
   }

   public void setAudibleBell() {
      level = OIA_LEVEL_AUDIBLE_BELL;
      fireOIAChanged(ScreenOIAListener.OIA_CHANGED_BELL);
   }

   protected void clearScreen() {
      level = OIA_LEVEL_CLEAR_SCREEN;
      fireOIAChanged(ScreenOIAListener.OIA_CHANGED_CLEAR_SCREEN);
   }

   /**
    * Add a ScreenOIAListener to the listener list.
    *
    * @param listener  The ScreenOIAListener to be added
    */
   public void addOIAListener(ScreenOIAListener listener) {

      if (listeners == null) {
          listeners = new java.util.Vector(3);
      }
      listeners.addElement(listener);

   }

   /**
    * Remove a iOhioSessionListener from the listener list.
    *
    * @param listener  The iOhioSessionListener to be removed
    */
   public void removeOIAListener(ScreenOIAListener listener) {

      if (listeners == null) {
          return;
      }
      listeners.removeElement(listener);
   }

   // object methods
   public Screen5250 getSource() {

      return source;
   }


   public void setSource(Screen5250 screen) {

      source = screen;

   }

   public void setOwner(int newOwner) {

      owner = newOwner;

   }

   public int getLevel() {

      return level;
   }

   public String getInhibitedText() {
      return inhibitedText;
   }

   public void setInputInhibited(int inhibit , int whatCode) {
      setInputInhibited(inhibit, whatCode, null);
   }

   public void setInputInhibited(int inhibit , int whatCode, String message) {

      inputInhibited = inhibit;
      level = OIA_LEVEL_INPUT_INHIBITED;
      inhibitedText = message;

//      if (saveInhibit != inhibit || saveInhibitLevel != whatCode) {
         switch(inhibit) {

            case INPUTINHIBITED_COMMCHECK :
               commCheck = whatCode;
               break;
            case INPUTINHIBITED_PROGCHECK :
               progCheck = whatCode;
               break;
            case INPUTINHIBITED_MACHINECHECK :
               machineCheck = whatCode;
               break;
            case INPUTINHIBITED_SYSTEM_WAIT :
               level = whatCode;
               break;
            case INPUTINHIBITED_NOTINHIBITED :
               level = whatCode;
               break;
         }

         saveInhibit = inhibit;
         saveInhibitLevel = level;
         fireOIAChanged(ScreenOIAListener.OIA_CHANGED_INPUTINHIBITED);
//      }
   }

   /**
    * Notify all registered listeners of the onOIAChanged event.
    *
    */
   private void fireOIAChanged(int change) {

      if (listeners != null) {
         int size = listeners.size();
         for (int i = 0; i < size; i++) {
            ScreenOIAListener target =
                    (ScreenOIAListener)listeners.elementAt(i);
            target.onOIAChanged((ScreenOIA)this, change);
         }
      }
   }

   Vector listeners = null;
   private boolean insertMode;
   private boolean locked;
   private boolean keysBuffered;
   private int size = 0;
   private int owner = 0;
   private int level = 0;
   private Screen5250 source = null;
   private int commCheck = 0;
   private int progCheck = 0;
   private int machineCheck = 0;
   private boolean messageWait;
   private boolean scriptRunning;
   private int inputInhibited = INPUTINHIBITED_NOTINHIBITED;
   private int saveInhibit = -1;
   private int saveInhibitLevel = -1;
   private String inhibitedText;

}

--- NEW FILE: Stream5250.java ---
/**
 * Title: tn5250J
 * Copyright:   Copyright (c) 2001
 * Company:
 * @author  Kenneth J. Pouncey
 * @version 0.4
 *
 * Description:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307 USA
 *
 */
package org.tn5250j.framework.tn5250;

public class Stream5250 {

    public int streamSize;
    public int opCode;
    public int dataStart;
    public int pos;
    public byte buffer[];

    public Stream5250(byte abyte0[]) {
        buffer = abyte0;
        // size without end of record 0xFF 0xEF
        streamSize = (abyte0[0] & 0xff) << 8 | abyte0[1] & 0xff;
        opCode = abyte0[9];
        dataStart = 6 + abyte0[6];
        pos = dataStart;
    }

    public final int getOpCode() {
        return opCode;
    }

    public final byte getNextByte()
        throws Exception  {
        if(pos > buffer.length)
            throw new Exception("Buffer length exceeded: " + pos);
        else
            return buffer[pos++];
    }

    public final void setPrevByte()
        throws Exception {
        if(pos == 0) {
            throw new Exception("Index equals zero.");
        }
        else {
            pos--;
            return;
      }
   }

   /**
    * Returns where we are in the buffer
    * @return position in the buffer
    */
   public final int getCurrentPos() {
      return pos;
   }

   public final byte getByteOffset(int off)
        throws Exception  {

        if((pos + off ) > buffer.length)
            throw new Exception("Buffer length exceeded: " + pos);
        else
            return buffer[pos + off];

   }

   public final boolean size() {
      return pos >= streamSize;
   }


   /**
    * Determines if any more bytes are available in the buffer to be processed.
    * @return yes or no
    */
   public final boolean hasNext() {

//      return pos >= buffer.length;
      return pos < streamSize;
   }

   /**
    * This routine will retrieve a segment based on the first two bytes being
    * the length of the segment.
    *
    * @return a new byte array containing the bytes of the segment.
    * @throws Exception
    */
   public final byte[] getSegment() throws Exception {

      // The first two bytes contain the length of the segment.
      int length = ((buffer[pos] & 0xff )<< 8 | (buffer[pos+1] & 0xff));
      // allocate space for it.
      byte[] segment = new byte[length];

      getSegment(segment,length,true);

      return segment;
   }


   /**
    * This routine will retrieve a byte array based on the first two bytes being
    * the length of the segment.
    *
    * @param segment - byte array
    * @param length - length of segment to return
    * @param adjustPos - adjust the position of the buffer to the end of the seg
    *                      ment
    * @throws Exception
    */
   public final void getSegment(byte[] segment, int length, boolean adjustPos)
               throws Exception {

      // If the length is larger than what is available throw an exception
      if((pos + length ) > buffer.length)
            throw new Exception("Buffer length exceeded: start " + pos
                                 + " length " + length);
      // use the system array copy to move the bytes from the buffer
      //    to the allocated byte array
      System.arraycopy(buffer,pos,segment,0,length);

      // update the offset to be after the segment so the next byte can be read
      if (adjustPos)
         pos +=length;

   }

}

--- NEW FILE: ScreenFields.java ---
/**
 * Title: tn5250J
 * Copyright:   Copyright (c) 2001
 * Company:
 * @author  Kenneth J. Pouncey
 * @version 0.5
 *
 * Description:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307 USA
 *
 */
package org.tn5250j.framework.tn5250;

import java.io.ByteArrayOutputStream;
import org.tn5250j.encoding.CodePage;
import org.tn5250j.TN5250jConstants;

public class ScreenFields implements TN5250jConstants {

   private ScreenField[] screenFields;
   private ScreenField currentField;
   private ScreenField saveCurrent;
   private int sizeFields;
   private boolean cpfExists;
   private int nextField;
   private int fieldIds;
   private Screen5250 screen;
   private boolean masterMDT;
   protected boolean currentModified;

   public ScreenFields(Screen5250 s) {

      screen = s;
      screenFields = new ScreenField[256];
   }

   public void clearFFT() {

      sizeFields = nextField = fieldIds = 0;
      cpfExists = false;   // clear the cursor progression fields flag
      currentField = null;
      masterMDT = false;

   }

   protected boolean existsAtPos(int lastPos) {

      ScreenField sf = null;

      // from 14.6.12 for Start of Field Order 5940 function manual
      //  examine the format table for an entry that begins at the current
      //  starting address plus 1.
      for (int x = 0;x < sizeFields; x++) {
         sf = screenFields[x];

         if (lastPos == sf.startPos()) {
            currentField = sf;
            currentModified = false;
            return true;
         }

      }

      return false;
   }

   public boolean isMasterMDT() {
      return masterMDT;
   }

   protected void setMasterMDT() {
      masterMDT = true;
   }

   public boolean isCurrentField() {
      return currentField == null;
   }

   public boolean isCurrentFieldFER() {
      return currentField.isFER();
   }

   public boolean isCurrentFieldDupEnabled() {
      return currentField.isDupEnabled();
   }

   public boolean isCurrentFieldToUpper() {
      return currentField.isToUpper();
   }

   public boolean isCurrentFieldBypassField() {
      return currentField.isBypassField();
   }

   public boolean isCurrentFieldHighlightedEntry() {
      if (currentField != null)
         return currentField.isHiglightedEntry();
      else
         return false;
   }

   public boolean isCurrentFieldAutoEnter() {
      return currentField.isAutoEnter();
   }

   public boolean withinCurrentField(int pos) {
      return currentField.withinField(pos);
   }

   public boolean isCurrentFieldContinued() {
      return currentField.isContinued();
   }

   public boolean isCurrentFieldContinuedFirst() {
      return currentField.isContinuedFirst();
   }

   public boolean isCurrentFieldContinuedMiddle() {
      return currentField.isContinuedMiddle();
   }

   public boolean isCurrentFieldContinuedLast() {
      return currentField.isContinuedLast();
   }

   public boolean isCurrentFieldModified() {
      return currentModified;
   }

   /**
    * This routine is used to check if we can send the Aid key to the host
    *
    * Taken from Section  16.2.1.2 Enter/Rec Adv Key
    *
    * In the normal unlocked state, when the workstation operator presses the
    * Enter/Rec Adv key:
    *
    * 1. The 5494 checks for the completion of mandatory-fill, self-check, and
    *    right-adjust fields when in an active field. (An active field is one in
    *    which the workstation operator has begun entering data.) If the
    *    requirements of the field have not been satisfied, an error occurs.
    *
    * @return
    *
    */
   public boolean isCanSendAid() {

      // We also have to check if we are still in the field.
      if (currentField != null &&
            (currentField.getAdjustment() > 0 || currentField.isSignedNumeric())
             && currentModified && isInField()
            && !currentField.isCanSend())

         return false;
      else
         return true;

   }

   protected void saveCurrentField() {
      saveCurrent = currentField;
   }

   protected void restoreCurrentField() {
      currentField = saveCurrent;
   }

   protected void setCurrentField(ScreenField sf) {
      currentField = sf;
   }

   protected void setCurrentFieldMDT() {
      currentField.setMDT();
      currentModified = true;
      masterMDT = true;
   }

   protected void setCurrentFieldFFWs(int ffw1, int ffw2) {

      masterMDT = currentField.setFFWs(ffw1,ffw2);

   }


   protected ScreenField setField(int attr, int row, int col, int len, int ffw1,
                           int ffw2, int fcw1, int fcw2) {

      ScreenField sf = null;
      screenFields[nextField] = new ScreenField(screen);
      screenFields[nextField].setField(attr,row,col,len,ffw1,ffw2,fcw1,fcw2);
      sf = screenFields[nextField++];

      sizeFields++;


      // set the field id if it is not a bypass field
      // this is used for cursor progression
      //  changed this because of problems not allocating field id's for
      //  all fields.  kjp 2002/10/21
//      if (!sf.isBypassField())
      sf.setFieldId(++fieldIds);

      // check if the cursor progression field flag should be set.
//      if ((fcw1 & 0x88) == 0x88)
      if (fcw1 == 0x88)
         cpfExists = true;

      if (currentField != null) {
         currentField.next = sf;
         sf.prev = currentField;
      }

      currentField = sf;

      // check if the Modified Data Tag was set while creating the field
      if (!masterMDT)
         masterMDT = currentField.mdt;

      currentModified = false;

      return currentField;

   }

   public ScreenField getField(int index) {

      return screenFields[index];
   }

   public ScreenField getCurrentField() {
      return currentField;
   }

   public int getCurrentFieldPos() {
      return currentField.getCurrentPos();
   }

   protected int getCurrentFieldShift() {
      return currentField.getFieldShift();
   }

   public String getCurrentFieldText() {

      return currentField.getText();
   }

   public int getCurrentFieldHighlightedAttr(){
      return currentField.getHighlightedAttr();
   }

   public int getSize() {

      return sizeFields;
   }

   public boolean isInField(int pos) {
      return isInField(pos,true);
   }

   public boolean isInField() {
      return isInField(screen.getLastPos(),true);
   }

   public boolean isInField(int pos, boolean chgToField) {

      ScreenField sf;

      for (int x = 0;x < sizeFields; x++) {
         sf = screenFields[x];

         if (sf.withinField(pos)) {

            if (chgToField) {
               if (!currentField.equals(sf))
                  currentModified = false;
               currentField = sf;
            }
            return true;
         }
      }
      return false;

   }

   public ScreenField[] getFields () {
      ScreenField[] fields = new ScreenField[sizeFields];
      for (int x = 0; x < sizeFields; x++) {

         fields[x] = screenFields[x];
      }

      return fields;
   }

   public void gotoFieldNext() {

      // sanity check - we where getting null pointers after a restore of screen
      //   and cursor was not positioned on a field when returned
      //   *** Note *** to myself
      //   maybe this is fixed I will have to check this some time
      int lastPos = screen.getLastPos();

      if (currentField == null && (sizeFields != 0) && !isInField(lastPos,true)) {
         int pos = lastPos;
         screen.setCursorOff();
         screen.advancePos();
         lastPos = screen.getLastPos();
         while (!isInField() && pos != lastPos) {
            screen.advancePos();
         }
         screen.setCursorOn();
      }

      // if we are still null do nothing
      if (currentField == null)
         return;

      ScreenField sf = currentField;

      if (!sf.withinField(lastPos)) {
         screen.setCursorOff();

         if (sizeFields > 0) {

            // lets get the current position so we can test if we have looped
            //    the screen and not found a valid field.
            int pos = lastPos;
            int savPos = lastPos;
            boolean done = false;
            do {
               screen.advancePos();
               lastPos = screen.getLastPos();
               if (isInField(lastPos)
                   || pos==lastPos) {
                  if (!currentField.isBypassField()) {
                     screen.gotoField(currentField);
                     done = true;
                  }
               }
            }  while ( !done && lastPos != savPos);
         }
         currentModified = false;
         screen.setCursorOn();

      }
      else {
         if (!cpfExists) {
            do {

               sf = sf.next;
            }
            while ( sf != null && sf.isBypassField());

         }
         else {
            int f = 0;
            int cp = sf.getCursorProgression();

            if (cp == 0) {
               do {

                  sf = sf.next;
               }
               while ( sf != null && sf.isBypassField());

            }
            else {
               ScreenField sf1 = null;
               boolean found = false;
               while (!found && f < sizeFields) {

                  sf1 = screenFields[f++];
                  if (sf1.getFieldId() == cp)
                     found = true;
               }
               if (found)
                  sf = sf1;
               else {
                  do {
                     sf = sf.next;
                  }
                  while ( sf != null && sf.isBypassField());

               }
               sf1 = null;
            }
         }
         if (sf == null)
            screen.gotoField(1);
         else {
            currentField = sf;
            screen.gotoField(currentField);
         }

         currentModified = false;

      }
   }

   public void gotoFieldPrev() {

      ScreenField sf = currentField;
      int lastPos = screen.getLastPos();

      if (!sf.withinField(lastPos)) {
         screen.setCursorOff();

         if (sizeFields > 0) {
            // lets get the current position so we can test if we have looped
            //    the screen and not found a valid field.
            int pos = lastPos;
            int savPos = lastPos;
            boolean done = false;

            do {
               screen.changePos(-1);
               lastPos = screen.getLastPos();

               if (isInField(lastPos)
                  || (pos == lastPos)) {

                  if (!currentField.isBypassField()) {
                     screen.gotoField(currentField);
                     done = true;
                  }
               }
            } while ( !done && lastPos != savPos);
         }
         screen.setCursorOn();

      }
      else {

         if (sf.startPos() == lastPos) {
            if (!cpfExists) {

               do {
                  sf = sf.prev;
               }
               while ( sf != null && sf.isBypassField());
            }
            else {

               int f = 0;
               int cp = sf.getFieldId();
               ScreenField sf1 = null;
               boolean found = false;
               while (!found && f < sizeFields) {

                  sf1 = screenFields[f++];
                  if (sf1.getCursorProgression() == cp)
                     found = true;
               }
               if (found)
                  sf = sf1;
               else {
                  do {
                     sf = sf.prev;
                  }
                  while ( sf != null && sf.isBypassField());
               }
               sf1 = null;
            }
         }

         if (sf == null) {
            int size = sizeFields;
            sf = screenFields[size - 1];

            while (sf.isBypassField() && size-- > 0) {
               sf = screenFields[size];

            }
         }
         currentField = sf;
         currentModified = false;
         screen.gotoField(currentField);
      }
   }

   protected void readFormatTable(ByteArrayOutputStream baosp,int readType,
                                    CodePage codePage) {

      ScreenField sf;
      boolean isSigned = false;
      char c;

      if (masterMDT) {

         StringBuffer sb = new StringBuffer();
         for (int x = 0; x < sizeFields; x++) {
            isSigned = false;

            sf = screenFields[x];

            if (sf.mdt || (readType == CMD_READ_INPUT_FIELDS)) {

               sb.setLength(0);
               sb.append(sf.getText());


               if (readType == CMD_READ_MDT_FIELDS ||
                     readType == CMD_READ_MDT_IMMEDIATE_ALT) {
                  int len = sb.length() - 1;

                  // we strip out all '\u0020' and less
                  while (len >= 0 &&
//                     (sb.charAt(len) <= ' ' || sb.charAt(len) >= '\uff20' )) {
                     (sb.charAt(len) < ' ' || sb.charAt(len) >= '\uff20')) {

                     // if we have the dup character and dup is enabled then we
                     //    stop here
                     if (sb.charAt(len) == 0x1C && sf.isDupEnabled())
                        break;

                     sb.deleteCharAt(len--);
                  }

               }

//               System.out.println("field " + sf.toString());
//               System.out.println(">" + sb.toString() + "<");
//               System.out.println(" field is all nulls");
               if (sf.isSignedNumeric() && sb.length() > 0 && sb.charAt(sb.length() - 1) == '-') {
                  isSigned = true;
                  sb.setLength(sb.length() - 1);
               }

               int len3 = sb.length();

               if (len3 > 0 || (readType == CMD_READ_MDT_FIELDS ||
                       readType == CMD_READ_MDT_IMMEDIATE_ALT)) {

                  if ((readType == CMD_READ_MDT_FIELDS ||
                       readType == CMD_READ_MDT_IMMEDIATE_ALT)) {

                     baosp.write(17);   // start of field data
                     baosp.write(sf.startRow()+1);
                     baosp.write(sf.startCol()+1);
                  }

//                  int len = sb.length();
                  for (int k = 0; k < len3; k++) {
                     c = sb.charAt(k);
                     // here we have to check for special instances of the
                     //    characters in the string field.  Attribute bytes
                     //    are encoded with an offset of \uff00
                     //    This is a hack !!!!!!!!!!!
                     //    See ScreenField object for a description
                     if (c < ' ' || c >= '\uff20') {

                        // if it is an offset attribute byte we just pass
                        //    it straight on to the output stream
                        if (c >= '\uff20' && c <= '\uff3f') {
                           baosp.write(c - '\uff00');
                        }
                        else
                           // check for dup character
                           if (c == 0x1C)
                              baosp.write(c);
                           else
                              baosp.write(codePage.uni2ebcdic(' '));
                     }
                     else {
                        if (isSigned && k == len3 - 1) {
                           baosp.write(0xd0 | (0x0f & c));
                        }
                        else
                           baosp.write(codePage.uni2ebcdic(c));

                     }
                  }
               }
            }
         }
      }
   }

}
--- NEW FILE: DataStreamQueue.java ---
/**
 * Title: tn5250J
 * Copyright:   Copyright (c) 2001
 * Company:
 * @author  Kenneth J. Pouncey
 * @version 0.4
 *
 * Description:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307 USA
 *
 */
package org.tn5250j.framework.tn5250;

import java.util.Vector;

public class DataStreamQueue {

   private final Object lock = new Object();
   private final Vector vector;
   public DataStreamQueue () {
      vector = new Vector();
   }

   /**
    * @todo redo the throttling of large queues that are backed up
    *       This is the cause of numerous painting bugs.
    * @return a datastream object from queue
    * @throws InterruptedException
    */
   public Object get() throws InterruptedException {
      synchronized (lock) {
         // wait until there is something to read
         while (isEmpty()) {
            lock.wait();
         }

         /**
          * @todo here is the throttling code to look at
          *
          * just something here to try.  OK it works but we need to be a little
          *     more intelligent with the throttling.
          */
         if (vector.size() >= 20) {
            vector.remove(0);
            vector.remove(0);
            vector.remove(0);
            vector.remove(0);
            vector.remove(0);
            vector.remove(0);
            vector.remove(0);
            vector.remove(0);
            vector.remove(0);
            vector.remove(0);
            vector.remove(0);
            vector.remove(0);
            vector.remove(0);
            vector.remove(0);
            vector.remove(0);
            vector.remove(0);
            vector.remove(0);
            vector.remove(0);
//            System.out.println(vector.size());
         }
            // we have the lock and state we're seeking
         return vector.remove(0);
      }
   }

   public boolean isEmpty() {

      return vector.isEmpty();
   }

   public void clear() {

      synchronized (lock) {
         vector.clear();
         lock.notifyAll();
      }

   }

   public void put(Object o) {
      synchronized (lock) {
         vector.addElement(o);
//         if (vector.size() > 5)
//            System.out.println(vector.size());
         // tell waiting threads to wake up
         lock.notifyAll();
      }
   }
}


-------------------------------------------------------
This SF.Net email is sponsored by BEA Weblogic Workshop
FREE Java Enterprise J2EE developer tools!
Get your free copy of BEA WebLogic Workshop 8.1 today.
http://ads.osdn.com/?ad_id=4721&alloc_id=10040&op=click