package org.tn5250j.tools;

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

import java.awt.BorderLayout;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;
import java.util.Vector;

import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

import org.tn5250j.event.FTPStatusEvent;
import org.tn5250j.event.FTPStatusListener;
import org.tn5250j.framework.tn5250.tnvt;
import org.tn5250j.tools.filters.FileFieldDef;
import org.tn5250j.tools.filters.OutputFilterInterface;

public class FTP5250Prot {

   private Socket ftpConnectionSocket;
   private BufferedReader ftpInputStream;
   private PrintStream ftpOutputStream;
   private InetAddress localHost;
   private boolean loggedIn;
   private String lastResponse;
   private int lastIntResponse;
   private String hostName;
   private int timeout = 50000;
   private boolean connected;
   private String remoteDir;
   private ArrayList ffd;
   private tnvt vt;
   private int recordLength;
   private int recordOutLength;
   private int fileSize;
   private Vector<FTPStatusListener> listeners;
   private FTPStatusEvent status;
   private boolean aborted;
   private char decChar;
   private OutputFilterInterface ofi;
   private Vector members;
   private Thread getThread;

   public FTP5250Prot (tnvt v) {
      vt = v;
      status = new FTPStatusEvent(this);
      // obtain the decimal separator for the machine locale
      DecimalFormat formatter =
            (DecimalFormat)NumberFormat.getInstance(Locale.getDefault()) ;

      decChar = formatter.getDecimalFormatSymbols().getDecimalSeparator();
   }

   public void setOutputFilter (OutputFilterInterface o) {
      ofi = o;
   }

   public void setDecimalChar(char dec) {
      decChar = dec;
   }
   /**
    * Set up ftp sockets and connect to an as400
    */
   public boolean connect(String host, int port) {

      try {

         hostName = host;
         ftpConnectionSocket = new Socket(host, port);
         ftpConnectionSocket.setSoTimeout(timeout);
         localHost = ftpConnectionSocket.getLocalAddress();
         ftpInputStream = new BufferedReader(new InputStreamReader(ftpConnectionSocket.getInputStream()));
         ftpOutputStream = new PrintStream(ftpConnectionSocket.getOutputStream());
         parseResponse();
         fileSize = 0;

         if (lastIntResponse == 220) {
            connected = true;
            return true;
         }
         else {
            connected = false;
            return false;
         }
      }
      catch(Exception _ex) {
         return false;
      }

   }

   /**
    * Send quit command to ftp server and close connections
    */
   public void disconnect() {
      try {
         if (isConnected()) {
            executeCommand("QUIT");
            ftpOutputStream.close();
            ftpInputStream.close();
            ftpConnectionSocket.close();
            connected = false;
         }
      }
      catch(Exception _ex) { }
   }

   /**
    * returns whether or not the system is connected to an AS400 or not
    */
   public boolean isConnected() {

      return connected;
   }

   /**
    * Add a FTPStatusListener to the listener list.
    *
    * @param listener  The FTPStatusListener to be added
    */
   public synchronized void addFTPStatusListener(FTPStatusListener listener) {

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

   }

   /**
    * Notify all registered listeners of the FTPStatusEvent.
    *
    */
   private void fireStatusEvent() {

      if (listeners != null) {
         int size = listeners.size();
         for (int i = 0; i < size; i++) {
            FTPStatusListener target =
                    listeners.elementAt(i);
            target.statusReceived(status);
         }
      }
   }

   /**
    * Notify all registered listeners of the command status.
    *
    */
   private void fireCommandEvent() {

      if (listeners != null) {
         int size = listeners.size();
         for (int i = 0; i < size; i++) {
            FTPStatusListener target =
                    listeners.elementAt(i);
            target.commandStatusReceived(status);
         }
      }
   }

   /**
    * Notify all registered listeners of the file information status.
    *
    */
   private void fireInfoEvent() {

      if (listeners != null) {
         int size = listeners.size();
         for (int i = 0; i < size; i++) {
            FTPStatusListener target =
                    listeners.elementAt(i);
            target.fileInfoReceived(status);
         }
      }
   }

   /**
    * Remove a FTPStatusListener from the listener list.
    *
    * @param listener  The FTPStatusListener to be removed
    */
   public synchronized void removeFTPStatusListener(FTPStatusListener listener) {
      if (listeners == null) {
          return;
      }
      listeners.removeElement(listener);

   }

   /**
    * Send the user id and password to the connected host
    *
    * @param user  The user name
    * @param password  The password of the user
    */
   public boolean login(String user, String passWord) {

      if(ftpOutputStream == null)
      {
         printFTPInfo("Not connected to any server!");
         return false;
      }
      aborted = false;
      loggedIn = true;

      // send user command to server
      executeCommand("USER", user);

      // send password to server
      int resp = executeCommand("PASS", passWord);

      if(resp == 230) {
         loggedIn = true;
      }
      else {
         loggedIn = false;
         return false;
      }

      // check if the connected to server is an as400 or not
      if (!isConnectedToOS400()) {
         printFTPInfo("Remote server is not an OS/400.  Disconnecting!");
         disconnect();
      }

      getRemoteDirectory();
      return true;
   }

   /**
    * Print out the remote directory of the
    *
    *    not used right now but maybe in the future to obtain a list of
    *    files to select for download
    */
   protected void printDirListing () {

      try {

         Socket passSocket;

         // This will create a passive socket and execute the NLST command
         passSocket = createPassiveSocket("NLST");

         BufferedReader br = new BufferedReader(new InputStreamReader(passSocket.getInputStream()));
         String file;
         while((file = br.readLine()) != null) {
            System.out.println(file);
         }
         passSocket.close();
         parseResponse();
      }
      catch(Exception _ex) {

      }

   }

   /**
    * Checks whether the remote system is an OS400 or not
    */
   private boolean isConnectedToOS400 () {

      // get type of system connected to
      executeCommand("SYST");

      // check whether this is an OS/400 system or not
      if (lastResponse.toUpperCase().indexOf("OS/400") >= 0) return true;
      return false;
   }

   /**
    * Returns whether a field is selected for output or not
    *
    */
   public boolean isFieldSelected(int which) {

      FileFieldDef ffD = (FileFieldDef)ffd.get(which);
      return ffD.isWriteField();

   }

   /**
    * Select all the fields for output
    */
   protected void selectAll() {

      FileFieldDef f;
      for (int x = 0; x < ffd.size(); x++) {
         f = (FileFieldDef)ffd.get(x);
         f.setWriteField(true);
      }

   }

   /**
    * Unselect all fields for output.  This is a convenience method to unselect
    * all fields for a file that will only need to output a couple of fields
    */
   protected void selectNone() {
      FileFieldDef f;
      for (int x = 0; x < ffd.size(); x++) {
         f = (FileFieldDef)ffd.get(x);
         f.setWriteField(false);
      }

   }

   /**
    * Returns whether there are any fields selected or not
    */
   public boolean isFieldsSelected() {

      FileFieldDef f;
      for (int x = 0; x < ffd.size(); x++) {
         f = (FileFieldDef)ffd.get(x);
         if (f.isWriteField())
            return true;
      }
      return false;
   }

   /**
    * Convenience method to select or unselect a field for output
    */
   public void setFieldSelected(int which,boolean value) {

      FileFieldDef ffD = (FileFieldDef)ffd.get(which);
      ffD.setWriteField(value);

   }

   /**
    * Convenience method to return the name of a field
    */
   public String getFieldName(int which) {

      FileFieldDef ffD = (FileFieldDef)ffd.get(which);
      return ffD.getFieldName();

   }

   /**
    * Returns the number of fields in the File Field Definition array of fields
    * returned from the DSPFFD command
    */
   public int getNumberOfFields() {

      return ffd.size();
   }

   /**
    * Returns the remote directy
    */
   private void getRemoteDirectory() {

      executeCommand("PWD");

      int i = lastResponse.indexOf("\"");
      int j = lastResponse.lastIndexOf("\"");
      if(i != -1 && j != -1)
         remoteDir = lastResponse.substring(i + 1, j);
      else
         remoteDir = "Can't parse remote dir!";
   }

   /**
    * Creates a passive socket to the remote host to allow the transfer of data
    *
    */
   private Socket createPassiveSocket(String cmd) {

      ServerSocket ss = null;

      try {
         try {

            // The following line does not return the correct address of the
            //    host.  It is a know bug for linux BUG ID 4269403
            //    Since it is a know bug we have to hack the damn thing.
            //    We will use the address from localHost that was obtained
            //    from the ftpConnection socket.

//            byte abyte0[] = InetAddress.getLocalHost().getAddress();
            byte abyte0[] = localHost.getAddress();
            ss = new ServerSocket(0);
            ss.setSoTimeout(timeout);
            StringBuffer pb = new StringBuffer("PORT ");
            for(int i = 0; i < abyte0.length; i++) {
               pb.append(abyte0[i] & 0xff);
               pb.append(",");
            }

            pb.append(ss.getLocalPort() >>> 8 & 0xff);
            pb.append(",");
            pb.append(ss.getLocalPort() & 0xff);
            executeCommand(pb.toString());
            executeCommand(cmd);

            if(lastResponse.startsWith("5") || lastResponse.startsWith("4")) {
               return null;
            }

            Socket socket = ss.accept();
            socket.setSoTimeout(timeout);
            return socket;
         }
         catch(IOException ioexception) {
             printFTPInfo("I/O error while setting up a ServerSocket on the client machine!" + ioexception);
         }
         return null;
      }
      finally {
         try {
        	 if(ss!=null){
        		 ss.close();
        	 }
         }
         catch(IOException ioexception1) {
             printFTPInfo("createPassiveSocket.close() exception!" + ioexception1);
         }
      }
   }

   /**
    * Retrieves the File Field Definitions and Member information for the remote
    *    file to be transferred
    */
   protected boolean getFileInfo(String tFile, boolean useInternal) {

      int memberOffset = tFile.indexOf(".");
      String file2 = null;
      String member2 = null;

      if (memberOffset > 0) {

//         System.out.println(tFile.substring(0,memberOffset));
         file2 = tFile.substring(0,memberOffset);
         member2 = tFile.substring(memberOffset + 1);
      }
      else {
         file2 = tFile;
      }

      final String file = file2;
      final String member = member2;
      final boolean internal = useInternal;

      Runnable getInfo = new Runnable () {

         // set the thread to run.
         public void run() {

            executeCommand("RCMD","dspffd FILE(" + file + ") OUTPUT(*OUTFILE) " +
                        "OUTFILE(QTEMP/FFD) ");

            if (lastResponse.startsWith("2")) {
               if (loadFFD(internal)) {
                  if (lastResponse.startsWith("2")) {
                     if (getMbrInfo(file,member)) {
                        fireInfoEvent();
                     }
                  }
               }
            }
         }
      };

      Thread infoThread = new Thread(getInfo);
      infoThread.start();
      return true;

   }

   /**
    * Loads the File Field Definition array with the field information of the
    * remote file
    */
   private boolean loadFFD(boolean useInternal) {

      Socket socket = null;
      BufferedReader dis = null;
      String remoteFile = "QTEMP/FFD";
      String recLength = "";
      Vector allowsNullFields = null;

      try {
         socket = createPassiveSocket("RETR " + remoteFile);
         if(socket == null) {
             return false;
         }


         dis = new BufferedReader(new InputStreamReader(socket.getInputStream()));

         String data;
         if (ffd != null) {
            ffd.clear();
            ffd = null;
         }

         ffd = new ArrayList();
         while((data = dis.readLine()) != null) {
            FileFieldDef ffDesc = new FileFieldDef(vt,decChar);

            if (useInternal)
               // WHFLDI  Field name internal
               ffDesc.setFieldName(data.substring(129,129+10));
            else {

               String text = "";

               // first lets check the column headings
               text = data.substring(261,261+20).trim() + " " +
                        data.substring(281,281+20).trim() + " " +
                        data.substring(301,301+20).trim();

               if (text.length() > 0)
                  ffDesc.setFieldName(text);
               else {

                  // WHFLD  Field name text description
                  ffDesc.setFieldName(data.substring(168,168+50).trim());

                  // if the text description is blanks then use the field name
                  if (ffDesc.getFieldName().trim().length() == 0)
                     // WHFLDI  Field name internal
                     ffDesc.setFieldName(data.substring(129,129+10));
               }
            }


            // WHFOBO  Field starting offset
            ffDesc.setStartOffset(data.substring(149,149+5));
            // WHFLDB  Field length
            ffDesc.setFieldLength(data.substring(159,159+5));
            // WHFLDD  Number of digits
            ffDesc.setNumDigits(data.substring(164,164+2));
            // WHFLDP  Number of decimal positions
            ffDesc.setDecPositions(data.substring(166,166+2));
            // WHFLDT  Field type
            ffDesc.setFieldType(data.substring(321,321+1));
            // WHFTXT  Text description
            ffDesc.setFieldText(data.substring(168,168+50));

            // WHNULL Allow NULL Data
            if (data.substring(503,503+1).equals("Y")) {
               if (allowsNullFields == null)
                  allowsNullFields = new Vector(3);
               allowsNullFields.add(ffDesc.getFieldName());
               printFTPInfo("Warning -- File allows null fields!!!");
            }

            // set selected
            ffDesc.setWriteField(true);

            recLength = data.substring(124,124+5);

            ffd.add(ffDesc);
         }

         printFTPInfo("Field Information Transfer complete!");

         if (allowsNullFields != null) {
            JPanel jp = new JPanel();
            jp.setLayout(new BorderLayout());
            JLabel message = new JLabel(LangTool.getString("messages.nullFieldWarning"));
            JTextArea jta = new JTextArea(6,30);
            jta.setEditable(false);
            JScrollPane sp = new JScrollPane(jta);
            String text = new String();

            for (int x = 0; x < allowsNullFields.size(); x++)
               text += allowsNullFields.get(x) + "\n";

            jta.setText(text);

            jp.add(message,BorderLayout.NORTH);
            jp.add(sp,BorderLayout.CENTER);
            JOptionPane.showMessageDialog(null,jp,"Warning",JOptionPane.WARNING_MESSAGE);
         }

      }
      catch(Exception _ex) {
         printFTPInfo("I/O error!");
         return false;
      }
      finally {
         try {
             socket.close();
         }
         catch(Exception _ex) { }
         try {
             dis.close();
         }
         catch(Exception _ex) { }
      }

      int l = 0;
      int o = 0;
      int r = Integer.parseInt(recLength);
      FileFieldDef f;
      printFTPInfo("<----------------- File Field Information ---------------->");

      for (int x = 0; x < ffd.size(); x++) {
         f = (FileFieldDef)ffd.get(x);
         l += f.getFieldLength();
         o += f.getBufferOutLength();
         printFTPInfo(f.toString());
//         System.out.println(f);
      }
      recordLength = l;
      recordOutLength = o;
      System.out.println(r + " " + l + " " + o);
      parseResponse();
      return true;

   }

   /**
    * Executes the command to obtain the member information of the remote file
    */
   protected boolean getMbrInfo(String file, String member) {

      executeCommand("RCMD","dspfd FILE(" + file + ")" +
                        " TYPE(*MBR)" +
                        " OUTPUT(*OUTFILE) " +
                        "OUTFILE(QTEMP/FML) ");

      if (!lastResponse.startsWith("2"))
         return false;

      if (getMbrSize(member))

      if (!lastResponse.startsWith("2"))
         return false;

      return true;
   }

   /**
    * Parses the information obtained by the DSPFD command to obtain the size of
    * the remote file and member.
    */
   private boolean getMbrSize(String member) {

      boolean flag = true;

      if(ftpOutputStream == null) {
         printFTPInfo("Not connected to any server!");
         return false;
      }
      if(!loggedIn) {
         printFTPInfo("Login was not successful! Aborting!");
         return false;
      }

      Socket socket = null;
      DataInputStream datainputstream = null;
      executeCommand("TYPE","I");
      String remoteFile = "QTEMP/FML";
      members = new Vector(10);

      try {
         socket = createPassiveSocket("RETR " + remoteFile);
         if(socket != null) {
            datainputstream = new DataInputStream(socket.getInputStream());

            byte abyte0[] = new byte[858];

            int c = 0;
            int len = 0;
            StringBuffer sb = new StringBuffer(10);

            printFTPInfo("<----------------- Member Information ---------------->");

            for(int j = 0; j != -1 && !aborted;) {

               j = datainputstream.read();
               if(j == -1)
                  break;
               c ++;
               abyte0[len++] = (byte)j;

               if (len == abyte0.length) {
                  sb.setLength(0);

                  // the offset for member name MBNAME is 164 with offset of 1 but
                  //   we have to offset the buffer by 0 which makes it 164 - 1
                  //   or 163
                  for (int f = 0;f < 10; f++) {
                     sb.append(vt.getCodePage().ebcdic2uni(abyte0[163 + f] & 0xff));
                  }

                  printFTPInfo(sb + " " + As400Util.packed2int(abyte0,345,5));

                  members.add(new MemberInfo(sb.toString(), As400Util.packed2int(abyte0,345,5)));

                  len =0;

               }
            }

            printFTPInfo("Member list Transfer complete!");
         }
         else
            flag = false;

      }
      catch(Exception _ex) {
         printFTPInfo("Error! " + _ex);
         return false;
      }
      finally {
         try {
             socket.close();
         }
         catch(Exception _ex) { }
         try {
             datainputstream.close();
         }
         catch(Exception _ex) { }
      }

      parseResponse();
      return flag;

   }

   /**
    * Convenience method to return the file name and member that is being
    *    transferred
    */
   public String getFullFileName(String tFile) {

      int memberOffset = tFile.indexOf(".");
      String file2 = null;
      String member2 = null;

      if (memberOffset > 0) {
         file2 = tFile.substring(0,memberOffset);
         member2 = tFile.substring(memberOffset + 1);
      }
      else {
         file2 = tFile;
      }

      if (members != null) {

         if (member2 == null) {
            MemberInfo mi = (MemberInfo)members.get(0);
            fileSize = mi.getSize();
            status.setFileLength(mi.getSize());
            member2 = mi.getName();
         }
         else {

            Iterator<?> i = members.iterator();
            MemberInfo mi = null;

            while (i.hasNext()) {
               mi = (MemberInfo)i.next();
               if (mi.getName().trim().equalsIgnoreCase(member2.trim())) {
                  fileSize = mi.getSize();
                  status.setFileLength(mi.getSize());
//                  System.out.println(" found member " + mi.getName());
                  break;
               }

            }
         }
      }

      if (member2 != null) return file2.trim() + "." + member2.trim();
      return file2.trim();
   }

   /**
    * Convenience method to return the file size of the file and member that is
    * being transferred
    */
   public int getFileSize() {

      return fileSize;
   }

   /**
    * Print output of the help command
    *
    *    Not used just a test method for me
    */
   protected boolean printHelp() {

      executeCommand("HELP");
      return true;
   }

   /**
    * Transfer the file information to an output file
    */
   protected boolean getFile(String remoteFile, String localFile) {

      boolean flag = true;

      if(ftpOutputStream == null) {
         printFTPInfo("Not connected to any server!");
         return false;
      }
      if(!loggedIn) {
         printFTPInfo("Login was not successful! Aborting!");
         return false;
      }

      final String localFileF = localFile;
      final String remoteFileF = remoteFile;

      Runnable getRun = new Runnable () {

         // set the thread to run.
         public void run() {

            Socket socket = null;
            DataInputStream datainputstream = null;
            String localFileFull = localFileF;
            executeCommand("TYPE","I");

            try {
               socket = createPassiveSocket("RETR " + remoteFileF);
               if(socket != null) {
                  datainputstream = new DataInputStream(socket.getInputStream());

                  writeHeader(localFileFull);

                  byte abyte0[] = new byte[recordLength];
                  StringBuffer rb = new StringBuffer(recordOutLength);

                  int c = 0;
                  int len = 0;

                  for(int j = 0; j != -1 && !aborted;) {

                     j = datainputstream.read();
                     if(j == -1)
                        break;
                     c ++;
                     abyte0[len++] = (byte)j;
                     if (len == recordLength) {
                        rb.setLength(0);
                        parseFFD(abyte0,rb);
                        len =0;

                        status.setCurrentRecord(c / recordLength);
                        fireStatusEvent();
                     }
                     Thread.yield();
         //            if ((c / recordLength) == 200)
         //               aborted = true;
                  }
                  System.out.println(c);
                  if (c == 0) {
                     status.setCurrentRecord(c);
                     fireStatusEvent();
                  }
                  else {
                     if (!aborted)
                        parseResponse();
                  }
                  writeFooter();
//                  parseResponse();
                  printFTPInfo("Transfer complete!");

               }
            }
            catch(InterruptedIOException iioe) {
               printFTPInfo("Interrupted! " + iioe.getMessage());
            }
            catch(Exception _ex) {
               printFTPInfo("Error! " + _ex);
            }
            finally {
               try {
                   socket.close();
               }
               catch(Exception _ex) { }
               try {
                  datainputstream.close();
               }
               catch(Exception _ex) { }
               try {
                  writeFooter();
               }
               catch(Exception _ex) { }

               disconnect();
            }
         }
      };

      getThread = new Thread(getRun);
      getThread.setPriority(2);
      getThread.start();

      return flag;

   }

   /**
    * Parse the field field definition of the data and return a string buffer of
    * the output to be written
    */
   private void parseFFD(byte[] cByte,StringBuffer rb) {

      ofi.parseFields(cByte,ffd,rb);
   }

   /**
    * Abort the current file transfer
    */

   public void setAborted() {
      aborted = true;
   }

   /**
    * Print ftp command events and responses
    */
   private void printFTPInfo(String msgText) {

      status.setMessage(msgText);
      fireCommandEvent();

   }

   /**
    * Execute the command without parameters on the remote ftp host
    */

   private int executeCommand(String cmd) {
      return executeCommand(cmd, null);
   }

   /**
    * Execute a command with parameters on the remote ftp host
    */
   private int executeCommand(String cmd, String params) {

      if(ftpOutputStream == null) {
         printFTPInfo("Not connected to any server!");
         return 0;
      }

      if(!loggedIn) {
         printFTPInfo("Login was not successful! Aborting!");
         return 0;
      }

      if(params != null)
         ftpOutputStream.print(cmd + " " + params + "\r\n");
      else
         ftpOutputStream.print(cmd + "\r\n");

      if(!cmd.equals("PASS"))
         printFTPInfo("SENT: " + cmd + " " + (params != null ? params : ""));
      else
         printFTPInfo("SENT: PASS ****************");

      parseResponse();
      return lastIntResponse;
   }

   /**
    * Parse the response returned from the remote host to be used for success
    * or failure of a command
    */
   private String parseResponse() {
      try {

         if (ftpInputStream == null)
            return "0000 Response Invalid";

         String response = ftpInputStream.readLine();
         String response2 = response;
         boolean append = true;

         // we loop until we get a valid numeric response
         while(response2 == null ||
                     response2.length() < 4 ||
                     !Character.isDigit(response2.charAt(0)) ||
                     !Character.isDigit(response2.charAt(1)) ||
                     !Character.isDigit(response2.charAt(2)) ||
                     response2.charAt(3) != ' ') {
            if(append) {
               response += "\n";
               append = false;
            }
            response2 = ftpInputStream.readLine();
            response += response2 + "\n";
         }

         // convert the numeric response to an int for testing later
         lastIntResponse = Integer.parseInt(response.substring(0, 3));
         // save off for printing later
         lastResponse = response;
         // print out the response
         printFTPInfo(lastResponse);

         return lastResponse;
      }
//      catch (InterruptedIOException iioe) {
//
//         try {
//            ftpInputStream.close();
//         }
//         catch (IOException ieo) {
//
//         }
//         return "0000 Response Invalid";
//
//      }
      catch(Exception exception) {
         System.out.println(exception);
         exception.printStackTrace();
         return "0000 Response Invalid";
      }
   }

   /**
    * Write the html header of the output file
    */
   private void writeHeader(String fileName) throws
                           FileNotFoundException {

      ofi.createFileInstance(fileName);

      ofi.writeHeader(fileName,hostName,ffd,decChar);

   }

   /**
    * write the footer of the html output
    */
   private void writeFooter() {

      ofi.writeFooter(ffd);

   }

   class MemberInfo {

      private String name;
      private int size;

      MemberInfo(String name, int size) {

         this.name = name;
         this.size = size;

      }

      public String getName() {
         return name;
      }

      public int getSize() {

         return size;
      }



   }
}