/**
   * Compute which element should be quizzed next from the given set of elements UID, according to
   * the statistics of each elements.
   *
   * @param elementsUID Set of elementsUID from which to found the next element.
   * @return String Element Unique ID
   */
  public String getNextElement(Vector<String> elementsUID) {
    String currentElementUID = null;
    float bestScore = Float.NEGATIVE_INFINITY;
    float currentScore = bestScore;
    Vector<String> bestsUIDs = new Vector<String>();

    Iterator<String> itElements = elementsUID.iterator();
    while (itElements.hasNext()) {
      currentElementUID = itElements.next();

      if (!statistics.containsKey(currentElementUID)) {
        KanjiNoSensei.log(
            Level.WARNING,
            Messages.getString("LearningProfile.LearningProfile.WarningNeverSeenElement")
                + " : \""
                + currentElementUID
                + "\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
        return currentElementUID;
      }

      currentScore = statistics.get(currentElementUID).getNeedScore();
      if (currentScore > bestScore) {
        bestsUIDs.removeAllElements();
        bestsUIDs.add(currentElementUID);
        bestScore = currentScore;
      } else if (currentScore == bestScore) {
        bestsUIDs.add(currentElementUID);
      }
    }

    return bestsUIDs.get(random.nextInt(bestsUIDs.size()));
  }
  /**
   * Loads a learning profile from File, throws IOException on ClassNotFound.
   *
   * @param file Learning profile file to open.
   * @throws IOException on any Input/Output error.
   */
  public static LearningProfile open(File file) throws IOException {
    KanjiNoSensei.log(
        Level.INFO,
        Messages.getString("LearningProfile.OpeningFile")
            + " : \""
            + file.getAbsolutePath()
            + "\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

    LearningProfile learningProfile = null;

    // Open file stream
    ObjectInputStream ois = null;
    try {
      ois =
          new RefactoredClassNameTolerantObjectInputStream(
              new FileInputStream(file), RefactoringInfos.REFACTORED_PACKAGES);
      Object obj = ois.readObject();
      if (!LearningProfile.class.isInstance(obj)) throw new ClassNotFoundException();
      learningProfile = (LearningProfile) obj;
      learningProfile.pack();
    } catch (ClassNotFoundException e) {
      KanjiNoSensei.log(
          Level.SEVERE,
          Messages.getString("LearningProfile.Open.ErrorOnElement")
              + " : "
              + e.getMessage()); // $NON-NLS-1$ //$NON-NLS-2$
      throw new IOException(
          Messages.getString("LearningProfile.Open.ErrorOnElement") + " : " + e.getMessage(),
          e); //$NON-NLS-1$ //$NON-NLS-2$)
    } finally {
      try {
        if (ois != null) ois.close();
      } catch (Exception e) {
        // Nothing.
      }
    }

    return learningProfile;
  }
  /**
   * Add elements with empty statistics. If an element from neverSeenElements is already known and
   * has statistics, a SEVERE error is logged, but no exception is thrown.
   *
   * @param neverSeenElements Set of elements UID of never seen elements.
   */
  public void addNeverSeenElements(Vector<String> neverSeenElements) {
    Iterator<String> itElements = neverSeenElements.iterator();
    String elementUID;
    while (itElements.hasNext()) {
      elementUID = itElements.next();

      if (statistics.containsKey(elementUID)) {
        KanjiNoSensei.log(
            Level.SEVERE,
            Messages.getString(
                "LearningProfile.LearningProfile.ErrorAlreadyKnownElement")); //$NON-NLS-1$
      } else {
        statistics.put(elementUID, new Statistics());
      }
    }
  }