/**
   * Try to make a database connection to the given URL. The driver should return "null" if it
   * realizes it is the wrong kind of driver to connect to the given URL. This will be common, as
   * when the JDBC driverManager is asked to connect to a given URL, it passes the URL to each
   * loaded driver in turn.
   *
   * <p>The driver should raise an SQLException if it is the right driver to connect to the given
   * URL, but has trouble connecting to the database.
   *
   * <p>The java.util.Properties argument can be used to pass arbitrary string tag/value pairs as
   * connection arguments.
   *
   * <p>My protocol takes the form:
   *
   * <PRE>
   *
   * jdbc:mysql://host:port/database
   *
   * </PRE>
   *
   * @param url the URL of the database to connect to
   * @param info a list of arbitrary tag/value pairs as connection arguments
   * @return a connection to the URL or null if it isnt us
   * @exception SQLException if a database access error occurs
   * @see java.sql.Driver#connect
   */
  public java.sql.Connection connect(String url, Properties info) throws SQLException {
    if (url != null) {
      if (StringUtils.startsWithIgnoreCase(url, LOADBALANCE_URL_PREFIX)) {
        return connectLoadBalanced(url, info);
      } else if (StringUtils.startsWithIgnoreCase(url, REPLICATION_URL_PREFIX)) {
        return connectReplicationConnection(url, info);
      }
    }

    Properties props = null;

    if ((props = parseURL(url, info)) == null) {
      return null;
    }

    try {
      Connection newConn =
          new com.mysql.jdbc.Connection(host(props), port(props), props, database(props), url);

      return newConn;
    } catch (SQLException sqlEx) {
      // Don't wrap SQLExceptions, throw
      // them un-changed.
      throw sqlEx;
    } catch (Exception ex) {
      throw SQLError.createSQLException(
          Messages.getString("NonRegisteringDriver.17") // $NON-NLS-1$
              + ex.toString()
              + Messages.getString("NonRegisteringDriver.18"), // $NON-NLS-1$
          SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
    }
  }
  public Properties parseURL(String url, Properties defaults) throws java.sql.SQLException {
    Properties urlProps = (defaults != null) ? new Properties(defaults) : new Properties();

    if (url == null) {
      return null;
    }

    if (!StringUtils.startsWithIgnoreCase(url, URL_PREFIX)
        && !StringUtils.startsWithIgnoreCase(url, MXJ_URL_PREFIX)
        && !StringUtils.startsWithIgnoreCase(url, LOADBALANCE_URL_PREFIX)
        && !StringUtils.startsWithIgnoreCase(url, REPLICATION_URL_PREFIX)) { // $NON-NLS-1$

      return null;
    }

    int beginningOfSlashes = url.indexOf("//");

    if (StringUtils.startsWithIgnoreCase(url, MXJ_URL_PREFIX)) {
      urlProps.setProperty(
          "socketFactory", "com.mysql.management.driverlaunched.ServerLauncherSocketFactory");
    }

    /*
     * Parse parameters after the ? in the URL and remove them from the
     * original URL.
     */
    int index = url.indexOf("?"); // $NON-NLS-1$

    if (index != -1) {
      String paramString = url.substring(index + 1, url.length());
      url = url.substring(0, index);

      StringTokenizer queryParams = new StringTokenizer(paramString, "&"); // $NON-NLS-1$

      while (queryParams.hasMoreTokens()) {
        String parameterValuePair = queryParams.nextToken();

        int indexOfEquals = StringUtils.indexOfIgnoreCase(0, parameterValuePair, "=");

        String parameter = null;
        String value = null;

        if (indexOfEquals != -1) {
          parameter = parameterValuePair.substring(0, indexOfEquals);

          if (indexOfEquals + 1 < parameterValuePair.length()) {
            value = parameterValuePair.substring(indexOfEquals + 1);
          }
        }

        if ((value != null && value.length() > 0)
            && (parameter != null && parameter.length() > 0)) {
          try {
            urlProps.put(parameter, URLDecoder.decode(value, "UTF-8"));
          } catch (UnsupportedEncodingException badEncoding) {
            // punt
            urlProps.put(parameter, URLDecoder.decode(value));
          } catch (NoSuchMethodError nsme) {
            // punt again
            urlProps.put(parameter, URLDecoder.decode(value));
          }
        }
      }
    }

    url = url.substring(beginningOfSlashes + 2);

    String hostStuff = null;

    int slashIndex = url.indexOf("/"); // $NON-NLS-1$

    if (slashIndex != -1) {
      hostStuff = url.substring(0, slashIndex);

      if ((slashIndex + 1) < url.length()) {
        urlProps.put(
            DBNAME_PROPERTY_KEY, //$NON-NLS-1$
            url.substring((slashIndex + 1), url.length()));
      }
    } else {
      hostStuff = url;
    }

    if ((hostStuff != null) && (hostStuff.length() > 0)) {
      urlProps.put(HOST_PROPERTY_KEY, hostStuff); // $NON-NLS-1$
    }

    String propertiesTransformClassName = urlProps.getProperty(PROPERTIES_TRANSFORM_KEY);

    if (propertiesTransformClassName != null) {
      try {
        ConnectionPropertiesTransform propTransformer =
            (ConnectionPropertiesTransform)
                Class.forName(propertiesTransformClassName).newInstance();

        urlProps = propTransformer.transformProperties(urlProps);
      } catch (InstantiationException e) {
        throw SQLError.createSQLException(
            "Unable to create properties transform instance '"
                + propertiesTransformClassName
                + "' due to underlying exception: "
                + e.toString(),
            SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
      } catch (IllegalAccessException e) {
        throw SQLError.createSQLException(
            "Unable to create properties transform instance '"
                + propertiesTransformClassName
                + "' due to underlying exception: "
                + e.toString(),
            SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
      } catch (ClassNotFoundException e) {
        throw SQLError.createSQLException(
            "Unable to create properties transform instance '"
                + propertiesTransformClassName
                + "' due to underlying exception: "
                + e.toString(),
            SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
      }
    }

    if (Util.isColdFusion()
        && urlProps.getProperty("autoConfigureForColdFusion", "true").equalsIgnoreCase("true")) {
      String configs = urlProps.getProperty(USE_CONFIG_PROPERTY_KEY);

      StringBuffer newConfigs = new StringBuffer();

      if (configs != null) {
        newConfigs.append(configs);
        newConfigs.append(",");
      }

      newConfigs.append("coldFusion");

      urlProps.setProperty(USE_CONFIG_PROPERTY_KEY, newConfigs.toString());
    }

    // If we use a config, it actually should get overridden by anything in
    // the URL or passed-in properties

    String configNames = null;

    if (defaults != null) {
      configNames = defaults.getProperty(USE_CONFIG_PROPERTY_KEY);
    }

    if (configNames == null) {
      configNames = urlProps.getProperty(USE_CONFIG_PROPERTY_KEY);
    }

    if (configNames != null) {
      List splitNames = StringUtils.split(configNames, ",", true);

      Properties configProps = new Properties();

      Iterator namesIter = splitNames.iterator();

      while (namesIter.hasNext()) {
        String configName = (String) namesIter.next();

        try {
          InputStream configAsStream =
              getClass().getResourceAsStream("configs/" + configName + ".properties");

          if (configAsStream == null) {
            throw SQLError.createSQLException(
                "Can't find configuration template named '" + configName + "'",
                SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
          }
          configProps.load(configAsStream);
        } catch (IOException ioEx) {
          throw SQLError.createSQLException(
              "Unable to load configuration template '"
                  + configName
                  + "' due to underlying IOException: "
                  + ioEx,
              SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE);
        }
      }

      Iterator propsIter = urlProps.keySet().iterator();

      while (propsIter.hasNext()) {
        String key = propsIter.next().toString();
        String property = urlProps.getProperty(key);
        configProps.setProperty(key, property);
      }

      urlProps = configProps;
    }

    // Properties passed in should override ones in URL

    if (defaults != null) {
      Iterator propsIter = defaults.keySet().iterator();

      while (propsIter.hasNext()) {
        String key = propsIter.next().toString();
        String property = defaults.getProperty(key);
        urlProps.setProperty(key, property);
      }
    }

    return urlProps;
  }