/**
   * Get fingerprint similarity of input fingerprints
   *
   * @return fingerprint similarity object
   */
  public FingerprintSimilarity getFingerprintsSimilarity() {
    Map<Integer, Integer> offset_Score_Table =
        new HashMap<Integer, Integer>(); // offset_Score_Table<offset,count>
    int numFrames = 0;
    float score = 0;
    int mostSimilarFramePosition = Integer.MIN_VALUE;

    // one frame may contain several points, use the shorter one be the
    // denominator
    if (fingerprint1.length > fingerprint2.length) {
      numFrames = FingerprintManager.getNumFrames(fingerprint2);
    } else {
      numFrames = FingerprintManager.getNumFrames(fingerprint1);
    }

    // get the pairs
    PairManager pairManager = new PairManager();
    Map<Integer, List<Integer>> this_Pair_PositionList_Table =
        pairManager.getPair_PositionList_Table(fingerprint1);
    Map<Integer, List<Integer>> compareWave_Pair_PositionList_Table =
        pairManager.getPair_PositionList_Table(fingerprint2);

    for (int compareWaveHashNumber : compareWave_Pair_PositionList_Table.keySet()) {

      // if the compareWaveHashNumber doesn't exist in both tables, no
      // need to compare
      if (!this_Pair_PositionList_Table.containsKey(compareWaveHashNumber)
          || !compareWave_Pair_PositionList_Table.containsKey(compareWaveHashNumber)) {
        continue;
      }

      // for each compare hash number, get the positions
      List<Integer> wavePositionList = this_Pair_PositionList_Table.get(compareWaveHashNumber);
      List<Integer> compareWavePositionList =
          compareWave_Pair_PositionList_Table.get(compareWaveHashNumber);

      for (int thisPosition : wavePositionList) {
        for (int compareWavePosition : compareWavePositionList) {

          int offset = thisPosition - compareWavePosition;

          if (offset_Score_Table.containsKey(offset)) {
            offset_Score_Table.put(offset, offset_Score_Table.get(offset) + 1);
          } else {
            offset_Score_Table.put(offset, 1);
          }
        }
      }
    }

    // map rank
    MapRankInteger mapRank = new MapRankInteger(offset_Score_Table, false);

    // get the most similar positions and scores
    List<Integer> orderedKeyList = mapRank.getOrderedKeyList(100, true);
    if (orderedKeyList.size() > 0) {
      int key = orderedKeyList.get(0);
      // get the highest score position
      if (mostSimilarFramePosition == Integer.MIN_VALUE) {
        mostSimilarFramePosition = key;
        score = offset_Score_Table.get(key);

        // accumulate the scores from neighbours
        if (offset_Score_Table.containsKey(key - 1)) {
          score += offset_Score_Table.get(key - 1) / 2;
        }
        if (offset_Score_Table.containsKey(key + 1)) {
          score += offset_Score_Table.get(key + 1) / 2;
        }
      }
    }

    /*
     * Iterator<Integer> orderedKeyListIterator=orderedKeyList.iterator();
     * while (orderedKeyListIterator.hasNext()){ int
     * offset=orderedKeyListIterator.next();
     * System.out.println(offset+": "+offset_Score_Table.get(offset)); }
     */

    score /= numFrames;
    float similarity = score;
    // similarity >1 means in average there is at least one match in every
    // frame
    if (similarity > 1) {
      similarity = 1;
    }

    fingerprintSimilarity.setMostSimilarFramePosition(mostSimilarFramePosition);
    fingerprintSimilarity.setScore(score);
    fingerprintSimilarity.setSimilarity(similarity);

    return fingerprintSimilarity;
  }