/* (non-Javadoc)
   * @see com.aptana.ide.core.ftp.BaseFTPConnectionFileManager#readFile(org.eclipse.core.runtime.IPath, org.eclipse.core.runtime.IProgressMonitor)
   */
  @Override
  protected InputStream readFile(IPath path, IProgressMonitor monitor)
      throws CoreException, FileNotFoundException {
    monitor.beginTask(Messages.FTPConnectionFileManager_initiating_download, 4);
    FTPClient downloadFtpClient = (FTPClient) pool.checkOut();
    try {
      initAndAuthFTPClient(downloadFtpClient, monitor, false);
      Policy.checkCanceled(monitor);
      setMessageLogger(downloadFtpClient, messageLogWriter);
      downloadFtpClient.setType(
          IFTPConstants.TRANSFER_TYPE_ASCII.equals(transferType)
              ? FTPTransferType.ASCII
              : FTPTransferType.BINARY);
      try {
        downloadFtpClient.chdir(path.removeLastSegments(1).toPortableString());
      } catch (FTPException e) {
        throwFileNotFound(e, path.removeLastSegments(1));
      }
      monitor.worked(1);
      Policy.checkCanceled(monitor);
      try {
        return new FTPFileDownloadInputStream(
            pool, downloadFtpClient, new FTPInputStream(downloadFtpClient, path.lastSegment()));
      } catch (FTPException e) {
        throwFileNotFound(e, path);
        return null;
      }
    } catch (Exception e) {
      setMessageLogger(downloadFtpClient, null);
      pool.checkIn(downloadFtpClient);

      if (e instanceof OperationCanceledException) {
        throw (OperationCanceledException) e;
      } else if (e instanceof FileNotFoundException) {
        throw (FileNotFoundException) e;
      }
      // does one retry
      if (connectionRetryCount < 1) {
        connectionRetryCount++;
        try {
          initAndAuthFTPClient(downloadFtpClient, monitor, true);
        } catch (IOException e1) {
          // ignores
        } catch (FTPException e1) {
          // ignores
        }
        try {
          return readFile(path, monitor);
        } finally {
          connectionRetryCount = 0;
        }
      } else {
        connectionRetryCount = 0;
        throw new CoreException(
            new Status(
                Status.ERROR,
                FTPPlugin.PLUGIN_ID,
                Messages.FTPConnectionFileManager_opening_file_failed,
                e));
      }
    } finally {
      monitor.done();
    }
  }
  /* (non-Javadoc)
   * @see com.aptana.ide.core.ftp.BaseFTPConnectionFileManager#writeFile(org.eclipse.core.runtime.IPath, long, org.eclipse.core.runtime.IProgressMonitor)
   */
  @Override
  protected OutputStream writeFile(IPath path, long permissions, IProgressMonitor monitor)
      throws CoreException, FileNotFoundException {
    monitor.beginTask(Messages.FTPConnectionFileManager_initiating_file_upload, 4);
    FTPClient uploadFtpClient = (FTPClient) pool.checkOut();
    try {
      initAndAuthFTPClient(uploadFtpClient, monitor, false);
      Policy.checkCanceled(monitor);
      setMessageLogger(uploadFtpClient, messageLogWriter);
      uploadFtpClient.setType(
          IFTPConstants.TRANSFER_TYPE_ASCII.equals(transferType)
              ? FTPTransferType.ASCII
              : FTPTransferType.BINARY);
      IPath dirPath = path.removeLastSegments(1);
      try {
        uploadFtpClient.chdir(dirPath.toPortableString());
      } catch (FTPException e) {
        throwFileNotFound(e, dirPath);
      }
      monitor.worked(1);
      Policy.checkCanceled(monitor);
      return new FTPFileUploadOutputStream(
          pool,
          uploadFtpClient,
          new FTPOutputStream(uploadFtpClient, generateTempFileName(path.lastSegment())),
          path.lastSegment(),
          null,
          permissions);
    } catch (Exception e) {
      setMessageLogger(uploadFtpClient, null);
      pool.checkIn(uploadFtpClient);

      if (e instanceof OperationCanceledException) {
        throw (OperationCanceledException) e;
      } else if (e instanceof FileNotFoundException) {
        throw (FileNotFoundException) e;
      } else if (e instanceof FTPException) {
        if (((FTPException) e).getReplyCode() == 553) {
          throw (FileNotFoundException)
              new FileNotFoundException(path.toPortableString()).initCause(e);
        }
      }
      if (connectionRetryCount < 1) {
        connectionRetryCount++;
        try {
          initAndAuthFTPClient(uploadFtpClient, monitor, true);
        } catch (IOException e1) {
          // ignores
        } catch (FTPException e1) {
          // ignores
        }
        try {
          return writeFile(path, permissions, monitor);
        } finally {
          connectionRetryCount = 0;
        }
      } else {
        connectionRetryCount = 0;
        throw new CoreException(
            new Status(
                Status.ERROR,
                FTPPlugin.PLUGIN_ID,
                Messages.FTPConnectionFileManager_opening_file_failed,
                e));
      }
    } finally {
      monitor.done();
    }
  }
  /* (non-Javadoc)
   * @see com.aptana.ide.core.io.vfs.IConnectionFileManager#connect(org.eclipse.core.runtime.IProgressMonitor)
   */
  public void connect(IProgressMonitor monitor) throws CoreException {
    Assert.isTrue(ftpClient != null, Messages.FTPConnectionFileManager_not_initialized);
    monitor = Policy.monitorFor(monitor);
    try {
      cwd = null;
      cleanup();

      ConnectionContext context = CoreIOPlugin.getConnectionContext(this);

      if (messageLogWriter == null) {
        if (context != null) {
          Object object = context.get(ConnectionContext.COMMAND_LOG);
          if (object instanceof PrintWriter) {
            messageLogWriter = (PrintWriter) object;
          } else if (object instanceof OutputStream) {
            messageLogWriter = new PrintWriter((OutputStream) object);
          }
        }
        if (messageLogWriter == null) {
          messageLogWriter = FTPPlugin.getDefault().getFTPLogWriter();
        }
        if (messageLogWriter != null) {
          messageLogWriter.println(StringUtils.format("---------- FTP {0} ----------", host));
          setMessageLogger(ftpClient, messageLogWriter);
        }
      } else {
        messageLogWriter.println(
            StringUtils.format("---------- RECONNECTING - FTP {0} ----------", host));
      }

      monitor.beginTask(
          Messages.FTPConnectionFileManager_establishing_connection, IProgressMonitor.UNKNOWN);
      ftpClient.setRemoteHost(host);
      ftpClient.setRemotePort(port);
      while (true) {
        monitor.subTask(Messages.FTPConnectionFileManager_connecting);
        ftpClient.connect();
        if (password.length == 0
            && !IFTPConstants.LOGIN_ANONYMOUS.equals(login)
            && (context == null || !context.getBoolean(ConnectionContext.NO_PASSWORD_PROMPT))) {
          getOrPromptPassword(
              StringUtils.format(Messages.FTPConnectionFileManager_ftp_auth, host),
              Messages.FTPConnectionFileManager_specify_password);
        }
        Policy.checkCanceled(monitor);
        monitor.subTask(Messages.FTPConnectionFileManager_authenticating);
        try {
          ftpClient.login(login, String.copyValueOf(password));
        } catch (FTPException e) {
          Policy.checkCanceled(monitor);
          if (ftpClient.getLastValidReply() == null
              || "331".equals(ftpClient.getLastValidReply().getReplyCode())) { // $NON-NLS-1$
            if (context != null && context.getBoolean(ConnectionContext.NO_PASSWORD_PROMPT)) {
              throw new CoreException(
                  new Status(
                      Status.ERROR,
                      FTPPlugin.PLUGIN_ID,
                      StringUtils.format("Authentication failed: {0}", e.getLocalizedMessage()),
                      e));
            }
            promptPassword(
                StringUtils.format(Messages.FTPConnectionFileManager_ftp_auth, host),
                Messages.FTPConnectionFileManager_invalid_password);
            safeQuit();
            continue;
          }
          throw e;
        }
        break;
      }

      Policy.checkCanceled(monitor);
      changeCurrentDir(basePath);

      ftpClient.setType(
          IFTPConstants.TRANSFER_TYPE_ASCII.equals(transferType)
              ? FTPTransferType.ASCII
              : FTPTransferType.BINARY);

      if ((hasServerInfo
              || (context != null && context.getBoolean(ConnectionContext.QUICK_CONNECT)))
          && !(context != null && context.getBoolean(ConnectionContext.DETECT_TIMEZONE))) {
        return;
      }
      getherServerInfo(context, monitor);

    } catch (OperationCanceledException e) {
      safeQuit();
      throw e;
    } catch (CoreException e) {
      safeQuit();
      throw e;
    } catch (UnknownHostException e) {
      safeQuit();
      throw new CoreException(
          new Status(
              Status.ERROR,
              FTPPlugin.PLUGIN_ID,
              "Host name not found: " + e.getLocalizedMessage(),
              e));
    } catch (FileNotFoundException e) {
      safeQuit();
      throw new CoreException(
          new Status(
              Status.ERROR,
              FTPPlugin.PLUGIN_ID,
              "Remote folder not found: " + e.getLocalizedMessage(),
              e));
    } catch (Exception e) {
      safeQuit();
      throw new CoreException(
          new Status(
              Status.ERROR,
              FTPPlugin.PLUGIN_ID,
              Messages.FTPConnectionFileManager_connection_failed + e.getLocalizedMessage(),
              e));
    } finally {
      monitor.done();
    }
  }