Integral FTP

ftpclient.js

Summary

Contains FTPClient - the main interface for the Integral FTP JavaScript library.

Version: 4.0.4

Author: Enterprise Distributed Technologies


Class Summary
FTPAskResponse Represents a response to an FTPClient@ask invocation.
FTPCallbackStatus Reports on the status of the an FTP operation.
FTPClient FTPClient is the main interface for the Integral FTP library.
FTPFile FTPFile contains the information describing the attributes of a particular file, namely its path, name, size, last-modified date, whether or not it's a directory and whether or not it's likely to be a text-file.
FTPFileList An instance of this class represents a collection of files - usually those in a particular directory.
FTPFileSize Represents a file-size.
FTPPromptFileResponse Represents a response to an FTPClient@promptFile invocation.
FTPRenderer An FTPRenderer may be used to produce an HTML representation of an FTPFileList.

Method Summary
static int FTPClient_getRetryCount()
           Returns the current retry-count, which determines the number of times the client will retry a failing transfer before giving up.
static int FTPClient_getRetryDelay()
           Returns the current retry-delay (in milliseconds), which is the amount of time to wait before retrying a failed transfer.
static void FTPClient_setRetryCount(<int> count)
           Sets the current retry-count, which determines the number of times the client will retry a failing transfer before giving up.
static void FTPClient_setRetryDelay(<int> delay)
           Sets the current retry-delay (in milliseconds), which is the amount of time to wait before retrying a failed transfer.

/**
 * @fileoverview Contains {@link FTPClient} - the main interface for the Integral FTP JavaScript library.
 * @author Enterprise Distributed Technologies
 * @version 4.0.4
 */

// FTPClient =============================================================================

/**
 * @ignore
 */
var _ftpClients = new Array();		// global reference	to FTPClient

/**
 * @ignore
 */
var FTPClient_sortColumn = "name";

/**
 * @ignore
 */
var FTPClient_sortAscending = true;

// FTPClient Methods -------------------------------------------------------------

/**
 * Constructs a new FTPClient object.
 * @class FTPClient is the main interface for the Integral FTP library.  It contains
 * methods for connecting to FTP servers, downloading and uploading files, listing
 * local and remote directories, and renaming and deleting local and remote files.
 * Please refer to the <a href="../devguide.html" target="_top">Integral FTP Developer's Guide</a>
 * for a broad description of how this class may be used.
 * @constructor
 * @return A new FTPClient
 */
function FTPClient()
{
	this._instance = _ftpClients.length;
	this.id = this._instance;
	_ftpClients[this._instance] = this;
}

// CONSTANTS -----------------------------------------------------------

/**
 * Constant used in {@link #downloadFile} and {@link #uploadFile} to 
 * direct FTPClient to overwrite any existing file with the same name.
 * @see #uploadFile
 * @see #downloadFile
 * @final
 */
FTPClient.prototype.WRITEMODE_OVERWRITE = 0;

/**
 * Constant used in {@link #downloadFile} and {@link #uploadFile} to 
 * direct FTPClient to resume any previous transfer from the point
 * at which is was stopped last time.
 * @see #uploadFile
 * @see #downloadFile
 * @final
 */
FTPClient.prototype.WRITEMODE_RESUME = 1;

/**
 * Constant used in {@link #downloadFile} and {@link #uploadFile} to 
 * direct FTPClient to append to the existing file (if any).
 * @see #uploadFile
 * @see #downloadFile
 * @final
 */
FTPClient.prototype.WRITEMODE_APPEND = 2;

// PROPERTIES ----------------------------------------------------------

/**
 * @ignore
 */
FTPClient.prototype._initStarted = false;

/**
 * @ignore
 */
FTPClient.prototype._initComplete = false;

/**
 * @ignore
 */
FTPClient.prototype._isConnected = false;

/**
 * @ignore
 */
FTPClient.prototype._tags = [];

/**
 * @ignore
 */
FTPClient.prototype._instance = null;

/**
 * Unique identifier for this instance of FTPClient.
 * @type string
 */
FTPClient.prototype.id = null;

/**
 * File transfer protocol to use (FTP, FTPS or SFTP).
 * @type string
 */
FTPClient.prototype.protocol = null;

/**
 * Domain name or IP address (and optionally port) of FTP server.
 * Host-names should be of the form "{subdomain}.{domain}:{port}.
 * @type string
 */
FTPClient.prototype.remoteHost = null;

/**
 * User-name of account on FTP server
 * @type string
 */
FTPClient.prototype.userName = null;

/**
 * Password of account on FTP server
 * @type string
 */
FTPClient.prototype.password = null;

/**
 * Initial remote directory on FTP server.  To change directory after connecting
 * use  {@link #changeDirectory}.
 * @type string
 */
FTPClient.prototype.initialRemoteDirectory = null;

/**
 * Language(s) to use when attempting parse dates in directory listings.
 * By default an attempt will first be made to parse the listings using
 * English and then in the default language of the Java installation
 * (if it is not English).
 * 
 * If this field is set then it should contain a comma-separated list of
 * languages.  The languages should be specified using Locale Identifiers 
 * such as "en_US" for US English, "fr_FR" for French and "es_ES" for Spanish.  
 * Thus if dateLanguages is "en_US,fr_FR,es_ES" then the parser will first 
 * try to parse the dates in Englsih, then French and finally in Spanish.
 * If none of these languages yield valid dates then dates will be returned
 * as null.
 * 
 * Note that this field must be set before {@link #connect} is called.
 */
FTPClient.prototype.dateLanguages = null;

/**
 * Minimum number of milliseconds between progress updates.
 * Must be set before {@link #connect} is called.
 * There is no upper limit since it depends on the number
 * of bytes transferred and the block-size of the transfers.
 * In most cases, however, the actual period should be just
 * a little more than this value.  The default is 500 milliseconds.
 * @type int
 */
FTPClient.prototype.minTransferNotifyPeriod = 500;

/**
 * Size of the data buffers (in bytes) used in reading and writing to the server.
 * @type int
 */
FTPClient.prototype.transferBufferSize = 16384;

/**
 * Deprecated: Use {@link #minTransferNotifyPeriod} instead.
 * Interval (in bytes) used for progress notification of transfers.
 * Must be set before {@link #connect} is called.
 * @type int
 */
FTPClient.prototype.transferNotifyInterval = 65535;

/**
 * Flag controlling the sort-order (ascending or descending) of files returned 
 * by {@link #localDirectoryList}.
 * The attribute by which the list is controlled by {@link #localSortColumn}.
 * @type boolean
 * @see #localDirectoryList
 */
FTPClient.prototype.localSortAscending = true;

/**
 * Attribute by which the list files returned by {@link #localDirectoryList} are
 * sorted.  Possible values are "name", "size" or "date".  The order (ascending
 * or descending) is controlled by {@link #localSortAscending}.
 * @type string
 * @see #localDirectoryList
 */
FTPClient.prototype.localSortColumn = "name";		// should be "name", "size" or "date"

/**
 * Flag controlling the sort-order (ascending or descending) of files returned 
 * by {@link #remoteDirectoryList}.
 * The attribute by which the list is controlled by {@link #remoteSortColumn}.
 * @type boolean
 * @see #remoteDirectoryList
 */
FTPClient.prototype.remoteSortAscending = true;

/**
 * Attribute by which the list files returned by {@link #remoteDirectoryList} are
 * sorted.  Possible values are "name", "size" or "date".  The order (ascending
 * or descending) is controlled by {@link #remoteSortAscending}.
 * @type string
 * @see #remoteDirectoryList
 */
FTPClient.prototype.remoteSortColumn = "name";		// should be "name", "size" or "date"

/**
 * Controls whether or not the EnterpriseDT splash screen is displayed on start-up.
 * This property must be set prior to calling the {@link #initialize} method.
 * It can also be set by passing an argument to {@link #initialize}.
 * @type boolean
 * @see #initialize
 */
FTPClient.prototype.showSplash = true;

/**
 * URL of splash image.  If it's null then the default image is used.
 * Splash images will look best if they're 150x150 in size.
 * @type string
 * @see #initialize
 */
FTPClient.prototype.splashImageURL = null;

/**
 * Minimum number of connections that the client makes with the server.
 * This property must be set prior to calling the {@link #initialize} method.
 * It can also be set by passing an argument to {@link #initialize}.
 * @type int
 * @see #initialize
 */
FTPClient.prototype.minPoolSize = 1;

/**
 * Maximum number of connections that the client makes with the server.
 * This property must be set prior to calling the {@link #initialize} method.
 * It can also be set by passing an argument to {@link #initialize}.
 * @type int
 * @see #initialize
 */
FTPClient.prototype.maxPoolSize = 5;

/**
 * Level of logging (Possible values are "OFF", "ERROR", "INFO", "DEBUG" and "ALL").  
 * Logging is written to the Java console and optionally to a log-file (see {@link #logToFile}).
 * It can also be set by passing an argument to {@link #initialize}.
 * @type string
 * @see #initialize
 */
FTPClient.prototype.logLevel = "OFF";

/**
 * If true then logging will be written to a file called
 * "IntegralFTP.log" in the machine's temporary directory.
 * It can also be set by passing an argument to {@link #initialize}.
 * @type boolean
 * @see #initialize
 */
FTPClient.prototype.logToFile = null;

/**
 * Path separator of local file-system.  This value get set during initialization.
 */
FTPClient.prototype.localSeparator = "\\";


// CALLBACKS -----------------------------------------------------------

/**
 * Callback for the {@link #initialize} method.
 * This field should be set to a function if notification is required when
 * the {@link #initialize} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @type callback
 * @see #initialize
 */
FTPClient.prototype.onInitialize = function (callbackStatus) {};

/**
 * Callback for the {@link #connect} method.
 * This field should be set to a function if notification is required when
 * the {@link #connect} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @type callback
 * @see #connect
 */
FTPClient.prototype.onConnect = function (callbackStatus) {};

/**
 * Callback for the {@link #disconnect} method.
 * This field should be set to a function if notification is required when
 * the {@link #disconnect} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {int} reasonCode Code describing the reason for the disconnection
 * (0=Normal disconnection, 1=Inactive for too long, 2=Lost connection, other=Unknown vause).
 * @param {string} reasonMessage Message describing the reason for the disconnection
 * ("Normal disconnection", "Inactive for too long", "Lost connection", "Unknown cause").
 * @type callback
 * @see #disconnect
 */
FTPClient.prototype.onDisconnect = function (callbackStatus, reasonCode, reasonMessage) {};

/**
 * Callback for the {@link #directoryList} method.
 * This field should be set to a function if notification is required when
 * the {@link #directoryList} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} remoteDirectory Name of the directory being listed.
 * @param {FTPFileList} fileList {@link FTPFileList} containing the files.
 * @type callback
 * @see #directoryList
 */
FTPClient.prototype.onDirectoryList = function (callbackStatus, remoteDirectory, fileList) {};

/**
 * Callback for the {@link #downloadFile} method.
 * This field should be set to a function if notification is required when
 * the {@link #downloadFile} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} remoteFileName Name of the file that was downloaded.
 * @type callback
 * @see #downloadFile
 */
FTPClient.prototype.onDownloadFile = function (callbackStatus, remoteFileName) {};

/**
 * Callback for the {@link #downloadText} method.
 * This field should be set to a function if notification is required when
 * the {@link #downloadText} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} remoteFileName Name of the file that was downloaded (as text).
 * @param {string} text String containing the contents of the file.
 * @type callback
 * @see #downloadText
 */
FTPClient.prototype.onDownloadText = function (callbackStatus, remoteFileName, text) {};

/**
 * Callback for the {@link #uploadFile} method.
 * This field should be set to a function if notification is required when
 * the {@link #uploadFile} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} remoteFileName Name of the file that was uploaded
 * @type callback
 * @see #uploadFile
 */
FTPClient.prototype.onUploadFile = function (callbackStatus, remoteFileName) {};

/**
 * Callback for the {@link #uploadText} method.
 * This field should be set to a function if notification is required when
 * the {@link #uploadText} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} remoteFileName Name of the file that the text was uploaded to.
 * @type callback
 * @see #uploadText
 */
FTPClient.prototype.onUploadText = function (callbackStatus, remoteFileName) {};

/**
 * Callback for the {@link #size} method.
 * This field should be set to a function if notification is required when
 * the {@link #size} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} remoteFileName Name of the file.
 * @param {int} size Size of the file in bytes.
 * @type callback
 * @see #size
 */
FTPClient.prototype.onSize = function (callbackStatus, remoteFileName, size) {};

/**
 * Callback for the {@link #modifiedTime} method.
 * This field should be set to a function if notification is required when
 * the {@link #modifiedTime} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} remoteFileName Name of the file.
 * @param {Date} modTime Last modified time of the file.
 * @type callback
 * @see #modifiedTime
 */
FTPClient.prototype.onModifiedTime = function (callbackStatus, remoteFileName, modTime) {};

/**
 * Callback for the {@link #rename} method.
 * This field should be set to a function if notification is required when
 * the {@link #rename} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} fromName Previous name of file.
 * @param {string} toName New name of file.
 * @type callback
 * @see #rename
 */
FTPClient.prototype.onRename = function (callbackStatus, fromName, toName) {};

/**
 * Callback for the {@link #deleteFile} method.
 * This field should be set to a function if notification is required when
 * the {@link #deleteFile} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} remoteFileName Name of the file.
 * @type callback
 * @see #deleteFile
 */
FTPClient.prototype.onDeleteFile = function (callbackStatus, remoteFileName) {};

/**
 * Callback for the {@link #deleteDirectory} method.
 * This field should be set to a function if notification is required when
 * the {@link #deleteDirectory} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} remoteDirectoryName Name of the directory.
 * @type callback
 * @see #deleteDirectory
 */
FTPClient.prototype.onDeleteDirectory = function (callbackStatus, remoteDirectoryName) {};

/**
 * Callback for the {@link #exists} method.
 * This field should be set to a function if notification is required when
 * the {@link #exists} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} remoteFileName Name of the file.
 * @param {boolean} exists true if the file exists and false otherwise.
 * @type callback
 * @see #exists
 */
FTPClient.prototype.onExists = function (callbackStatus, remoteFileName, exists) {};

/**
 * Callback for the {@link #executeCommand} method.
 * This field should be set to a function if notification is required when
 * the {@link #executeCommand} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} command FTP command executed.
 * @param {string} result Server's response to FTP command.
 * @type callback
 * @see #executeCommand
 */
FTPClient.prototype.onExecuteCommand = function (callbackStatus, command, result) {};

/**
 * Callback for the {@link #changeDirectory} method.
 * This field should be set to a function if notification is required when
 * the {@link #changeDirectory} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} remoteDirectory Name of remote working directory.
 * @type callback
 * @see #changeDirectory
 */
FTPClient.prototype.onChangeDirectory = function (callbackStatus, remoteDirectory) {};

/**
 * Callback for the {@link #createDirectory} method.
 * This field should be set to a function if notification is required when
 * the {@link #createDirectory} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} remoteDirectory Name of the directory that was created.
 * @type callback
 * @see #createDirectory
 */
FTPClient.prototype.onCreateDirectory = function (callbackStatus, remoteDirectory) {};

/**
 * Callback for the {@link #localDirectoryList} method.
 * This field should be set to a function if notification is required when
 * the {@link #localDirectoryList} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} localDirectory Name of the directory being listed.
 * @param {FTPFileList} fileList {@link FTPFileList} containing the files.
 * @type callback
 * @see #localDirectoryList
 */
FTPClient.prototype.onLocalDirectoryList = function (callbackStatus, localDirectory, fileList) {};

/**
 * Callback for the {@link #localRename} method.
 * This field should be set to a function if notification is required when
 * the {@link #localRename} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} fromName Previous name of file.
 * @param {string} toName New name of file.
 * @type callback
 * @see #localRename
 */
FTPClient.prototype.onLocalRename = function (callbackStatus, fromName, toName) {};

/**
 * Callback for the {@link #localDeleteFile} method.
 * This field should be set to a function if notification is required when
 * the {@link #localDeleteFile} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} remoteFileName Name of the file.
 * @type callback
 * @see #localDeleteFile
 */
FTPClient.prototype.onLocalDeleteFile = function (callbackStatus, remoteFileName) {};

/**
 * Callback for the {@link #localCreateDirectory} method.
 * This field should be set to a function if notification is required when
 * the {@link #localCreateDirectory} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} localDirectory Name of the directory that was created.
 * @type callback
 * @see #localCreateDirectory
 */
FTPClient.prototype.onLocalCreateDirectory = function (callbackStatus, localDirectory) {};

/**
 * Callback for the {@link #localSize} method.
 * This field should be set to a function if notification is required when
 * the {@link #localSize} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} localFileName Name of the file.
 * @param {int} size Size of the file in bytes.
 * @type callback
 * @see #localSize
 */
FTPClient.prototype.onLocalSize = function (callbackStatus, localFileName, size) {};

/**
 * Callback for the {@link #localModifiedTime} method.
 * This field should be set to a function if notification is required when
 * the {@link #localModifiedTime} method completes.  See the <a href="../devguide.html">Integral FTP
 * Developer's Guide</a> for details and examples.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} localFileName Name of the file.
 * @param {Date} modTime Last modified time of the file.
 * @type callback
 * @see #localModifiedTime
 */
FTPClient.prototype.onLocalModifiedTime = function (callbackStatus, localFileName, modTime) {};

/**
 * Callback for all errors.
 * This field should be set to a function if notification is required when
 * an error occurs.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @type callback
 */
FTPClient.prototype.onError = function (callbackStatus) {};

/**
 * Callback for transfer-progress updates.  This callback is invoked during
 * uploads and downloads at intervals of at least {@link #minTransferNotifyPeriod}
 * milliseconds.  It may be used to provide feedback for the user on the progress
 * of the transfer.
 * @param {FTPCallbackStatus} callbackStatus Status information (see {@link FTPCallbackStatus}).
 * @param {string} remoteFileName Name of the file being transferred.
 * @param {int} byteCount Number of bytes that have been transferred so far.
 * @type callback
 * @see #minTransferNotifyPeriod
 * @see #uploadFile
 * @see #downloadFile
 * @see #uploadText
 * @see #downloadText
 */
FTPClient.prototype.onTransferProgress = function (callbackStatus, remoteFileName, byteCount) {};


// METHOD DECLARATIONS -------------------------------------------------

FTPClient.prototype.initialize = FTPClient_initialize;
FTPClient.prototype.isInitialized = FTPClient_isInitialized;
FTPClient.prototype.getAllLogLevels = FTPClient_getAllLogLevels;
FTPClient.prototype.getLogLevel = FTPClient_getLogLevel;
FTPClient.prototype.setLogLevel = FTPClient_setLogLevel;
FTPClient.prototype.isKeepAliveEnabled = FTPClient_isKeepAliveEnabled;
FTPClient.prototype.setKeepAliveEnabled = FTPClient_setKeepAliveEnabled;
FTPClient.prototype.getConnectMode = FTPClient_getConnectMode;
FTPClient.prototype.setConnectMode = FTPClient_setConnectMode;
FTPClient.prototype.getTransferType = FTPClient_getTransferType;
FTPClient.prototype.setTransferType = FTPClient_setTransferType;
FTPClient.prototype.getCharacterSet = FTPClient_getCharacterSet;
FTPClient.prototype.setCharacterSet = FTPClient_setCharacterSet;
FTPClient.prototype.setTemplateURLs = FTPClient_setTemplateURLs;
FTPClient.prototype.isViewCachingEnabled = FTPClient_isViewCachingEnabled;
FTPClient.prototype.setViewCachingEnabled = FTPClient_setViewCachingEnabled;
FTPClient.prototype.isRemoteHostValid = FTPClient_isRemoteHostValid;
FTPClient.prototype.alert = FTPClient_alert;
FTPClient.prototype.ask = FTPClient_ask;
FTPClient.prototype.promptFile = FTPClient_promptFile;
FTPClient.prototype.promptFiles = FTPClient_promptFiles;
FTPClient.prototype.connect = FTPClient_connect;
FTPClient.prototype.isConnected = FTPClient_isConnected;
FTPClient.prototype.disconnect = FTPClient_disconnect;
FTPClient.prototype.changeDirectory = FTPClient_changeDirectory;
FTPClient.prototype.createDirectory = FTPClient_createDirectory;
FTPClient.prototype.directoryList = FTPClient_directoryList;
FTPClient.prototype.downloadFile = FTPClient_downloadFile;
FTPClient.prototype.downloadText = FTPClient_downloadText;
FTPClient.prototype.uploadFile = FTPClient_uploadFile;
FTPClient.prototype.uploadText = FTPClient_uploadText;
FTPClient.prototype.cancelTransfer = FTPClient_cancelTransfer;
FTPClient.prototype.size = FTPClient_size;
FTPClient.prototype.modifiedTime = FTPClient_modifiedTime;
FTPClient.prototype.deleteFile = FTPClient_deleteFile;
FTPClient.prototype.deleteDirectory = FTPClient_deleteDirectory;
FTPClient.prototype.rename = FTPClient_rename;
FTPClient.prototype.exists = FTPClient_exists;
FTPClient.prototype.executeCommand = FTPClient_executeCommand;
FTPClient.prototype.localDirectoryList = FTPClient_localDirectoryList;
FTPClient.prototype.localDeleteFile = FTPClient_localDeleteFile;
FTPClient.prototype.localRename = FTPClient_localRename;
FTPClient.prototype.localCreateDirectory = FTPClient_localCreateDirectory;
FTPClient.prototype.localSize = FTPClient_localSize;
FTPClient.prototype.localModifiedTime = FTPClient_localModifiedTime;
FTPClient.prototype.getLocalHomeDirectory = FTPClient_getLocalHomeDirectory;
FTPClient.prototype.getLocalTempDirectory = FTPClient_getLocalTempDirectory;
FTPClient.prototype.getLocalAcceptorPort = FTPClient_getLocalAcceptorPort;
FTPClient.prototype.getRemoteAcceptorPort = FTPClient_getRemoteAcceptorPort;
FTPClient.prototype.getWorkingDirectory = FTPClient_getWorkingDirectory;
FTPClient.prototype.registerMimeType = FTPClient_registerMimeType;

/**
 * @ignore
 */
FTPClient.prototype._getAppletHTML = FTPClient__getAppletHTML;

/**
 * @ignore
 */
FTPClient.prototype._checkInitialization = FTPClient__checkInitialization;

/**
 * @ignore
 */
FTPClient.prototype._addHTML = FTPClient__addHTML;

/**
 * @ignore
 */
FTPClient.prototype._setTag = FTPClient__setTag;

/**
 * @ignore
 */
FTPClient.prototype._getTag = FTPClient__getTag;


// METHOD IMPLEMENTATIONS ----------------------------------------------

/**
 * Initializes the FTPClient instance [ASYNCHRONOUS - calls {@link #onInitialize} when complete].
 * This method must be called before any FTP operations are performed.  The main purpose
 * is to load the invisible Integral FTP applet onto the page.  The arguments determine
 * whether or not the EnterpriseDT splash will be displayed and the nature of the logging (if any).
 * @param {string} jarURL The absolute or relative URL of the IntegralFTP.jar file.
 * @param {boolean} showSplash Determines whether or not the EnterpriseDT splash will be displayed.
 * @param {string} logLevel Level of logging (Possible values are
 * "OFF", "ERROR", "INFO", "DEBUG" and "ALL").  Logging is written to the Java console
 * and optionally to a log-file (see below).
 * @param {boolean} logToFile If true then logging will be written to a file called
 * "IntegralFTP.log" in the machine's temporary directory.
 * @param {int} minPoolSize Minimum number of connections that the client will make to the server.
 * @param {int} maxPoolSize Maximum number of connections that the client may make to the server.
 * @see #onInitialize
 * @see #isInitialized
 */
function FTPClient_initialize(jarURL, showSplash, logLevel, logToFile, minPoolSize, maxPoolSize) 
{
	if (this._initStarted) {
		return;
	}
	this._initStarted = true;

    // set any parameter overrides
	if (showSplash!==undefined && showSplash!==null)
		this.showSplash = showSplash;
	if (logLevel!==undefined && logLevel!==null)
		this.logLevel = logLevel;
	if (logToFile!==undefined && logToFile!==null)
		this.logToFile = logToFile;
	if (minPoolSize!==undefined && minPoolSize!==null)
		this.minPoolSize = minPoolSize;
	if (maxPoolSize!==undefined && maxPoolSize!==null)
		this.maxPoolSize = maxPoolSize;
	
	// applet positioning
	var _info = navigator.userAgent; 
	var _ie = (_info.indexOf("MSIE") > 0 && _info.indexOf("Win") > 0 && _info.indexOf("Windows 3.1") < 0);
	var w = !this.showSplash && _ie ? 0 : 150;
	var h = !this.showSplash && _ie ? 0 : 150;
	var divTop = (document.body.clientHeight - w)/3;
	if (divTop<10) divTop = 10;
	var divLeft = (document.body.clientWidth - h)/2;
	if (divLeft<10) divLeft = 10;
	var appletStyle = "width:" + w + "px;height:" + h + "px;";
	if (!_ie && !this.showSplash)
		appletStyle = "visibility:hidden;";
    var divStyle = "position:absolute;top:" + divTop + "px;left:" + divLeft + "px;width:0px;height:0px"
    
	// applet parameters
	var appletParams = {};
	if (this.showSplash!==null)
		appletParams.showSplash = this.showSplash;
	if (this.splashImageURL!==null)
		appletParams.splashImageURL = this.splashImageURL;
	if (this.minPoolSize!==null)
		appletParams.minPoolSize = this.minPoolSize;
	if (this.maxPoolSize!==null)
		appletParams.maxPoolSize = this.maxPoolSize;
	if (this.logLevel!==null)
		appletParams.logLevel = this.logLevel;
	if (this.logToFile!==null)
		appletParams.logToFile = this.logToFile;
    var appletHTML = this._getAppletHTML(this._instance, "com/enterprisedt/net/ftp/applet/FTPApplet.class", jarURL, appletParams, appletStyle);
	this._addHTML(document, "<div style='" + divStyle + "'>" + appletHTML + "</div>");
}

/**
 * @ignore
 */
function FTPClient__getAppletHTML(appletName, classFile, jarURL, appletParams, appletStyle) 
{
    var appletHTML = "";
	var _info = navigator.userAgent; 
    var _ie = (_info.indexOf("MSIE") > 0 && _info.indexOf("Win") > 0 && _info.indexOf("Windows 3.1") < 0);
    var _ns = (navigator.appName.indexOf("Netscape") >= 0 && ((_info.indexOf("Win") > 0 && _info.indexOf("Win16") < 0) || (_info.indexOf("Sun") > 0) || (_info.indexOf("Linux") > 0) || (_info.indexOf("AIX") > 0) || (_info.indexOf("OS/2") > 0) || (_info.indexOf("IRIX") > 0)));
    var _ns6 = ((_ns == true) && (_info.indexOf("Mozilla/5") >= 0));
    if (_ie == true && !navigator.javaEnabled()) {
		appletHTML += "<object \n";
		appletHTML += "    style='" + appletStyle + "'";
		appletHTML += "    classid = 'clsid:8AD9C840-044E-11D1-B3E9-00805F499D93'\n";
		appletHTML += "    codebase = 'http://java.sun.com/update/1.6.0/jinstall-6-windows-i586.cab'\n";
		appletHTML += "    id = '" + appletName + "' >\n";
		appletHTML += "    	<param name=code value='" + classFile + "' >\n";
		appletHTML += "    	<param name=archive value='" + jarURL + "' >\n";
		appletHTML += "    	<param name=id value='" + appletName + "' >\n";
		appletHTML += "    	<param name=mayscript value='true' >\n";
		appletHTML += "    	<param name=type value='application/x-java-applet;version=1.6'>\n";
		appletHTML += "    	<param name=scriptable value='true'>\n";
		for (var p in appletParams)
			appletHTML += "    	<param name=" + p + " value='" + appletParams[p] + "'>\n";
		appletHTML += "</object>\n";
    } else if (_ns == true && _ns6 == false) {
		appletHTML += "<embed \n";
		appletHTML += "    style='" + appletStyle + "'";
		appletHTML += "    type = 'application/x-java-applet;version=1.6' \n";
		appletHTML += "	   code = '" + classFile + "' \n";
		appletHTML += "	   archive = '" + jarURL + "' \n";
		appletHTML += "	   id = '" + appletName + "' \n";
		appletHTML += "	   mayscript = 'true' \n";
		for (var p in appletParams)
			appletHTML += "  " + p + "='" + appletParams[p] + "'\n";
		appletHTML += "	   scriptable = true \n";
		appletHTML += "	   pluginspage = 'http://www.java.com/en/download/manual.jsp'>\n";
		appletHTML += "</embed>\n";
	} else {
		appletHTML += "<applet code='" + classFile + "'";
		appletHTML += " archive='" + jarURL + "'";
		appletHTML += " id='" + appletName + "'";
		appletHTML += " mayscript";
		appletHTML += " style='" + appletStyle + "'>\n";
		appletHTML += "    <param name=code value='" + classFile + "' >\n";
		appletHTML += "    <param name=archive value='" + jarURL + "' >\n";
		appletHTML += "    <param name=id value='" + appletName + "' >\n";
		appletHTML += "    <param name=type value='application/x-java-applet;version=1.6'>\n";
		appletHTML += "    <param name=scriptable value='true'>\n";
		for (var p in appletParams)
			appletHTML += "    <param name=" + p + " value='" + appletParams[p] + "'>\n";
		appletHTML += "</applet>\n";
	}
	return appletHTML;
}

/**
 * @ignore
 */
function FTPClient__checkInitialization() 
{
	if (!this._initStarted) {
		throw "FTP client has not been initialized.  " +
			"FTPClient.initialize() must be called.";
	}
	else if (!this._initComplete) {
		throw "FTP client has finished initializing.  " +
			"Please wait for FTPClient.onInitialize() to be called.";
	}
}

/**
 * Returns true if the FTPClient has been initialized.
 * @return True if the FTPClient has been initialized.
 * @type int
 * @see #initialize
 */
function FTPClient_isInitialized() 
{
	return this._initComplete;
}
	
/**
 * Returns an array of strings containing the names of all the valid logging levels.
 * The names are "OFF", "ERROR", "WARNING", "INFO", "DEBUG" and "ALL".
 * @return An array of strings containing all available logging levels.
 * @type string[]
 * @see #getLogLevel
 * @see #setLogLevel
 */
function FTPClient_getAllLogLevels () 
{
	this._checkInitialization();
	var levels = this.applet.getAllLogLevels();
	for (var i=0; levels.length; i++) {
		levels[i] = ""+levels[i];		// convert to JavaScript string
	}
	return levels;
}

/**
 * Returns the current logging level.
 * @return The current logging level.
 * @type string
 * @see #setLogLevel
 * @see #getAllLogLevels
 */
function FTPClient_getLogLevel () 
{
	this._checkInitialization();
	return this.applet.getLogLevel();
}

/**
 * Sets the current logging level.
 * @param {string} level Desired logging level.
 * @see #getLogLevel
 * @see #getAllLogLevels
 */
function FTPClient_setLogLevel (level) 
{
	this._checkInitialization();
	this.applet.setLogLevel(level);
}

/**
 * Is the connection pool's keep alive thread enabled, i.e. will connections
 * in the thread pool be regularly pinged to ensure they are maintained as live
 * connections? Enabled by default.
 * 
 * @return {boolean} true if enabled, false if not enabled.
 * @see #setKeepAliveEnabled
 */
function FTPClient_isKeepAliveEnabled()
{
    this._checkInitialization();
    return this.applet.isKeepAliveEnabled()==true;
}

/**
 * Change the connection pool keep alive setting, switching it on or off. If the 
 * connection pool's keep alive thread is enabled, connections
 * in the thread pool be regularly pinged to ensure they are maintained as live
 * connections. Enabled by default.
 *
 * @param {boolean} enabled true to enable, false to disable
 * @see #isKeepAliveEnabled
 */
function FTPClient_setKeepAliveEnabled(enabled)
{
    this._checkInitialization();
    this.applet.setKeepAliveEnabled(enabled);
}

/**
 * Returns the current connection-mode.  This will be either "active" or
 * "passive".
 * @return The current connection-mode.
 * @type string
 * @see #setConnectMode
 */
function FTPClient_getConnectMode()
{
    this._checkInitialization();
    return "" + this.applet.getConnectMode();
}

/**
 * Sets the connection-mode of data-channels to "active" or "passive".
 * This value will be used in subsequent uploads, downloads and directory
 * listings. 
 * @param {string} mode Connection mode (must be "active" or "passive").
 * @see #getConnectMode
 */
function FTPClient_setConnectMode(mode)
{
    this._checkInitialization();
    try {
        this.applet.setConnectMode(mode);
    } catch (ex) {
        throw "Invalid connection-mode - must be 'active' or 'passive'.";
    }
}

/**
 * Returns the current retry-count, which determines the number of times
 * the client will retry a failing transfer before giving up.
 * @return The retry-count.
 * @type int
 * @see #setRetryCount
 * @see #getRetryDelay
 * @see #setRetryDelay
 */
function FTPClient_getRetryCount()
{
    this._checkInitialization();
    return this.applet.getRetryCount();
}

/**
 * Sets the current retry-count, which determines the number of times
 * the client will retry a failing transfer before giving up.
 * @param {int} count The retry-count.
 * @see #getRetryCount
 * @see #getRetryDelay
 * @see #setRetryDelay
 */
function FTPClient_setRetryCount(count)
{
    this._checkInitialization();
    this.applet.setRetryCount(count);
}

/**
 * Returns the current retry-delay (in milliseconds), which is the amount of time to wait
 * before retrying a failed transfer.
 * @return The retry-delay in milliseconds.
 * @type int
 * @see #getRetryCount
 * @see #setRetryCount
 * @see #setRetryDelay
 */
function FTPClient_getRetryDelay()
{
    this._checkInitialization();
    return this.applet.getRetryDelay();
}

/**
 * Sets the current retry-delay (in milliseconds), which is the amount of time to wait
 * before retrying a failed transfer.
 * @param {int} delay The retry-delay in milliseconds.
 * @see #getRetryCount
 * @see #setRetryCount
 * @see #getRetryDelay
 */
function FTPClient_setRetryDelay(delay)
{
    this._checkInitialization();
    this.applet.setRetryDelay(delay);
}

/**
 * Returns the current transfer-type.  This will be either "ascii" or
 * "passive".
 * @return The current transfer-type.
 * @type string
 * @see #setTransferType
 */
function FTPClient_getTransferType()
{
    this._checkInitialization();
    return "" + this.applet.getTransferType();
}

/**
 * Sets the transfer-type of data-channels to "ascii" or "passive".
 * This value will be used in subsequent uploads and downloads. 
 * @param {string} mode Connection mode (must be "ascii" or "passive").
 * @see #getTransferType
 */
function FTPClient_setTransferType(type)
{
    this._checkInitialization();
    try {
        this.applet.setTransferType(type);
    } catch (ex) {
        throw "Invalid connection-mode - must be 'ascii' or 'binary'.";
    }
}

/**
 * Returns the current character-set.
 * @return The current character-set.
 * @type string
 * @see #setCharacterSet
 */
function FTPClient_getCharacterSet()
{
    this._checkInitialization();
    return "" + this.applet.getCharacterSet();
}

/**
 * Sets the current character-set.  The default is US-ASCII.  Other common character-sets are
 * UTF-8, ISO-8859-1 and UTF-16.  Any character-set supported by Java is supported (see
 * <a href="http://www.google.com.au/search?q=java+charset&btnI=1">here</a>.)
 * @param {string} charSet Character-set.
 * @see #getCharacterSet
 */
function FTPClient_setCharacterSet(charSet)
{
    this._checkInitialization();
    try {
        this.applet.setCharacterSet(charSet);
    } catch (ex) {
        throw "Invalid character-set.";
    }
}

/**
 * Sets the view and editing templates.
 * @param {string} localViewURL URL Template for viewing local files.
 * @param {string} localEditorURL URL Template for editing local files.
 * @param {string} remoteViewURL URL Template for viewing remote files.
 * @param {string} removeEditorURL URL Template for editing remote files.
 * @see #isViewCachingEnabled
 * @see #setViewCachingEnabled
 */
function FTPClient_setTemplateURLs(localViewURL, localTextEditorURL, localHTMLEditorURL, 
	remoteViewURL, remoteTextEditorURL, remoteHTMLEditorURL) 
{
	this._checkInitialization();
	this.applet.setTemplateURLs(localViewURL, localTextEditorURL, localHTMLEditorURL, 
		remoteViewURL, remoteTextEditorURL, remoteHTMLEditorURL);
}

/**
 * Returns true if view-caching is enabled.
 * @return True if view-catching is enabled.
 * @type boolean
 * @see #setViewCachingEnabled
 * @see #setTemplateURLs
 */
function FTPClient_isViewCachingEnabled() 
{
	this._checkInitialization();
	return this.applet.isViewCachingEnabled();
}

/**
 * Controls whether view caching is enabled (the default is true).
 * @param {boolean} enable Set to true is view caching is desired.
 * @see #isViewCachingEnabled
 * @see #setTemplateURLs
 */
function FTPClient_setViewCachingEnabled(enable) 
{
	this._checkInitialization();
	this.applet.setViewCachingEnabled(enable);
}

/**
 * Returns true is the given host-name can be parsed.
 * Host-names should be of the form "{subdomain}.{domain}:{port}.
 * @param (string) hostName Host-name to be checked.
 * @see #remoteHost
 */
function FTPClient_isRemoteHostValid (hostName) 
{
	try {
		if (hostName===undefined || hostName===null) {
			hostName = this.remoteHost;
		}
		new FTPEndPoint(hostName);
		return true;
	} catch (e) {
		return false;
	}
}

/**
 * Shows a message-box with an OK button [ASYNCHRONOUS - no callback].
 * This method is similar to the standard JavaScript alert function, but
 * it uses a Java dialog.  It is recommended that this method is used
 * in place of the JavaScript alert function for increase
 * stability.  If the JavaScript alert function is used then instability
 * can occur if the Integral FTP applet calls back to the browser's
 * JavaScript engine while the message-box is being shown.
 * @param {string} message Message to be displayed.
 * @return A unique identifier for this asynchronous operation.
 * @type int
 * @see #ask
 */
function FTPClient_alert(message) 
{
	this._checkInitialization();
	return this.applet.alert(message);
}

/**
 * Prompts the user with a message and allows them to press one of 
 * two or three buttons [ASYNCHRONOUS - calls user-specified method when complete].
 * The callback method should have two arguments: <i>askResponse</i> ({@link FTPAskResponse})
 * and <i>tag</i> (object).
 * @param {string} message Message to be displayed as a prompt.
 * @param {callback} callbackFunction Function to be called when the user has pressed a button.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @param {string} button1Text Text of first button.
 * @param {string} button2Text Text of second button.
 * @param {string} button3Text Text of third button.
 * @return A unique identifier for this asynchronous operation.
 * @type int
 */
function FTPClient_ask(message, callbackFunction, tag, button1Text, button2Text, button3Text) 
{
	this._checkInitialization();
	if (typeof(callbackFunction)=="function") {
		callbackFunction = "" + callbackFunction;
		callbackFunction = callbackFunction.substring(0, callbackFunction.indexOf("("));
		callbackFunction = callbackFunction.replace("function", "");
		callbackFunction = callbackFunction.trim();
	}
	if (button1Text===undefined || button1Text===null) button1Text = "OK";
	if (button2Text===undefined || button2Text===null) button2Text = "Cancel";
	if (button3Text===undefined || button3Text===null) button3Text = null;
	var taskID = this.applet.ask(message, callbackFunction, button1Text, button2Text, button3Text);
	this._setTag(taskID, tag);
	return taskID
}

/**
 * Prompts the user for a file 
 * [ASYNCHRONOUS - calls user-specified method when complete].
 * The callback method should have two arguments: <i>promptFileResponse</i> ({@link FTPPromptFileResponse})
 * and <i>tag</i> (object).
 * @param {boolean} isOpen Should this be an open-file dialog (true) or a save-file dialog (false)
 * @param {callback} callbackFunction Function to be called when the user has pressed a button.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @param {string} title Title of dialog
 * @param {string} directory Starting directory of dialog
 * @param {string} file Initially selected file
 * @return A unique identifier for this asynchronous operation.
 * @type int
 */
function FTPClient_promptFile(isOpen, callbackFunction, tag, title, directory, file) 
{
	this._checkInitialization();
	if (typeof(callbackFunction)=="function") {
		callbackFunction = "" + callbackFunction;
		callbackFunction = callbackFunction.substring(0, callbackFunction.indexOf("("));
		callbackFunction = callbackFunction.replace("function", "");
		callbackFunction = callbackFunction.trim();
	}
	if (title===undefined || title===null) title = "Please select a file";
	if (directory===undefined) directory = null;
	if (file===undefined) file = null;
	var taskID = this.applet.promptFile(isOpen, title, directory, file, callbackFunction);
	this._setTag(taskID, tag);
	return taskID
}

/**
 * Prompts the user for multiple files.
 * [ASYNCHRONOUS - calls user-specified method when complete].
 * The callback method should have two arguments: <i>promptFileResponse</i> ({@link FTPPromptFileResponse})
 * and <i>tag</i> (object).
 * @param {callback} callbackFunction Function to be called when the user has pressed a button.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @param {string} title Title of dialog
 * @param {string} directory Starting directory of dialog
 * @return A unique identifier for this asynchronous operation.
 * @type int
 */
function FTPClient_promptFiles(callbackFunction, tag, title, directory) 
{
	this._checkInitialization();
	if (typeof(callbackFunction)=="function") {
		callbackFunction = "" + callbackFunction;
		callbackFunction = callbackFunction.substring(0, callbackFunction.indexOf("("));
		callbackFunction = callbackFunction.replace("function", "");
		callbackFunction = callbackFunction.trim();
	}
	if (title===undefined || title===null) title = "Please select one or more files";
	if (directory===undefined) directory = null;
	var taskID = this.applet.promptFiles(title, directory, callbackFunction);
	this._setTag(taskID, tag);
	return taskID
}
	
/**
 * Connect to an FTP server [ASYNCHRONOUS - calls {@link #onConnect} when complete].
 * The following actions must be done before calling this method:
 * <ul>
 * <li>Initialize the FTPClient by calling {@link #initialize}.</li>
 * <li>{@link #remoteHost} must be set to the host-name and (optionally) port of the FTP server.</li>
 * <li>{@link #userName} must be set to the user-name of user's account on the FTP server.</li>
 * <li>{@link #password} must be set to the password of user's account on the FTP server.</li>
 * </ul>
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * @type int
 * @see #initialize
 * @see #remoteHost
 * @see #userName
 * @see #password
 * @see #disconnect
 */
function FTPClient_connect (tag) 
{
	this._checkInitialization();
    if (this.protocol!=null)
        this.applet.setProtocol(this.protocol);
	var endPoint = new FTPEndPoint(this.remoteHost);
	this.applet.setRemoteHost(endPoint.hostName);
	if (endPoint.portNumber!=null) {
		this.applet.setRemotePort(endPoint.portNumber);
	} else {
		this.applet.setRemotePort(-1);
	}
	this.applet.setUserName(this.userName);
	this.applet.setPassword(this.password);
	if (this.initialRemoteDirectory!==null)
		this.applet.setInitialRemoteDirectory(this.initialRemoteDirectory);
	this.applet.setTransferBufferSize(this.transferBufferSize);
	this.applet.setMinTransferNotifyPeriod(this.minTransferNotifyPeriod);
	try {
		if (this.dateLanguages!==null)
		  this.applet.setDateLanguages(this.dateLanguages);
	} catch (e1) {
        throw (e1.message!==undefined) ? e1.message : e2;
	}
	try {
		var taskID = this.applet.connectAsync("FTPClient_onConnect");
		if (tag!==undefined && tag!==null) {
			this._setTag(taskID, tag);
		}
		return taskID;
	} catch (e2) {
		throw (e2.message!==undefined) ? e2.message : e2;
	}
}

/**
 * Returns true if this FTPClient is currently connected to a server.
 * @return True if this FTPClient is connected.
 * @type boolean
 * @see #connect
 * @see #disconnect
 */
function FTPClient_isConnected () 
{
	return this._isConnected;
}

/**
 * Disconnects from the server [ASYNCHRONOUS - calls {@link #onDisconnect} when complete].
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * @type int
 * @see #connect
 */
function FTPClient_disconnect (tag) {
	this._checkInitialization();
	var taskID = this.applet.disconnectAsync("FTPClient_onDisconnect");
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Changes the working directory on the server
 * [ASYNCHRONOUS - calls {@link #onChangeDirectory} when complete].
 * @param {string} directory Directory to change into.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * @type int
 */
function FTPClient_changeDirectory(directory, tag) 
{
	this._checkInitialization();
	var taskID = this.applet.changeDirectoryAsync("FTPClient_onChangeDirectory", directory);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Creates a new directory on the server
 * [ASYNCHRONOUS - calls {@link #onCreateDirectory} when complete].
 * @param {string} directory Name of the directory to create.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * @type int
 */
function FTPClient_createDirectory (directory, tag) 
{
	this._checkInitialization();
	var taskID = this.applet.createDirectoryAsync("FTPClient_onCreateDirectory", directory);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * List the contents of a remote directory 
 * [ASYNCHRONOUS - calls {@link #onDirectoryList} when complete].
 * If no directory is specified then the current working directory is listed.
 * @param {string} directory Name of directory to list.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * @type int
 */
function FTPClient_directoryList (directory, tag) 
{
	this._checkInitialization();
	if (directory===undefined || directory===null || directory=="") {
		directory = "";
	}
	var taskID = this.applet.directoryListAsync(directory, "FTPClient_onDirectoryList");
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Downloads a file [ASYNCHRONOUS - calls {@link #onDownloadFile} when complete].
 * @param {string} localFileName Name of local file to download to.
 * @param {string} remoteFileName Name of remote file to download.
 * @param {int} writeMode Specifies whether a file is overwritten 
 * ({@link #WRITEMODE_OVERWRITE}), resumed ({@link #WRITEMODE_RESUME}) or 
 * appended to ({@link #WRITEMODE_APPEND}).
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * @type int
 */
function FTPClient_downloadFile (localFileName, remoteFileName, writeMode, tag) 
{
	this._checkInitialization();
	if (writeMode===undefined) {
		writeMode = 0;
	}
	var taskID = this.applet.downloadFileAsync("FTPClient_onDownloadFile", 
		"FTPClient_onTransferProgress", localFileName, remoteFileName, writeMode);
	window.console.log(taskID);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Downloads a file into a JavaScript string 
 * [ASYNCHRONOUS - calls {@link #onDownloadText} when complete].
 * @param {string} remoteFileName Name of the file to download.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * Note that since this is an asynchronous method, the result will be returned
 * its corresponding callback {@link #onDownloadText}.
 * @type int
 */
// writeMode must be 0 (overwrite), 1 (resume) or 2 (append)
function FTPClient_downloadText(remoteFileName, tag) 
{
	this._checkInitialization();
	var taskID = this.applet.downloadTextAsync("FTPClient_onDownloadText", remoteFileName);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Uploads a file [ASYNCHRONOUS - calls {@link #onUploadFile} when complete].
 * @param {string} localFileName Name of the local file to upload.
 * @param {string} remoteFileName Name of the remote file to upload to.
 * @param {int} writeMode Specifies whether a file is overwritten 
 * ({@link #WRITEMODE_OVERWRITE}), resumed ({@link #WRITEMODE_RESUME}) or 
 * appended to ({@link #WRITEMODE_APPEND}).
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * @type int
 */
// writeMode must be 0 (overwrite), 1 (resume) or 2 (append)
function FTPClient_uploadFile (localFileName, remoteFileName, writeMode, tag) 
{
	this._checkInitialization();
	if (writeMode===undefined) {
		writeMode = 0;
	}
	var taskID = this.applet.uploadFileAsync("FTPClient_onUploadFile", 
		"FTPClient_onTransferProgress", localFileName, remoteFileName, writeMode);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Uploads a JavaScript string to a file on the server 
 * [ASYNCHRONOUS - calls {@link #onUploadText} when complete].
 * @param {string} text String to upload.
 * @param {string} remoteFileName Name of the file to write on the remote server.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * @type int
 */
function FTPClient_uploadText (text, remoteFileName, tag) 
{
	this._checkInitialization();
	var taskID = this.applet.uploadTextAsync("FTPClient_onUploadText", text, remoteFileName);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Cancels the transfer specified by the given identifier.
 * The identifier should be the one returned by one of the asynchronous
 * download or upload methods.
 * @param {int} transferID Identifier of the transfer to be cancelled.
 * @see #uploadFile
 * @see #uploadText
 * @see #downloadFile
 * @see #downloadText
 */
function FTPClient_cancelTransfer (transferID) 
{
	this._checkInitialization();
	this.applet.cancelTransferAsync(transferID);
}

/**
 * Gets the size of a file [ASYNCHRONOUS - calls {@link #onSize} when complete].
 * <b>IMPORTANT</b>: The integer returned by this method is NOT the size of the
 * file.  The size of the file will be provided to the onSize callback.
 * @param {string} remoteFileName Name of the remote file.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * Note that since this is an asynchronous method, the result will be returned
 * its corresponding callback {@link #onSize}.
 * @type int
 */
function FTPClient_size (remoteFileName, tag) 
{
	this._checkInitialization();
	var taskID = this.applet.getSizeAsync("FTPClient_onSize", remoteFileName);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Gets the last-modified time of a file 
 * [ASYNCHRONOUS - calls {@link #onModifiedTime} when complete].
 * @param {string} remoteFileName Name of the file.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * Note that since this is an asynchronous method, the result will be returned
 * its corresponding callback {@link #onModifiedTime}.
 * @type int
 */
function FTPClient_modifiedTime (remoteFileName, tag) 
{
	this._checkInitialization();
	var taskID = this.applet.getModifiedTimeAsync("FTPClient_onModifiedTime", remoteFileName);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Delete a file [ASYNCHRONOUS - calls {@link #onDeleteFile} when complete].
 * @param {string} remoteFileName Name of the file to delete.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * @type int
 */
function FTPClient_deleteFile (remoteFileName, tag) 
{
	this._checkInitialization();
	var taskID = this.applet.deleteFileAsync("FTPClient_onDeleteFile", remoteFileName);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Delete a directory [ASYNCHRONOUS - calls {@link #onDeleteDirectory} when complete].
 * @param {string} remoteDirectoryName Name of the directory to delete.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * @type int
 */
function FTPClient_deleteDirectory (remoteDirectoryName, tag) 
{
	this._checkInitialization();
	var taskID = this.applet.deleteDirectoryAsync("FTPClient_onDeleteDirectory", remoteDirectoryName);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Rename a file [ASYNCHRONOUS - calls {@link #onRename} when complete].
 * @param {string} fromFileName File to rename.
 * @param {string} toFileName New file-name.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * @type int
 */
function FTPClient_rename (fromFileName, toFileName, tag) 
{
	this._checkInitialization();
	var taskID = this.applet.renameAsync("FTPClient_onRename", fromFileName, toFileName);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Checks for the existence of a file 
 * [ASYNCHRONOUS - calls {@link #onExists} when complete].
 * @param {string} remoteFileName Name of the file to find.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * Note that since this is an asynchronous method, the result will be returned
 * its corresponding callback {@link #onExists}.
 * @type int
 */
function FTPClient_exists (remoteFileName, tag) 
{
	this._checkInitialization();
	var taskID = this.applet.existsAsync("FTPClient_onExists", remoteFileName);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Executes an arbitrary FTP command.
 * [ASYNCHRONOUS - calls {@link #onExecuteCommand} when complete].
 * @param {string} command Command to be executed.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * Note that since this is an asynchronous method, the result will be returned
 * its corresponding callback {@link #onExecuteCommand}.
 * @type int
 */
function FTPClient_executeCommand(command, tag)
{
	this._checkInitialization();
	var taskID = this.applet.executeCommand("FTPClient_onExecuteCommand", command);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * List the contents of a local directory  
 * [ASYNCHRONOUS - calls {@link #onLocalDirectoryList} when complete].
 * @param {string} dirPath Path of local directory to be listed.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * Note that since this is an asynchronous method, the result will be returned
 * its corresponding callback {@link #onLocalDirectoryList}.
 * @type int
 */
function FTPClient_localDirectoryList (dirPath, tag) 
{
	this._checkInitialization();
	var taskID = this.applet.localDirectoryListAsync("FTPClient_onLocalDirectoryList", dirPath);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Delete a local file [ASYNCHRONOUS - calls {@link #onLocalDeleteFile} when complete].
 * @param {string} fileName Name of local file to delete.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * @type int
 */
function FTPClient_localDeleteFile (fileName, tag) 
{
	this._checkInitialization();
	var taskID = this.applet.localDeleteAsync("FTPClient_onLocalDeleteFile", fileName);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Rename a local file [ASYNCHRONOUS - calls {@link #onLocalRename} when complete].
 * @param {string} oldFileName Path of file to rename.
 * @param {string} newFileName New name of file.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * @type int
 */
function FTPClient_localRename (oldFileName, newFileName, tag) 
{
	this._checkInitialization();
	var taskID = this.applet.localRenameAsync("FTPClient_onLocalRename", oldFileName, newFileName);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Creates a directory on the local disk 
 * [ASYNCHRONOUS - calls {@link #onLocalCreateDirectory} when complete].
 * @param {string} directoryName Path of the directory to create.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * @type int
 */
function FTPClient_localCreateDirectory (directoryName, tag) 
{
	this._checkInitialization();
	var taskID = this.applet.localCreateDirectoryAsync("FTPClient_onLocalCreateDirectory", directoryName);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Get the size of a local file 
 * [ASYNCHRONOUS - calls {@link #onLocalSize} when complete].
 * @param {string} fileName Path of the file.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * Note that since this is an asynchronous method, the result will be returned
 * its corresponding callback {@link #onLocalSize}.
 * @type int
 */
function FTPClient_localSize (fileName, tag) 
{
	this._checkInitialization();
	var taskID = this.applet.localSizeAsync("FTPClient_onLocalSize", fileName);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Get the last-modified time of a local file 
 * [ASYNCHRONOUS - calls {@link #onLocalModifiedTime} when complete].
 * @param {string} fileName Path of the local file.
 * @param {object} tag The value of this argument is not used by FTPClient, but is simply
 * passed to the callback when the operation is complete.  From there is may be accessed
 * via the {@link FTPCallbackStatus#tag} field.
 * @return A unique identifier for this asynchronous operation.
 * Note that since this is an asynchronous method, the result will be returned
 * its corresponding callback {@link #onLocalModifiedTime}.
 * @type int
 */
function FTPClient_localModifiedTime (fileName, tag) 
{
	this._checkInitialization();
	var taskID = this.applet.localModifiedTimeAsync("FTPClient_onLocalModifiedTime", fileName);
	if (tag!==undefined && tag!==null) {
		this._setTag(taskID, tag);
	}
	return taskID;
}

/**
 * Gets the name of the user's home directory.
 * @return Name of the directory.
 * @type string
 */
function FTPClient_getLocalHomeDirectory () 
{
	this._checkInitialization();
	return ""+this.applet.getLocalHomeDirectory();
}

/**
 * Gets the name of the user's TEMP directory.
 * @return Name of the directory.
 * @type string
 */
function FTPClient_getLocalTempDirectory () 
{
	this._checkInitialization();
	return ""+this.applet.getLocalTempDirectory();
}

/**
 * Gets the number of the port to which HTTP requests may be directed
 * when viewing the contents of a local file.
 * @return Number of the port.
 * @type int
 */
function FTPClient_getLocalAcceptorPort () 
{
	this._checkInitialization();
	return this.applet.getLocalAcceptorPort();
}

/**
 * Gets the number of the port to which HTTP requests may be directed
 * when viewing the contents of a remote file.
 * @return Number of the port.
 * @type int
 */
function FTPClient_getRemoteAcceptorPort () 
{
	this._checkInitialization();
	return this.applet.getRemoteAcceptorPort();
}

/**
 * Get the current remote working directory.
 * @return the remote working directory.
 * @type string
 */
function FTPClient_getWorkingDirectory () 
{
	this._checkInitialization();
	return "" + this.applet.getWorkingDirectory();
}

/**
 * Registers an extension as a particular MIME type.
 * MIME types are used when viewing local or remote files
 * using Integral FTP's embedded HTTP proxy.
 * @param {string} extension File-extension
 * @param {string} mimeType MIME type
 */
function FTPClient_registerMimeType (extension, mimeType) 
{
	this._checkInitialization();
	this.applet.registerMimeType(extension, mimeType);
}

/**
 * @ignore
 */
function FTPClient__addHTML(doc, html) 
{
	if (doc.all) {
		doc.body.insertAdjacentHTML('beforeEnd', html);
	} else if (doc.createRange) {
		var range = doc.createRange();
		range.setStartAfter(doc.body.lastChild);
		var docFrag = range.createContextualFragment(html);
		doc.body.appendChild(docFrag);
	} else if (doc.layers) {
		var l = new Layer(1);
		l.doc.open();
		l.doc.write(html);
		l.doc.close();
		l.top = doc.height;
		doc.height += l.doc.height;
		l.visibility = 'show';
	}
}

/**
 * @ignore
 */
function FTPClient__setTag(taskID, tag) 
{
	this._tags.push(new FTPTagItem(taskID, tag))
}

/**
 * @ignore
 */
function FTPClient__getTag(taskID, remove) 
{
	if (remove === undefined)
		remove = true;
	
	var index = -1;
	for (var i in this._tags) {
		if (this._tags[i].taskID===taskID) {
			index = i;
			break;
		}
	}
	var tag = null;
	if (index>=0) {
		tag = this._tags[index].tag;
		if (remove)
			this._tags.splice(index, 1);
	}
	return tag;
}

// FTPClient Callbacks -------------------------------------------------------

/**
 * @ignore
 */
function FTPClient_onInitialize(clientName, taskID, errorMessage)
{
	// we give the browser another 1000ms to add the applet to the DOM
	// this fixes the problem where getLocalSeparator sometimes throws
	// an exception
	if (errorMessage!=null)
		errorMessage = "\"" + errorMessage.replace("\"", "\\\"") + "\"";
	else
		errorMessage = "null";
	setTimeout("FTPClient_onInitializeDelayed('" + clientName + "', " + taskID + ", " + errorMessage + ")", 1000);
}

/**
 * @ignore
 */
function FTPClient_onInitializeDelayed(clientName, taskID, errorMessage)
{
	var ftpClient = _ftpClients[clientName];
	ftpClient.applet = document.getElementById(clientName);
	ftpClient._initComplete = true;
	setTimeout("FTPClient_hideApplet('" + clientName + "');", ftpClient.showSplash===true ? 2000 : 1);
	if (ftpClient.onInitialize!==null)
		ftpClient.onInitialize(new FTPCallbackStatus(ftpClient, errorMessage===null, errorMessage, taskID));
	try {
		// we put these inside a catch-block because they sometimes throw
		// exception (not sure why) and they're not essential for most 
		// uses
		ftpClient.applet.setErrorCallback("FTPClient_onError");
		ftpClient.localSeparator = ""+ftpClient.applet.getLocalSeparator();
	} catch (e) {
	}
}

/**
 * @ignore
 */
function FTPClient_hideApplet(clientName)
{
	_ftpClients[clientName].applet.style.width = 0;
	_ftpClients[clientName].applet.style.height = 0;
}

/**
 * @ignore
 */
function FTPClient_onError(clientName, taskID, errorMessage)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onError!==null) {
		ftpClient.onError(new FTPCallbackStatus(ftpClient, errorMessage===null, errorMessage, taskID, ftpClient._getTag(taskID)));
	}
}

/**
 * @ignore
 */
function FTPClient_onConnect(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onConnect!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		if (asyncResult!=null) {
			ftpClient._isConnected = asyncResult.isSuccessful();
			ftpClient.onConnect(FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID)));
		}
	}
}

/**
 * @ignore
 */
function FTPClient_onDisconnect(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onDisconnect!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		ftpClient._isConnected = false;
		var reasonCode = asyncResult.getReason();
		var reasonMessage;
		switch (reasonCode) {
			case 0:
				reasonMessage = "Normal disconnection.";
				break;
			case 1:
				reasonMessage = "Inactive for too long.";
				break;
			case 2:
				reasonMessage = "Lost connection.";
				break;
			default:
				reasonMessage = "Unknown cause.";
				break;
		}
		ftpClient.onDisconnect(FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID)), reasonCode, reasonMessage);
	}
}

/**
 * @ignore
 */
function FTPClient_onChangeDirectory(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onChangeDirectory!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		var remoteDirectory = status.success ? (""+asyncResult.getRemoteDirectory()) : (""+asyncResult.getDirectory());
		ftpClient.onChangeDirectory(status, remoteDirectory);
	}
}

/**
 * @ignore
 */
function FTPClient_onCreateDirectory(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onCreateDirectory!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		var remoteDirectory = status.success ? (""+asyncResult.getRemoteDirectory()) : (""+asyncResult.getDirectory());
		ftpClient.onCreateDirectory(status, remoteDirectory);
	}
}

/**
 * @ignore
 */
function FTPClient_onDirectoryList(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onDirectoryList!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		if (!status.success) {
			ftpClient.onDirectoryList(status, null, null);
		} else {
			var dirPath = (""+asyncResult.getDirectory());
			var fileList = new FTPFileList();
			var files = eval(""+asyncResult.getListingAsJavascript());
			for (var f in files) {
				var file = files[f];
				if (file.name!=="." && file.name!=="..") {
					var fileDate = new Date();
					fileDate.setFromJavaDateString(file.modifiedDate);
					fileList.add(file.path, file.name, file.size, fileDate, file.isDirectory, file.isTextFile);
				}
			}
			if (dirPath!="/") {
				fileList.insert(0, null, "..", 0, null, true, false);
			}
		
			FTPClient_sortColumn = ftpClient.remoteSortColumn;
			FTPClient_sortAscending = ftpClient.remoteSortAscending;
			fileList.files.sort(FTPClient_compareFiles);
			
			ftpClient.onDirectoryList(status, dirPath, fileList);
		}
	}
}

/**
 * @ignore
 */
function FTPClient_onTransferProgress(clientName, taskID, progressID, count)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onTransferProgress!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(progressID);
		if (asyncResult!=null) {  // timing can cause this to be zero if called after transfer completes
			var status = new FTPCallbackStatus(ftpClient, true, null, taskID, ftpClient._getTag(taskID, false));
			var remoteFileName = (""+asyncResult.getRemoteFileName());
			ftpClient.onTransferProgress(status, remoteFileName, count);
		}
	}
}

/**
 * @ignore
 */
function FTPClient_onDownloadFile(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onDownloadFile!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		var remoteFileName = status.success ? (""+asyncResult.getRemoteFileName()) : null;
		ftpClient.onDownloadFile(status, remoteFileName);
	}
}

/**
 * @ignore
 */
function FTPClient_onDownloadText(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onDownloadText!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		var remoteFileName = status.success ? (""+asyncResult.getRemoteFileName()) : null;
		var text = status.success ? (""+asyncResult.getText()) : null;
		ftpClient.onDownloadText(status, remoteFileName, text);
	}
}

/**
 * @ignore
 */
function FTPClient_onUploadFile(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onUploadFile!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		var remoteFileName = status.success ? (""+asyncResult.getRemoteFileName()) : null;
		ftpClient.onUploadFile(status, remoteFileName);
	}
}

/**
 * @ignore
 */
function FTPClient_onUploadText(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onUploadText!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		var remoteFileName = status.success ? (""+asyncResult.getRemoteFileName()) : null;
		ftpClient.onUploadText(status, remoteFileName);
	}
}

/**
 * @ignore
 */
function FTPClient_onSize(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onSize!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		var fileName = status.success ? (""+asyncResult.getRemoteFileName()) : null;
		var size = status.success ? asyncResult.getSize() : null;
		ftpClient.onSize(status, fileName, size);
	}
}

/**
 * @ignore
 */
function FTPClient_onModifiedTime(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onModifiedTime!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		var fileName = status.success ? (""+asyncResult.getRemoteFileName()) : null;
		var modTime = status.success ? asyncResult.getModifiedTime() : null;
		ftpClient.onModifiedTime(status, fileName, modTime);
	}
}
	
/**
 * @ignore
 */
function FTPClient_onDeleteFile(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onDeleteFile!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var fileName = (""+asyncResult.getRemoteFileName());
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		ftpClient.onDeleteFile(status, fileName);
	}
}
	
/**
 * @ignore
 */
function FTPClient_onDeleteDirectory(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onDeleteDirectory!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var dirName = (""+asyncResult.getRemoteDirectory());
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		ftpClient.onDeleteDirectory(status, dirName);
	}
}
	
/**
 * @ignore
 */
function FTPClient_onRename(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onRename!==null) {
		var fromName = null;
		var toName = null;
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		if (status.success) {
			fromName = (""+asyncResult.getFromFileName());
			toName = (""+asyncResult.getToFileName());
		}
		ftpClient.onRename(status, fromName, toName);
	}
}

/**
 * @ignore
 */
function FTPClient_onExists(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onExists!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		var fileName = status.success ? (""+asyncResult.getRemoteFileName()) : null;
		var exists = status.success ? asyncResult.exists() : null;
		ftpClient.onExists(status, fileName, exists);
	}
}

/**
 * @ignore FTPClient_onExecuteCommand
 */
function FTPClient_onExecuteCommand(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onExists!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		var command = status.success ? (""+asyncResult.getCommand()) : null;
		var result = status.success ? (""+asyncResult.getResult()) : null;
		ftpClient.onExecuteCommand(status, command, result);
	}
}

/**
 * @ignore
 */
function FTPClient_onLocalDirectoryList(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onLocalDirectoryList!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		if (!status.success) {
			ftpClient.onLocalDirectoryList(status, null, null);
		} else {
			var files = eval(""+asyncResult.getListingAsJavascript());
			var isRoot = false;
			var dirPath = (""+asyncResult.getDirectory());
			if (dirPath.length===0) {
				isRoot = true;
			}
			
			var fileList = new FTPFileList();
			if (!isRoot) {
				// chop off trailing separator
				var parentDir = dirPath.substring(0, dirPath.length-1);
				
				// now cut off last directory-name
				parentDir = parentDir.substring(0, parentDir.lastIndexOf(ftpClient.localSeparator)+1);
				if (this.localSeparator=="/" && parentDir=="")
					parentDir = "/"
				
				fileList.add(parentDir, "..", 0, null, true, false);
			}
			for (var f in files) {
				var file = files[f];
				var fileDate = new Date();
				fileDate.setFromJavaDateString(file.modifiedDate);
				fileList.add(file.path, file.name, file.size, fileDate, isRoot || file.isDirectory, 
						!file.isDirectory && file.isTextFile);
//				var javaFile = javaFiles.get(i);
//				var path = null;
//				var name = null;
//				var length = null;
//				var modifiedDate = null;
//				var isDirectory = null;
//				var isTextFile = null;
//				try {
//					path = javaFile.getRaw();
//					name = javaFile.getName();
//					length = parseInt(javaFile.size().toString());
//					modifiedDate = new Date();
//                    modifiedDate.setFromJavaDate(javaFile.lastModified());
//					isDirectory = isRoot || javaFile.isDir();
//					isTextFile = !isDirectory && ftpClient.applet.isTextFile(name);
//				} catch (e) {
//					//error(e.message);
//				}
//				if (path!==null && name!==null && length!==null && modifiedDate!==null 
//					&& isDirectory!==null) {
//					fileList.add(path, name, length, modifiedDate, isDirectory, isTextFile);
//				}
			}
			
			FTPClient_sortColumn = ftpClient.localSortColumn;
			FTPClient_sortAscending = ftpClient.localSortAscending;
			fileList.files.sort(FTPClient_compareFiles);
			
			ftpClient.onLocalDirectoryList(status, dirPath, fileList);
		}
	}	
}
	
/**
 * @ignore
 */
function FTPClient_onLocalRename(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onLocalRename!==null) {
		var fromName = null;
		var toName = null;
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		if (status.success) {
			fromName = (""+asyncResult.getFromFileName());
			toName = (""+asyncResult.getToFileName());
		}
		ftpClient.onLocalRename(status, fromName, toName);
	}
}
	
/**
 * @ignore
 */
function FTPClient_onLocalDeleteFile(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onLocalDeleteFile!==null) {
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var fileName = (""+asyncResult.getFileName());
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		ftpClient.onLocalDeleteFile(status, fileName);
	}
}
	
/**
 * @ignore
 */
function FTPClient_onLocalSize(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onLocalSize!==null) {
		var size = -1;
		var fileName = null;
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		if (status.success) {
			size = asyncResult.getSize();
			fileName = (""+asyncResult.getFileName());
		}
		ftpClient.onLocalSize(status, fileName, size);
	}
}

/**
 * @ignore
 */
function FTPClient_onLocalModifiedTime(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onLocalModifiedTime!==null) {
		var modifiedTime = null;
		var fileName = null;
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		if (status.success) {
			modifiedTime = new Date();
			modifiedTime.setFromJavaDate(asyncResult.getModifiedTime());
			fileName = (""+asyncResult.getFileName());
		}
		ftpClient.onLocalModifiedTime(status, fileName, modifiedTime);
	}
}

/**
 * @ignore
 */
function FTPClient_onLocalCreateDirectory(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	if (ftpClient.onLocalCreateDirectory!==null) {
		var directoryPath = null;
		var asyncResult = ftpClient.applet.getAsyncResult(taskID);
		var status = FTPClient_createStatus(ftpClient, asyncResult, taskID, ftpClient._getTag(taskID));
		if (status.success) {
			directoryPath = asyncResult.getDirectoryPath();
		}
		ftpClient.onLocalCreateDirectory(status, directoryPath);
	}
}

/**
 * @ignore
 */
function FTPClient_onDialogResult(clientName, taskID)
{
	var ftpClient = _ftpClients[clientName];
	var asyncResult = ftpClient.applet.getAsyncResult(taskID);
	var callbackMethod = asyncResult.getCallbackMethod();
	var callbackMethodString = "" + callbackMethod;
	var asyncResultString = "" + asyncResult;
	if (callbackMethod!==null && callbackMethod!==undefined 
			&& callbackMethodString!="null" && callbackMethodString!="undefined"
			&& callbackMethodString!="" ) {
		var tag = ftpClient._getTag(taskID);
		var callback = eval(""+callbackMethod);
		if (asyncResultString.indexOf("MessageBox", 0)>=0) {
			var message = asyncResult.getMessage();
			var button1Text = asyncResult.getButton1Text();
			var button2Text = asyncResult.getButton2Text();
			var button3Text = asyncResult.getButton3Text();
			var response = asyncResult.getResponse();
			callback(new FTPAskResponse(message, button1Text, button2Text, button3Text, response), tag);
		} else if (asyncResultString.indexOf("FilePrompt", 0)>=0) {
			var files = null;
			if (asyncResult.isMultiSelect() && asyncResult.getFiles().length>0) {
				files = new Array();
				for (var i=0; i<asyncResult.getFiles().length; i++)
					files[i] = "" + asyncResult.getFiles()[i];
			} else if (!asyncResult.isMultiSelect() && asyncResult.getFile()!=null) {
				files = new Array();
				files[0] = "" + asyncResult.getFile();
			}
			callback(new FTPPromptFileResponse(ftpClient, files), tag);
		}
	}
}

// FTPClient global method -------------------------------------------------------

/**
 * @ignore
 */
function FTPClient_compareFiles (file1, file2) {
	var result = 0;
	
	if (file1.isDirectory && !file2.isDirectory) {
		result = -1;
	} else if (!file1.isDirectory && file2.isDirectory) {
		result = 1;
	} else {
		if (FTPClient_sortColumn=="size") {
			result = file1.size - file2.size;
		}
		if (FTPClient_sortColumn=="date") {
			if (file1.modifiedDate===null && file2.modifiedDate!==null) {
				result = -1;
			} else if (file1.modifiedDate!==null && file2.modifiedDate===null) {
				result = 1;
			} else if (file1.modifiedDate!==null && file2.modifiedDate!==null) {
				result = file1.modifiedDate.getTime() - file2.modifiedDate.getTime();
			}
		}
		if (result===0) {
			var name1 = file1.name.toLowerCase();
			var name2 = file2.name.toLowerCase();
			result = name1 > name2 ? 1 : (name1 < name2 ? -1 : 0);
		}
	}
	
	if (FTPClient_sortAscending) {
		return result;
	} else {
		return result * -1;
	}
}


// FTPClient Callback Status ====================================================

/**
 * Construct an FTPCallbackStatus object.
 * @class Reports on the status of the an FTP operation.
 * FTPCallbackStatus objects are passed as the first argument of every
 * FTPClient callback.  It informs the callback of the success or failure
 * of the operations and the error-message (in case of failure).  It also
 * contains the unique identifier of the operation (returned by the
 * FTPClient method that launched the operation, as well as the tag that
 * was passed in when the operation was launched.  Please refer to the
 * <a href="../devguide.html">Integral FTP Developer's Guide</a> for details.
 * @param {boolean} success True if the operation succeeded.
 * @param {string} errorMessage Error message (in case of failure).
 * @param {int} taskID Task identifier.
 * @param {object} tag User-defined tag that was passed into the method.
 * that launched the operation.
 * @constructor
 */
function FTPCallbackStatus(ftpClient, success, errorMessage, taskID, tag)
{
	/**
	 * FTPClient which called back.
	 * @type FTPClient
	 */
	this.ftpClient = ftpClient;
	
	/**
	 * Flag indicating whether or not the operation succeeded.
	 * @type boolean
	 */
	this.success = success;
	
	/**
	 * Error message (in case of failure)
	 * @type string
	 */
	this.errorMessage = errorMessage!==null ? (""+errorMessage) : null;
	
	/**
	 * Unique identifier that identifies the task.
	 * @type int
	 */
	this.taskID = Number(taskID);
	
	/**
	 * User-defined tag that was passed into the method
	 * @type object
	 */
	this.tag = tag;
}

/**
 * @ignore
 */
function FTPClient_createStatus(ftpClient, asyncResult, taskID, tag)
{
	if (asyncResult===null)
		return new FTPCallbackStatus(ftpClient, false, "Internal Error: No result available.", taskID, tag);
		
	var success = asyncResult.isSuccessful();
	var exception = asyncResult.getThrowable();
	var errorMessage = exception!==undefined && exception!==null ? exception.getMessage() : null;
	return new FTPCallbackStatus(ftpClient, success, errorMessage, taskID, tag);
}


// FTPAskResponse =========================================================================

/**
 * Constructs an FTPAskResponse.
 * @class Represents a response to an {@link FTPClient@ask} invocation.  The
 * {@link #response} member contains the text of the button that the user pressed.
 * @constructor
 * @param {string} message Message that was displayed.
 * @param {string} button1Text Text of the first button.
 * @param {string} button2Text Text of the second button.
 * @param {string} button3Text Text of the third button.
 * @param {string} response Text of button that the user pressed.
 */
function FTPAskResponse(message, button1Text, button2Text, button3Text, response)
{
	/**
	 * Message that was displayed.
	 * @type string
	 */
	this.message = message;
	
	/**
	 * Text of the first button.
	 * @type string
	 */
	this.button1Text = button1Text;
	
	/**
	 * Text of the second button.
	 * @type string
	 */
	this.button2Text = button2Text;
	
	/**
	 * Text of the third button.
	 * @type string
	 */
	this.button3Text = button3Text;
	
	/**
	 * Text of button that the user pressed.
	 * @type string
	 */
	this.response = response;
}


//FTPPromptFileResponse =========================================================================

/**
* Constructs an FTPPromptFileResponse.
* @class Represents a response to an {@link FTPClient@promptFile} invocation.  The
* {@link #file} member contains the path of the file that was selected.  The value
* is null if the user cancelled the dialog.
* @constructor
* @param {string} file Path of file that was selected.
*/
function FTPPromptFileResponse(ftpClient, files)
{
	/**
	 * FTPClient which prompted
	 * @type FTPClient
	 */
	this.ftpClient = ftpClient;
	
	/**
	 * Path of (first) file that was selected.
	 * @type string
	 */
	this.file = files!=null && files.length>0 ? files[0] : null;
	
	/**
	 * Paths of files that were selected.
	 */
	this.files = files;
}


// FTPFileSize ============================================================================

/**
 * @ignore
 */
FTPFileSize_byteUnits = [ "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB"];

/**
 * Constructs an FTPFileSize object.
 * @class Represents a file-size.  This contains the size of the file in bytes as
 * an integer, a string-representation and the units of the string representation.
 * @param {int} numBytes Number of bytes in the file.
 * @constructor
 */
function FTPFileSize(numBytes) {
	/**
	 * Number of bytes in the file.
	 * @type int
	 */
	this.numBytes = numBytes;
	
	/**
	 * Units of the string-representation, {@link #numberString}.
	 * @type string
	 */
	this.units = FTPFileSize_byteUnits[0];
	
	/**
	 * String representation of the number.  The units 
	 * of this representation are given in {@link @units}.
	 * @type string
	 */
	this.numberString = "";
	
	var number = numBytes;
	var m = 1;
	while (number>=1024 && m<FTPFileSize_byteUnits.length) {
		number = Math.floor(number / 1024);
		this.units = FTPFileSize_byteUnits[m++];
	}
	number = ""+number;
	for (var i=0; i<number.length; i++) {
		this.numberString = this.numberString + number.charAt(i);
		if (i<number.length-1 && (number.length-i-1)%3===0) {
			this.numberString = this.numberString + ",";
		}
	}
}

// FTPRenderer ============================================================================

/**
 * Constructs an FTPRenderer object that may be used to write HTML to the given document.
 * @class An FTPRenderer may be used to produce an HTML representation of
 * an {@link FTPFileList}.  The main method is renderFileList, which will write the 
 * entire list to HTML.  If changes are required for particular elements of the list
 * then the FTPRenderer method that corresponds to that element may be overridden.
 * For example, by default names are rendered as
 * <tt >&lt;td class='ftpFile ftpName'&gt;fileName&lt;/td&gt;</tt>, but this may be changed
 * by overriding the {@link #renderFileName} method and changing it to write something
 * else.
 * @constructor
 * @type FTPRenderer
 */
function FTPRenderer(document)
{
	this.document = document;
	this.showSeconds = true;
}
	
FTPRenderer.prototype.renderFileList = FTPRenderer_renderFileList;
FTPRenderer.prototype.renderNameHeading = FTPRenderer_renderNameHeading;
FTPRenderer.prototype.renderSizeHeading = FTPRenderer_renderSizeHeading;
FTPRenderer.prototype.renderDateHeading = FTPRenderer_renderDateHeading;
FTPRenderer.prototype.renderFile = FTPRenderer_renderFile;
FTPRenderer.prototype.renderFileName = FTPRenderer_renderFileName;
FTPRenderer.prototype.renderFileSize = FTPRenderer_renderFileSize;
FTPRenderer.prototype.renderFileDate = FTPRenderer_renderFileDate;
FTPRenderer.prototype.renderDirectory = FTPRenderer_renderDirectory;
FTPRenderer.prototype.renderDirectoryName = FTPRenderer_renderDirectoryName;
FTPRenderer.prototype.renderDirectoryDate = FTPRenderer_renderDirectoryDate;
FTPRenderer.prototype.renderNameFooter = FTPRenderer_renderNameFooter;
FTPRenderer.prototype.renderSizeFooter = FTPRenderer_renderSizeFooter;
FTPRenderer.prototype.renderDateFooter = FTPRenderer_renderDateFooter;

/**
 * Writes the given file list to the FTPRenderer's document as a table.
 * The table will have the CSS style <tt>ftpList</tt>
 * @param {FTPFileList} fileList File-list to be renderered
 * @see FTPFileList
 */
function FTPRenderer_renderFileList(fileList) 
{
	this.document.writeln("<table class='ftpList'>");
	this.document.write("<tr>");
	this.renderNameHeading();
	this.renderSizeHeading();
	this.renderDateHeading();
	this.document.writeln("</tr>");
	for (var i=0; i<fileList.files.length; i++)
	{
		var file = fileList.files[i];
		if (file.isDirectory) {
			this.renderDirectory(file);
		} else {
			this.renderFile(file);
		}
	}
	this.document.write("<tr>");
	this.renderNameFooter();
	this.renderSizeFooter();
	this.renderDateFooter();
	this.document.writeln("</tr>");
	this.document.writeln("</table>");
}

/**
 * Called when writing the heading of the Name column.
 * The cell will have the CSS styles <tt>ftpHead ftpNameHead</tt>.
 */
function FTPRenderer_renderNameHeading() 
{
	this.document.write("<th class='ftpHead ftpNameHead'>Name</th>");
}

/**
 * Called when writing the heading of the Size column.
 * The cell will have the CSS styles <tt>ftpHead ftpSizeHead</tt>.
 */
function FTPRenderer_renderSizeHeading() 
{
	this.document.write("<th class='ftpHead ftpSizeHead' colspan='2'>Size</th>");
}

/**
 * Called when writing the heading of the Date column.
 * The cell will have the CSS styles <tt>ftpHead ftpDateHead</tt>.
 */
function FTPRenderer_renderDateHeading() 
{
	this.document.write("<th class='ftpHead ftpDateHead'>Date</th>");
}
	
/**
 * Called when rendering a file.
 * This method calls {@link #renderFileName}, {@link #renderFileSize}
 * and  {@link #renderFileDate}.
 * @param {FTPFile} file File to render.
 */
function FTPRenderer_renderFile(file) 
{
	this.document.writeln("<tr>");
	this.renderFileName(file.name, file.path, file.isTextFile);
	this.renderFileSize(new FTPFileSize(file.size));
	this.renderFileDate(file.modifiedDate);
	this.document.writeln("</tr>");
}

/**
 * Called when rendering a file-name.
 * @param {FTPFile} file File to render.
 */
function FTPRenderer_renderFileName(fileName, filePath, isTextFile) 
{
	this.document.writeln("<td class='ftpFile ftpName'>" + fileName + "</td>");
}

/**
 * Called when rendering a file-size.
 * @param {FTPFileSize} fileSize File-size to render.
 */
function FTPRenderer_renderFileSize(fileSize) 
{
	this.document.writeln("<td class='ftpFile ftpSizeNumber'>" + fileSize.numberString + "</td>");
	this.document.writeln("<td class='ftpFile ftpSizeUnits'>" + fileSize.units + "</td>");
}

/**
 * Called when rendering a file-date.
 * @param {Date} fileDate Date to render.
 */
function FTPRenderer_renderFileDate(fileDate) 
{
	this.document.write("<td class='ftpFile ftpDate'>" + fileDate.toFTPString(this.showSeconds) + "</td>");
}

/**
 * Called when rendering a directory.
 * @param {FTPFile} directory Directory to render.
 */
function FTPRenderer_renderDirectory(directory) 
{
	this.document.writeln("<tr>");
	this.renderDirectoryName(directory.name, directory.path);
	this.document.writeln("<td class='ftpFile ftpSizeNumber'></td>");
	this.document.writeln("<td class='ftpFile ftpSizeUnits'></td>");
	this.renderDirectoryDate(directory.modifiedDate);
	this.document.writeln("</tr>");
}

/**
 * Called when rendering a directory-name.
 * @param {string} directoryName Name of the directory.
 * @param {string} directoryPath Path of the directory.
 */
function FTPRenderer_renderDirectoryName(directoryName, directoryPath) 
{
	this.document.writeln("<td class='ftpFile ftpName'>" + directoryName + "</td>");
}

/**
 * Called when rendering a directory's date.
 * @param {Date} directoryDate Date of the directory.
 */
function FTPRenderer_renderDirectoryDate(directoryDate) 
{
	this.document.write("<td class='ftpFile ftpDate'>");
	if (directoryDate!==null) {
		this.document.write(directoryDate.toFTPString(this.showSeconds));
	}
	this.document.writeln("</td>");
}

/**
 * Called when rendering the Name column's footer.
 */
function FTPRenderer_renderNameFooter() 
{
	this.document.write("<td class='ftpFooter ftpNameFooter'>&nbsp;</td>");
}

/**
 * Called when rendering the Size column's footer.
 */
function FTPRenderer_renderSizeFooter() 
{
	this.document.write("<td class='ftpFooter ftpSizeFooter' colspan='2'>&nbsp;</td>");
}

/**
 * Called when rendering the Date column's footer.
 */
function FTPRenderer_renderDateFooter() 
{
	this.document.write("<td class='ftpFooter ftpDateFooter'>&nbsp;</td>");
}


// FTPFile ================================================================================

/**
 * Constructs an FTPFile object.
 * @class FTPFile contains the information describing the attributes of a
 * particular file, namely its path, name, size, last-modified date,
 * whether or not it's a directory and whether or not it's likely to be
 * a text-file.
 * @param {string} filePath Full path of the file.
 * @param {string} fileName Name of the file.
 * @param {FTPFileSize} size Size of the file.
 * @param {Date} modifiedDate Date when the file was last modified.
 * @param {boolean} isDirectory True if the object represents a directory.
 * @param {boolean} isTextFile True if the file is likely to be a text-file.
 * @constructor
 */
function FTPFile(filePath, fileName, size, modifiedDate, isDirectory, isTextFile)
{
	/**
	 * Full path of the file.
	 * @type string
	 */
	this.path = filePath!==null ? (""+filePath) : null;	// convert from Java to JS
	
	/**
	 * Name of the file.
	 * @type string
	 */
	this.name = fileName!==null ? (""+fileName) : null;	// convert from Java to JS
	
	/**
	 * Size of the file.
	 * @type FTPFileSize
	 */
	this.size = size;
	
	/**
	 * Date when the file was last modified.
	 * @type Date
	 */
	this.modifiedDate = modifiedDate;
	
	/**
	 * True if the object represents a directory.
	 * @type boolean
	 */
	this.isDirectory = (isDirectory===true);
	
	/**
	 * True if the file is likely to be a text-file.
	 * @type boolean
	 */
	this.isTextFile = isTextFile;
}

// FTPEndPoint ===========================================================================
	
/**
 * @ignore
 */
function FTPEndPoint(text) {
	text = text.trim();
	if (text.length===0) {
		throw "No server address supplied.";
	}
	var invalidMessage = "Invalid server address: must be of the form 'address[:port]'";
	var tokens = text.split(':');
	if (tokens.length>2) {
		throw invalidMessage;
	}
	var port = tokens.length>1 ? parseInt(tokens[1]): null;
	
	/**
	 * @ignore
	 */
	this.hostName = tokens[0];
	/**
	 * @ignore
	 */
	this.portNumber = port!==NaN ? port : null;
}

// FTPFileList ===========================================================================

/**
 * Constructs a file-list object.
 * @class An instance of this class represents a collection of files - usually
 * those in a particular directory.  It's important to note that FTPFileList
 * is not itself an array - the member {@link #files} is an array of {@link FTPFile}s.
 * @constructor
 */
function FTPFileList()
{
	/**
	 * An array of files.
	 * @type FTPFile
	 */
	this.files = [];
	
	/**
	 * Add a file to the end of the {@link #files} array.
	 * @param {string} filePath Full path of the file.
	 * @param {string} fileName Name of the file.
	 * @param {FTPFileSize} size Size of the file.
	 * @param {Date} modifiedDate Date when the file was last modified.
	 * @param {boolean} isDirectory True if the object represents a directory.
	 * @param {boolean} isTextFile True if the file is likely to be a text-file.
	 */
	this.add = function(path, name, size, date, isDirectory, isTextFile) {
		var file = new FTPFile(path, name, size, date, isDirectory, isTextFile);
		this.files.push(file);
	};
	
	/**
	 * Inserts a file at the given index of the {@link #files} array.
	 * @param {int} index Index at which to insert the file.
	 * @param {string} filePath Full path of the file.
	 * @param {string} fileName Name of the file.
	 * @param {FTPFileSize} size Size of the file.
	 * @param {Date} modifiedDate Date when the file was last modified.
	 * @param {boolean} isDirectory True if the object represents a directory.
	 * @param {boolean} isTextFile True if the file is likely to be a text-file.
	 */
	this.insert = function(index, path, name, size, date, isDirectory, isTextFile) {
		var file = new FTPFile(path, name, size, date, isDirectory, isTextFile);
		this.files.splice(0, 0, file);
	};
	
	/**
	 * Returns true of a file with the give path is in the list.
	 * @param {string} path Path to search for.
	 * @return True if the list contains a file with the given path.
	 * @type boolean
	 */
	this.containsFilePath = function(path) {
		for (file in this.files) {
			if (this.files[i].path==path) {
				return true;
			}
		}
		return false;
	};
	
	/**
	 * Returns true of a file with the give name is in the list.
	 * @param {string} name Name to search for.
	 * @return True if the list contains a file with the given name.
	 * @type boolean
	 */
	this.containsFileName = function(name) {
		return this.findByFileName(name)!==null;
	};
	
	/**
	 * Returns the file with the give name or null if there isn't one in the list.
	 * @param {string} name Name to search for.
	 * @return The file or null.
	 * @type FTPFile
	 */
	this.findByFileName = function(name) {
		for (i in this.files) {
			if (this.files[i].name==name) {
				return this.files[i];
			}
		}
		return null;
	};
}

// FTPTagItem ---------------------------------------------------------------------

/**
 * @ignore
 */
function FTPTagItem(taskID, tag) {
	this.taskID = taskID;
	this.tag = tag;
}

// String methods -----------------------------------------------------------------

/**
 * @ignore
 */
String.prototype.trim = function() { 
	return this.replace(/^\s+|\s+$/, ''); 
};

/**
 * @ignore
 */
String.prototype.startsWith = function(sub) {
	return sub!==null && this.substring(0, sub.length)===sub;
};

// Date methods -----------------------------------------------------------------
	
/**
 * @ignore
 */
Date.prototype.toFTPString = function(showSeconds) {
	var dateString = this.getFullYear() + 
		"-" + this._pad(this.getMonth()+1, "0", 2, true) + 
		"-"  + this._pad(this.getDate(), "0", 2, true) + 
		" " + this._pad(this.getHours(), "0", 2, true) + 
		":"  + this._pad(this.getMinutes(), "0", 2, true);
	if (showSeconds) {
		dateString = dateString + ":" + this._pad(this.getSeconds(), "0", 2, true);
	}
	return dateString;
};

Date.prototype.setFromJavaDateString = function(javaDateString) {
    this.setTime(Date.parse(javaDateString));
};

Date.prototype.setFromJavaDate = function(javaDate) {
	this.setFromJavaDateString(javaDate.toGMTString());
};

/**
 * @ignore
 */
Date.prototype._pad = function(obj, padChar, width, padLeft) {
	var text = (""+obj);
	for (var i=text.length; i<width; i++) {
		text = padLeft ? padChar + text : text + padChar;
	}
	return text;
};

Integral FTP

Documentation generated by JSDoc on Tue Jan 24 10:46:49 2012