//----------------------------------------------------------------------------
//
// Module:      FTPController.java      
//
// Description: FTP controller, inheritting from the model
//
// FESI Copyright (c) Jean-Marc Lugrin, 2000
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, 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
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//----------------------------------------------------------------------------

import java.awt.*;
import java.awt.event.*;
import java.io.*;

import com.oroinc.net.ftp.*;
import FESI.jslib.*;

/**
 * Controller class (in the sense of Model-View-Controller)
 * for FesiFTP.
 *<P>It is a subclass of the Model, which contains the low level
 * (gui independent) functions.
 */    
public class FTPController extends FTPModel {
    
    // The user interface owning this contoller
    private FTPInterface GUIinterface = null;
    
    private String eol = System.getProperty("line.separator", "\n");

    // Default values to propose to the user
    public String defaultServer = "";
    public String defaultUsername = "anonymous";
    public String defaultPassword = "anonymous";
    

    /**
     * Create a new FTP controller, owned by the FTPinterface
     *
     * @param   GUIinterface  The interface owning the controller
     */
    public FTPController(FTPInterface GUIinterface) {
        super();
	    this.GUIinterface = GUIinterface;
    }
    
    // ---------------------------------------------------------------------------
    // Proxies - used here but developed especially for access from EcmaScript
    // ---------------------------------------------------------------------------

    /**
     * log an error via the GUI
     *
     * @param   text  The text of the error
     */
    public void logError(String text) {
        GUIinterface.logMessage("** " + text + eol);
        GUIinterface.logError(text);
    }


    /**
     * Log a message (no EOL at end) via the GUI
     *
     * @param   text  The message to log
     */
    public void logMessage(String text) {
        GUIinterface.logMessage(text);
    }


    /**
     * Log a message (with EOL at end) via the GUI
     *
     * @param   text  The message to log
     */

    public void logMessageEol(String text) {
        GUIinterface.logMessage(text + eol);
    }
    

    /**
     * Request a string parameter from the user, with a default value
     *
     * @param   requestTitle  The title of the dialog box
     * @param   requestText   The label of the request
     * @param   defaultAnswer Default value of the request
     * @return  The entered string, null if cancelled  
     */
    public String requestDialog(
                    String requestTitle, 
                    String requestText,
                    String defaultAnswer){
       return GUIinterface.requestDialog(requestTitle, requestText, defaultAnswer);
   }

    /**
     * 
     * Request a string parameter from the user
     *
     * @param   requestTitle  The title of the dialog box
     * @param   requestText   The label of the request
     * @return  The entered string, null if cancelled  
     */
    public String requestDialog(
                    String requestTitle, 
                    String requestText){
       return GUIinterface.requestDialog(requestTitle, requestText, "");
   }



    /**
     * Request a server name, username and password from the user
     *
     * @param   defaultServer  
     * @param   defaultUsername  
     * @param   defaultPassword  
     * @return  A ConnectionInfo with the various names, null if cancelled
     */
   public ConnectionInfo requestConnectionInfo(String defaultServer,
                                                String defaultUsername,
                                                String defaultPassword) {
         return GUIinterface.requestConnectionInfo(defaultServer,
                                        defaultUsername, defaultPassword);
    }


    /**
     * Add the macro to the macro menu
     *
     * @param   name  The name of the macro
     * @param   text  The command to execute
     */

    public void addMacro(String name, String text) {
        GUIinterface.addMacro(name, text);
    }



    // ---------------------------------------------------------------------------
    // Remote commands
    // ---------------------------------------------------------------------------
    

    /**
     * Do a connection, requesting information from the user, allow the user
     * to cancel the request. Use the 'connected' property to check if a
     * connection was effectively established
     *
     * @return true if no error was detected    
     */
    public boolean doConnect() {
        if (isConnected()) {
            logError("Already connected");
            return false;
        } else {
            ConnectionInfo ci = requestConnectionInfo(defaultServer,
                                        defaultUsername, defaultPassword);
            if (ci==null) {
                logMessage(">> Connection request cancelled " + eol);
                return true; // Cancel is not an error
            } 
            String server = ci.server.trim();
            String username = ci.username.trim();
            String password = ci.password.trim();
            logMessage(">> Connecting to '" + server + "'" + eol);
            try {
                if (connect(server, username, password)) {
                    appendReplyStrings();
                    logMessage(">> Connected" + eol);
                    return true;
                }
            } catch (JSException ignore) {
            }
            appendReplyStrings();
            logError("Connect error: " + lastError);
            return false;
        }        
        
    }
    


    /**
     * Disconnect
     *
     * @return  true if an existing connection was disConnected  
     */
    public boolean doDisconnect() {
        if (!connected()) return false;
        logMessage(">> Disconnecting ... " + eol);
        try {    
           disconnect();
           appendReplyStrings();
           logMessage(eol + ">> Disconnection done" + eol);
           return true;
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
    }
     

    /**
     * Display the current working directory at the remote site
     *
     * @return true if no error    
     */
    public boolean doRemotePrintWorkingDirectory() {
        if (!connected()) return false; 
        try {   
            String dir = remoteGetWorkingDirectory();
            if (dir == null) {
               logError(lastError);
               return false;
           }
           logMessage(">> Current remote directory: " + eol + dir + eol);
           return true;
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
    }
   
    /**
     * Change the remote working directory to a value specified by the user
     *
     * @return true if no error    
     */
    public boolean doRemoteChangeWorkingDirectory() {
        if (!connected()) return false; 
        try { 
            String dir = requestDialog("Directory request","Directory:", "");
            if (dir==null || dir.trim().equals("")) {
                logMessage(">> Change remote working directory cancelled " + eol);
                return true; // Cancel is not an error
            }
            boolean success = remoteChangeWorkingDirectory(dir);
            if (success) {
                 String newDir = null;
                try {
                    newDir = remoteGetWorkingDirectory();
                } catch (JSException ignore) {
                    // If exception mode and server does not support PWD
                }
               if (newDir==null) {
                    logMessage(">> Remote working directory changed " + eol);
                } else {
                    logMessage(">> New remote working directory: " + eol + newDir + eol);
                }
                return true;
            }
            logError(lastError);
            return false;
       } catch (JSException ignore) {
            logError(lastError);
            return false;
       }
    }    
    

    /**
     * Change the remote working directory to its parent
     *
     * @return true if no error    
     */
    public boolean doRemoteChangeToParentDirectory() {
        if (!connected()) return false; 
        try {   
            boolean success = remoteChangeToParentDirectory();
            if (success) {
                String newDir = null;
                try {
                    newDir = remoteGetWorkingDirectory();
                } catch (JSException ignore) {
                    // If exception mode and server does not support PWD
                }
                if (newDir==null) {
                    logMessage(">> Remote working directory changed to parent" + eol);
                } else {
                    logMessage(">> New remote working directory: " + eol + newDir + eol);
                }
                return true;
            }
           logError(lastError);
           return false;
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
    }
    

    /**
     * List the name and content of the remote directory
     *
     * @return true if no error    
     */
    public boolean doRemoteListDirectory() {
        if (!connected()) return false;
        try {    
            logMessage(">> Remote directory listing" + eol);
                String dir = null;
                try {
                    dir = remoteGetWorkingDirectory();
                } catch (JSException ignore) {
                    // If exception mode and server does not support PWD
                }
            if (dir == null) {
                // Continue event if cannot get current directory
                logMessage("Current directory listing" + eol);
            } else {
                logMessage("Directory: " + dir + eol);
            }
            
            FTPFile[] ftpFiles = remoteGetFileList();
            if (ftpFiles == null) {
               logError(lastError);
               return false;
            }
            if (ftpFiles.length==0) {
               logMessage(" no file" + eol);
            } else {
               for (int i = 0; i<ftpFiles.length; i++) {
                   logMessage(" " + ftpFiles[i].toString() + eol);
               }
               logMessage("   " + ftpFiles.length + " file(s)" + eol);
            }
        } catch (JSException ignore) {
           logError(lastError);
           return false;
        }
        return true;
    }


    /**
     * Make a remote directory with the name specified by the user
     *
     * @return true if no error    
     */
    public boolean doRemoteMakeDirectory() {
        if (!connected()) return false;
        try {    
            String dir = requestDialog("Directory request","Directory:", "");
            if (dir==null || dir.trim().equals("")) {
                logMessage(">> Make remote directory cancelled " + eol);
                return true; // Cancel is not an error
            }
            if (!remoteMakeDirectory(dir)) {
                  logError(lastError);
                  return false;
            }
            logMessage(">> Remote directory '" + dir + "' created" + eol);
            return true;
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
    }
    


    /**
     * Rename a remote file specified by the user
     *
     * @return true if no error    
     */
    public boolean doRemoteRenameFile() {
        if (!connected()) return false;  
        try {  
            String srcFile = requestDialog("File request","File to rename:", "");
            if (srcFile==null || srcFile.trim().equals("")) {
                logMessage("Rename remote file cancelled " + eol);
                return true; // Cancel is not an error
            }
            String dstFile = requestDialog("File request","Rename to:", "");
            if (dstFile==null || dstFile.trim().equals("")) {
                logMessage("Rename remote file cancelled " + eol);
                return true; // Cancel is not an error
            } 
            if (!remoteRenameFile(srcFile, dstFile)) {
                logError(lastError);
                return false;
            }
            logMessage(">> Remote file '" + srcFile + "' renamed to '" + dstFile + "'" + eol);
            return true;
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
    }



    /**
     * Delete a remote file specified by the user
     *
     * @return true if no error    
     */
    public boolean doRemoteDeleteFile() {
        if (!connected()) return false;  
        try {  
            String file = requestDialog("File request","File:", "");
            if (file==null || file.trim().equals("")) {
                logMessage("Delete remote file cancelled " + eol);
                return true; // Cancel is not an error
            }
            if (!remoteDeleteFile(file)) {
                logError(lastError);
                return false;
            } else {
                logMessage(">> Remote file '" + file + "' deleted" + eol);
                return true;
            }
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
    }

    /**
     * Delete a remote directory specified by the user
     *
     * @return true if no error    
     */
    public boolean doRemoteRemoveDirectory() {
        if (!connected()) return false; 
        try {   
            String directoryName = requestDialog("Directory request","File:", "");
            if (directoryName==null || directoryName.trim().equals("")) {
                logMessage(">> Remove remote directory cancelled " + eol);
                return true; // Cancel is not an error
            } 
            if (!remoteRemoveDirectory(directoryName)) {
                logError(lastError);
                return false;
            } else {
                logMessage(">> Remote directory '" + directoryName + "' removed" + eol);
                return true;
            }
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
    }



    // ---------------------------------------------------------------------------
    // Local commands
    // ---------------------------------------------------------------------------
    

    /**
     * Display the local directory
     *
     * @return  true if successful   
     */
    public boolean doLocalPrintWorkingDirectory() {
        try {
           logMessage(">> Current local directory:" + eol + localGetWorkingDirectory()  + eol);
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
       return true;
    }


    /**
     * Change local directory to the one specified by the user
     *
     * @return  true if successful   
     */
    public boolean doLocalChangeWorkingDirectory() {
        try {
           String dir = requestDialog("Directory request","Directory:", "");
           if (dir==null || dir.trim().equals("")) {
               logMessage(">> Change local working directory cancelled " + eol);
                return true; // Cancel is not an error
            }
           String newDir = localChangeWorkingDirectory(dir);
           if (newDir!=null) {
               logMessage(">> New local working directory: " + eol + newDir + eol);
               return true;
           } else {
               logError(lastError);
               return false;
           }
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
    }    
    

    /**
     * Change the local directory to its parent
     *
     * @return  true if successful   
     */
    public boolean doLocalChangeToParentDirectory() {
        try {
           String newDir = localChangeToParentDirectory();
           if (newDir!=null) {
               logMessage(">> New local working directory: " + eol + newDir + eol);
               return true;
           } else {
               logError(lastError);
               return false;
           }
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
    }


    /**
     * List the name and content of the local directory
     *
     * @return  true if successful   
     */
    public boolean doLocalListDirectory() {
        try {
           logMessage(">> Local directory listing" + eol);
           String dir = localGetWorkingDirectory();
           if (dir == null) {
               logError(lastError);
               return false;
           }
           logMessage("Directory: " + dir + eol);
           
           FTPFile[] ftpFiles = localGetFileList();
           if (ftpFiles == null) {
               logError(lastError);
               return false;
           }
           if (ftpFiles.length==0) {
               logMessage(" no file" + eol);
           } else {
               for (int i = 0; i<ftpFiles.length; i++) {
                   logMessage(" " + ftpFiles[i].toString() + eol);
               }
               logMessage("   " + ftpFiles.length + " file(s)" + eol);
           }
           return true;
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
    }

 

    /**
     * Create a local directory with the name specified by the user
     *
     * @return  true if successful   
     */
    public boolean doLocalMakeDirectory() {
        try {
           String dir = requestDialog("Directory request","Directory:", "");
           if (dir==null || dir.trim().equals("")) {
                logMessage(">> Make local directory cancelled " + eol);
                return true; // Cancel is not an error
           } else {
              if (!localMakeDirectory(dir)) {
                  logError(lastError);
                  return false;
              } else {
                  logMessage(">> Remote directory '" + dir + "' created" + eol);
                  return true;
              }
          }
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
    }
    


    /**
     * Rename a local file specified by the user
     *
     * @return true if no error    
     */
    public boolean doLocalRenameFile() {
        try {
            String srcFile = requestDialog("File request","File to rename:", "");
            if (srcFile==null || srcFile.trim().equals("")) {
                logMessage("Rename local file cancelled " + eol);
                return true; // Cancel is not an error
            }
            String dstFile = requestDialog("File request","Rename to:", "");
            if (dstFile==null || dstFile.trim().equals("")) {
                logMessage("Rename local file cancelled " + eol);
                return true; // Cancel is not an error
            } 
            if (!localRenameFile(srcFile, dstFile)) {
                logError(lastError);
                return false;
            } else {
                logMessage(">> Local file '" + srcFile + "' renamed to '" + dstFile + "'" + eol);
                return true;
            }
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
    }


    /**
     * Delete a local file as specified by the user
     *
     * @return  true if successful   
     */
    public boolean doLocalDeleteFile() {
        try {
           String file = requestDialog("File request","File:", "");
           if (file==null || file.trim().equals("")) {
                logMessage("Delete local file cancelled " + eol);
                return true; // Cancel is not an error
           }
          if (!localDeleteFile(file)) {
              logError(lastError);
              return false;
          } else {
              logMessage(">> Local file '" + file + "' deleted" + eol);
              return true;
          }
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
    }

    

    /**
     * Delete a local directory as specified by the user
     *
     * @return  true if successful   
     */
    public boolean doLocalRemoveDirectory() {
        try {
           String directoryName = requestDialog("Directory request","Directory:", "");
           if (directoryName==null || directoryName.trim().equals("")) {
               logMessage(">> Remove local directory cancelled " + eol);
                return true; // Cancel is not an error
           }
          if (!localDeleteFile(directoryName)) {
              logError(lastError);
              return false;
          } else {
              logMessage(">> Local directory '" + directoryName + "' removed" + eol);
              return true;
          }
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
    }

    // ---------------------------------------------------------------------------
    // Transfer commands
    // ---------------------------------------------------------------------------
    

    /**
     * Retrieve a text file with the name provided by the user. 
     *
     * @return   true if success  
     */
    public boolean doGetTextFile() {
        return doGetFile(FTP.ASCII_FILE_TYPE);
    }

    /**
     * Retrieve a binary file with the name provided by the user. 
     *
     * @return   true if success  
     */
    public boolean doGetBinaryFile() {
        return doGetFile(FTP.BINARY_FILE_TYPE);
    }

    /**
     * Retrieve a file with the name provided by the user. Use the same name
     * for local and remote.
     *
     * @param   mode  FTP.ASCII_FILE_TYPE or FTP.BINARY_FILE_TYPE
     * @return  true if successful   
     */
    private boolean doGetFile(int mode) {
        if (!connected()) return false;
        try {    
            String modeString = (mode==FTP.ASCII_FILE_TYPE) ? "text" : "binary";
            String fileName = requestDialog("Remote file to get","File:","");
            if (fileName==null || fileName.trim().equals("")) {
                logMessage(">> Get file cancelled " + eol);
                return true; // Cancel is not an error
            }
             logMessage(">> Getting file '" + fileName + 
                             " in " + modeString + " mode ..." + eol);
             if (getFile(mode, fileName, fileName)) {
                logMessage(">> ... Done" + eol);
                return true;
            } else {
                logError(lastError);
                return false;
            }
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
    }
    

    /**
     * Send a text file with the name provided by the user. 
     *
     * @return   true if success  
     */
    public boolean doSendTextFile() {
        return doSendFile(FTP.ASCII_FILE_TYPE);
    }

    /**
     * Send a binary file with the name provided by the user. 
     *
     * @return   true if success  
     */
    public boolean doSendBinaryFile() {
        return doSendFile(FTP.BINARY_FILE_TYPE);
    }

    /**
     * Send a file with the name provided by the user. Use the same name
     * for local and remote.
     *
     * @param   mode  FTP.ASCII_FILE_TYPE or FTP.BINARY_FILE_TYPE
     * @return  true if successful   
     */
    private boolean doSendFile(int mode) {
        if (!connected()) return false; 
        try {   
            String modeString = (mode==FTP.ASCII_FILE_TYPE) ? "text" : "binary";
            String fileName = requestDialog("Local file to send","File:","");
            if (fileName==null || fileName.trim().equals("")) {
                logMessage(">> Send file cancelled " + eol);
                return true; // Cancel is not an error
            }
            logMessage(">> Sending file '" + fileName +
                         " in " + modeString + " mode ..." + eol);
            if (sendFile(mode, fileName, fileName)) {
                logMessage(">> ... Done" + eol);
                return true;
            } else {
                logError(lastError);
                return false;
            }
       } catch (JSException ignore) {
           logError(lastError);
           return false;
       }
           
    }
    
    // ---------------------------------------------------------------------------
    // Utility routines
    // ---------------------------------------------------------------------------

    /**
     * Append the reply strings of a command as a log message
     */
    private void appendReplyStrings() {
        if (lastReply != null) {
            logMessage(lastReply);
        }
    }
    
    boolean connected() {
        if (isConnected()) {
            return true;
        } else {
            lastError = "Not connected";
            logError(lastError);
            return false;
        }
    }
}

    