/**
   * Parses a line of a VMS FTP server file listing and converts it into a usable format in the form
   * of an <code> FTPFile </code> instance. If the file listing line doesn't describe a file, <code>
   *  null </code> is returned, otherwise a <code> FTPFile </code> instance representing the files
   * in the directory is returned.
   *
   * <p>
   *
   * @param entry A line of text from the file listing
   * @return An FTPFile instance corresponding to the supplied entry
   */
  public FTPFile parseFTPEntry(String entry) {
    // one block in VMS equals 512 bytes
    long longBlock = 512;

    if (matches(entry)) {
      FTPFile f = new FTPFile();
      f.setRawListing(entry);
      String name = group(1);
      String size = group(2);
      String datestr = group(3) + " " + group(4);
      String owner = group(5);
      String permissions[] = new String[3];
      permissions[0] = group(9);
      permissions[1] = group(10);
      permissions[2] = group(11);
      try {
        f.setTimestamp(super.parseTimestamp(datestr));
      } catch (ParseException e) {
        // intentionally do nothing
      }

      String grp;
      String user;
      StringTokenizer t = new StringTokenizer(owner, ",");
      switch (t.countTokens()) {
        case 1:
          grp = null;
          user = t.nextToken();
          break;
        case 2:
          grp = t.nextToken();
          user = t.nextToken();
          break;
        default:
          grp = null;
          user = null;
      }

      if (name.lastIndexOf(".DIR") != -1) {
        f.setType(FTPFile.DIRECTORY_TYPE);
      } else {
        f.setType(FTPFile.FILE_TYPE);
      }
      // set FTPFile name
      // Check also for versions to be returned or not
      if (isVersioning()) {
        f.setName(name);
      } else {
        name = name.substring(0, name.lastIndexOf(";"));
        f.setName(name);
      }
      // size is retreived in blocks and needs to be put in bytes
      // for us humans and added to the FTPFile array
      long sizeInBytes = Long.parseLong(size) * longBlock;
      f.setSize(sizeInBytes);

      f.setGroup(grp);
      f.setUser(user);
      // set group and owner

      // Set file permission.
      // VMS has (SYSTEM,OWNER,GROUP,WORLD) users that can contain
      // R (read) W (write) E (execute) D (delete)

      // iterate for OWNER GROUP WORLD permissions
      for (int access = 0; access < 3; access++) {
        String permission = permissions[access];

        f.setPermission(access, FTPFile.READ_PERMISSION, permission.indexOf('R') >= 0);
        f.setPermission(access, FTPFile.WRITE_PERMISSION, permission.indexOf('W') >= 0);
        f.setPermission(access, FTPFile.EXECUTE_PERMISSION, permission.indexOf('E') >= 0);
      }

      return f;
    }
    return null;
  }
  //    @Override
  public FTPFile parseFTPEntry(String entry) {
    FTPFile file = new FTPFile();
    file.setRawListing(entry);
    int type;
    boolean isDevice = false;

    if (matches(entry)) {
      String typeStr = group(1);
      String hardLinkCount = group(15);
      String usr = group(16);
      String grp = group(17);
      String filesize = group(18);
      String datestr = group(19) + " " + group(20);
      String name = group(21);
      String endtoken = group(22);

      try {
        file.setTimestamp(super.parseTimestamp(datestr));
      } catch (ParseException e) {
        // intentionally do nothing
      }

      // A 'whiteout' file is an ARTIFICIAL entry in any of several types of
      // 'translucent' filesystems, of which a 'union' filesystem is one.

      // bcdelfmpSs-
      switch (typeStr.charAt(0)) {
        case 'd':
          type = FTPFile.DIRECTORY_TYPE;
          break;
        case 'e': // NET-39 => z/OS external link
          type = FTPFile.SYMBOLIC_LINK_TYPE;
          break;
        case 'l':
          type = FTPFile.SYMBOLIC_LINK_TYPE;
          break;
        case 'b':
        case 'c':
          isDevice = true;
          type = FTPFile.FILE_TYPE; // TODO change this if DEVICE_TYPE implemented
          break;
        case 'f':
        case '-':
          type = FTPFile.FILE_TYPE;
          break;
        default: // e.g. ? and w = whiteout
          type = FTPFile.UNKNOWN_TYPE;
      }

      file.setType(type);

      int g = 4;
      for (int access = 0; access < 3; access++, g += 4) {
        // Use != '-' to avoid having to check for suid and sticky bits
        file.setPermission(access, FTPFile.READ_PERMISSION, (!group(g).equals("-")));
        file.setPermission(access, FTPFile.WRITE_PERMISSION, (!group(g + 1).equals("-")));

        String execPerm = group(g + 2);
        if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) {
          file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true);
        } else {
          file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false);
        }
      }

      if (!isDevice) {
        try {
          file.setHardLinkCount(Integer.parseInt(hardLinkCount));
        } catch (NumberFormatException e) {
          // intentionally do nothing
        }
      }

      file.setUser(usr);
      file.setGroup(grp);

      try {
        file.setSize(Long.parseLong(filesize));
      } catch (NumberFormatException e) {
        // intentionally do nothing
      }

      if (null == endtoken) {
        file.setName(name);
      } else {
        // oddball cases like symbolic links, file names
        // with spaces in them.
        name += endtoken;
        if (type == FTPFile.SYMBOLIC_LINK_TYPE) {

          int end = name.indexOf(" -> ");
          // Give up if no link indicator is present
          if (end == -1) {
            file.setName(name);
          } else {
            file.setName(name.substring(0, end));
            file.setLink(name.substring(end + 4));
          }

        } else {
          file.setName(name);
        }
      }
      return file;
    }
    return null;
  }