// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (c) 2012-2014 Monty Program Ab
// Copyright (c) 2015-2021 MariaDB Corporation Ab

package org.mariadb.jdbc.util;

public final class Security {

  /**
   * Parse the option "sessionVariable" to ensure having no injection. semi-column not in string
   * will be replaced by comma.
   *
   * @param sessionVariable option value
   * @return parsed String
   */
  public static String parseSessionVariables(String sessionVariable) {
    StringBuilder out = new StringBuilder();
    StringBuilder sb = new StringBuilder();
    Parse state = Parse.Normal;
    boolean iskey = true;
    boolean singleQuotes = true;
    boolean first = true;
    String key = null;

    char[] chars = sessionVariable.toCharArray();

    for (char car : chars) {

      if (state == Parse.Escape) {
        sb.append(car);
        state = Parse.String;
        continue;
      }

      switch (car) {
        case '"':
          if (state == Parse.Normal) {
            state = Parse.String;
            singleQuotes = false;
          } else if (!singleQuotes) {
            state = Parse.Normal;
          }
          break;

        case '\'':
          if (state == Parse.Normal) {
            state = Parse.String;
            singleQuotes = true;
          } else if (singleQuotes) {
            state = Parse.Normal;
          }
          break;

        case '\\':
          if (state == Parse.String) {
            state = Parse.Escape;
          }
          break;

        case ';':
        case ',':
          if (state == Parse.Normal) {
            if (!iskey) {
              if (!first) {
                out.append(",");
              }
              out.append(key);
              out.append(sb);
              first = false;
            } else {
              key = sb.toString().trim();
              if (!key.isEmpty()) {
                if (!first) {
                  out.append(",");
                }
                out.append(key);
                first = false;
              }
            }
            iskey = true;
            key = null;
            sb = new StringBuilder();
            continue;
          }
          break;

        case '=':
          if (state == Parse.Normal && iskey) {
            key = sb.toString().trim();
            iskey = false;
            sb = new StringBuilder();
          }
          break;

        default:
          // nothing
      }

      sb.append(car);
    }

    if (!iskey) {
      if (!first) {
        out.append(",");
      }
      out.append(key);
      out.append(sb);
    } else {
      String tmpkey = sb.toString().trim();
      if (!tmpkey.isEmpty() && !first) {
        out.append(",");
      }
      out.append(tmpkey);
    }
    return out.toString();
  }

  private enum Parse {
    Normal,
    String, /* inside string */
    Escape /* found backslash */
  }
}
