/*
 * Copyright (c) 2014, Yahoo!, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License. You
 * may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License. See accompanying
 * LICENSE file.
 */
package com.yahoo.ycsb.db;

import java.util.Properties;

/**
 * OptionsSupport provides methods for handling legacy options.
 *
 * @author rjm
 */
public final class OptionsSupport {

  /** Value for an unavailable property. */
  private static final String UNAVAILABLE = "n/a";

  /**
   * Updates the URL with the appropriate attributes if legacy properties are
   * set and the URL does not have the property already set.
   *
   * @param url
   *          The URL to update.
   * @param props
   *          The legacy properties.
   * @return The updated URL.
   */
  public static String updateUrl(String url, Properties props) {
    String result = url;

    // max connections.
    final String maxConnections =
        props.getProperty("mongodb.maxconnections", UNAVAILABLE).toLowerCase();
    if (!UNAVAILABLE.equals(maxConnections)) {
      result = addUrlOption(result, "maxPoolSize", maxConnections);
    }

    // Blocked thread multiplier.
    final String threadsAllowedToBlockForConnectionMultiplier =
        props
            .getProperty(
                "mongodb.threadsAllowedToBlockForConnectionMultiplier",
                UNAVAILABLE).toLowerCase();
    if (!UNAVAILABLE.equals(threadsAllowedToBlockForConnectionMultiplier)) {
      result =
          addUrlOption(result, "waitQueueMultiple",
              threadsAllowedToBlockForConnectionMultiplier);
    }

    // write concern
    String writeConcernType =
        props.getProperty("mongodb.writeConcern", UNAVAILABLE).toLowerCase();
    if (!UNAVAILABLE.equals(writeConcernType)) {
      if ("errors_ignored".equals(writeConcernType)) {
        result = addUrlOption(result, "w", "0");
      } else if ("unacknowledged".equals(writeConcernType)) {
        result = addUrlOption(result, "w", "0");
      } else if ("acknowledged".equals(writeConcernType)) {
        result = addUrlOption(result, "w", "1");
      } else if ("journaled".equals(writeConcernType)) {
        result = addUrlOption(result, "journal", "true"); // this is the
        // documented option
        // name
        result = addUrlOption(result, "j", "true"); // but keep this until
        // MongoDB Java driver
        // supports "journal" option
      } else if ("replica_acknowledged".equals(writeConcernType)) {
        result = addUrlOption(result, "w", "2");
      } else if ("majority".equals(writeConcernType)) {
        result = addUrlOption(result, "w", "majority");
      } else {
        System.err.println("WARNING: Invalid writeConcern: '"
            + writeConcernType + "' will be ignored. "
            + "Must be one of [ unacknowledged | acknowledged | "
            + "journaled | replica_acknowledged | majority ]");
      }
    }

    // read preference
    String readPreferenceType =
        props.getProperty("mongodb.readPreference", UNAVAILABLE).toLowerCase();
    if (!UNAVAILABLE.equals(readPreferenceType)) {
      if ("primary".equals(readPreferenceType)) {
        result = addUrlOption(result, "readPreference", "primary");
      } else if ("primary_preferred".equals(readPreferenceType)) {
        result = addUrlOption(result, "readPreference", "primaryPreferred");
      } else if ("secondary".equals(readPreferenceType)) {
        result = addUrlOption(result, "readPreference", "secondary");
      } else if ("secondary_preferred".equals(readPreferenceType)) {
        result = addUrlOption(result, "readPreference", "secondaryPreferred");
      } else if ("nearest".equals(readPreferenceType)) {
        result = addUrlOption(result, "readPreference", "nearest");
      } else {
        System.err.println("WARNING: Invalid readPreference: '"
            + readPreferenceType + "' will be ignored. "
            + "Must be one of [ primary | primary_preferred | "
            + "secondary | secondary_preferred | nearest ]");
      }
    }

    return result;
  }

  /**
   * Adds an option to the url if it does not already contain the option.
   *
   * @param url
   *          The URL to append the options to.
   * @param name
   *          The name of the option.
   * @param value
   *          The value for the option.
   * @return The updated URL.
   */
  private static String addUrlOption(String url, String name, String value) {
    String fullName = name + "=";
    if (!url.contains(fullName)) {
      if (url.contains("?")) {
        return url + "&" + fullName + value;
      }
      return url + "?" + fullName + value;
    }
    return url;
  }

  /**
   * Hidden Constructor.
   */
  private OptionsSupport() {
    // Nothing.
  }
}
