/**
   * Retrieves a list of pages from Scalaris.
   *
   * @param <T>
   * @param connection the connection to Scalaris
   * @param opType operation type indicating what is being read
   * @param scalaris_keys the keys under which the page list is stored in Scalaris
   * @param failNotFound whether the operation should fail if the key is not found or not (the value
   *     contains null if not failed!)
   * @param timeAtStart the start time of the method using this method
   * @param statName name for the time measurement statistics
   * @return a result object with the page list on success
   */
  protected static final <T> ValueResult<List<T>> getPageList3(
      Connection connection,
      ScalarisOpType opType,
      Collection<String> scalaris_keys,
      boolean failNotFound,
      final long timeAtStart,
      String statName,
      ErlangConverter<List<T>> conv) {
    List<InvolvedKey> involvedKeys = new ArrayList<InvolvedKey>();

    if (connection == null) {
      return new ValueResult<List<T>>(
          false,
          involvedKeys,
          "no connection to Scalaris",
          true,
          statName,
          System.currentTimeMillis() - timeAtStart);
    }

    final MyScalarisSingleOpExecutor executor =
        new MyScalarisSingleOpExecutor(new TransactionSingleOp(connection), involvedKeys);

    final ScalarisReadListOp1<T> readOp =
        new ScalarisReadListOp1<T>(
            scalaris_keys, Options.getInstance().OPTIMISATIONS.get(opType), conv, failNotFound);
    executor.addOp(readOp);
    try {
      executor.run();
    } catch (Exception e) {
      return new ValueResult<List<T>>(
          false,
          involvedKeys,
          e.getClass().getCanonicalName()
              + " reading page list at \""
              + involvedKeys.toString()
              + "\" from Scalaris: "
              + e.getMessage(),
          e instanceof ConnectionException,
          statName,
          System.currentTimeMillis() - timeAtStart);
    }

    return new ValueResult<List<T>>(
        involvedKeys, readOp.getValue(), statName, System.currentTimeMillis() - timeAtStart);
  }
  /**
   * Retrieves a random page title from Scalaris.
   *
   * @param connection the connection to Scalaris
   * @param random the random number generator to use
   * @return a result object with the page list on success
   */
  public static final ValueResult<NormalisedTitle> getRandomArticle(
      Connection connection, Random random) {
    final long timeAtStart = System.currentTimeMillis();
    final String statName = "random article";

    final Optimisation optimisation =
        Options.getInstance().OPTIMISATIONS.get(ScalarisOpType.PAGE_LIST);
    final ErlangConverter<List<ErlangValue>> conv =
        new ErlangConverter<List<ErlangValue>>() {
          @Override
          public List<ErlangValue> convert(ErlangValue v) throws ClassCastException {
            return v.listValue();
          }
        };
    final List<String> scalarisKeys = Arrays.asList(getPageListKey(0));

    if (optimisation instanceof APPEND_INCREMENT_BUCKETS) {
      List<InvolvedKey> involvedKeys = new ArrayList<InvolvedKey>();

      if (connection == null) {
        return new ValueResult<NormalisedTitle>(
            false,
            involvedKeys,
            "no connection to Scalaris",
            true,
            statName,
            System.currentTimeMillis() - timeAtStart);
      }

      final MyScalarisSingleOpExecutor executor =
          new MyScalarisSingleOpExecutor(new TransactionSingleOp(connection), involvedKeys);

      final ScalarisReadRandomListEntryOp1<ErlangValue> readOp =
          new ScalarisReadRandomListEntryOp1<ErlangValue>(
              scalarisKeys, optimisation, conv, true, random);
      executor.addOp(readOp);
      try {
        executor.run();
      } catch (Exception e) {
        return new ValueResult<NormalisedTitle>(
            false,
            involvedKeys,
            e.getClass().getCanonicalName()
                + " reading page list at \""
                + involvedKeys.toString()
                + "\" from Scalaris: "
                + e.getMessage(),
            e instanceof ConnectionException,
            statName,
            System.currentTimeMillis() - timeAtStart);
      }

      // return if successful, otherwise fall back and read the whole list
      // as with no optimisation
      if (readOp.getValue() != null) {
        return new ValueResult<NormalisedTitle>(
            involvedKeys,
            NormalisedTitle.fromNormalised(readOp.getValue().stringValue()),
            statName,
            System.currentTimeMillis() - timeAtStart);
      }
    }

    ValueResult<List<ErlangValue>> result =
        getPageList3(
            connection, ScalarisOpType.PAGE_LIST, scalarisKeys, true, timeAtStart, statName, conv);
    ValueResult<NormalisedTitle> vResult;
    if (result.success) {
      String randomTitle = result.value.get(random.nextInt(result.value.size())).stringValue();
      vResult =
          new ValueResult<NormalisedTitle>(
              result.involvedKeys, NormalisedTitle.fromNormalised(randomTitle));
    } else {
      vResult =
          new ValueResult<NormalisedTitle>(
              false, result.involvedKeys, result.message, result.connect_failed);
    }
    vResult.stats = result.stats;
    return vResult;
  }