package de.ivu.elect.business.system.entity;

import java.sql.SQLException;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public enum DbType {


  MYSQL {
    @Override
    public String getNowFunction() {
      return "now()";
    }

    @Override
    public String getSqlResouceName() {
      return "mysql.zip";
    }

    @Override
    public boolean isRetry(String statement, SQLException sex) {
      return super.isRetry(statement, sex) || isMysqlDeadlock(sex);
    }

  },
  MARIADB {
    @Override
    public String getNowFunction() {
      return "now()";
    }

    @Override
    public String getSqlResouceName() {
      return "mysql.zip";
    }

    @Override
    public boolean isCommitAfterCraeteStatement() {
      return true;
    }

    @Override
    public boolean isRetry(String statement, SQLException sex) {
      return super.isRetry(statement, sex) || isMysqlDeadlock(sex);
    }

  },
  ORACLE {
    @Override
    public String getNowFunction() {
      return "sysdate";
    }

    @Override
    public String getSqlResouceName() {
      return "oracle.zip";
    }
  },
  H2 {
    @Override
    public String getNowFunction() {
      return "CURRENT_TIMESTAMP()";
    }

    @Override
    public String getSqlResouceName() {
      return "h2.zip";
    }

    @Override
    public boolean isSupportsMultipleColumnsInSubQuery() {
      return false; // ELECT-6934
    }

  },
  DERBY {
    @Override
    public String getNowFunction() {
      return "CURRENT_TIMESTAMP";
    }

    @Override
    public String getSqlResouceName() {
      return "derby.zip";
    }

    @Override
    public boolean isSupportsMultipleColumnsInSubQuery() {
      return false; // ELECT-6934
    }
  },
//  MSSQL {
//    @Override
//    public String getNowFunction() {
//      return "CURRENT_TIMESTAMP";
//    }
//
//    @Override
//    public String getSqlResouceName() {
//      return "mssql.zip";
//    }
//
//    @Override
//    public boolean isIgnoreSql(String statement) {
//      return super.isIgnoreSql(statement) || "go".equalsIgnoreCase(statement);
//    }
//
//    @Override
//    public boolean isRetry(String statement, SQLException sex) {
//      return super.isRetry(statement, sex) || isMssqlOnDeleteAction(statement, sex);
//    }
//
//    private boolean isMssqlOnDeleteAction(String statement, SQLException sex) {
//      return sex.getErrorCode() == 1785 && (statement.endsWith("ON DELETE CASCADE") || statement.endsWith("ON DELETE SET NULL"));
//    }
//
//    @Override
//    public String filterRetry(String statement, SQLException sex) {
//
//      // TODO ELECT-7946
//      if (isMssqlOnDeleteAction(statement, sex)) {
//        String replace = statement.replace("ON DELETE CASCADE", "ON DELETE NO ACTION");
//        replace = replace.replace("ON DELETE SET NULL", "ON DELETE NO ACTION");
//        return replace;
//      }
//      return super.filterRetry(statement, sex);
//    }
//  },

  UNKNOWN

          {
    @Override
    public boolean isUnknown() {
      return true;
    }

    @Override
    public String getNowFunction() {
      throw new UnsupportedOperationException();
    }

    @Override
    public String getSqlResouceName() {
      throw new UnsupportedOperationException();
    }
  };

  private static final Logger LOG = LoggerFactory.getLogger(DbType.class);

  public boolean isRetry(String statement, SQLException sex) {
    LOG.info("DbType.isRetry - "+"statement = '" + statement+"'"+", ErrorCode = " + sex.getErrorCode());
    return false;
  }

  public String filterRetry(String statement, SQLException sex) {
    return statement;
  }

  public boolean isCommitAfterCraeteStatement() {
    return false;
  }

  public static DbType fromProductName(String productName) {
    if (StringUtils.isBlank(productName)) {
      return UNKNOWN;
    }
    if (productName.toLowerCase().contains("mysql")) {
      return MYSQL;
    }
    if (productName.toLowerCase().contains("mariadb")) {
      return MARIADB;
    }
    if (productName.toLowerCase().contains("oracle")) {
      return ORACLE;
    }
    if (productName.toLowerCase().contains("h2")) {
      return H2;
    }
    if (productName.toLowerCase().contains("derby")) {
      return DERBY;
    }
//    if (productName.toLowerCase().contains("microsoft sql server")) {
//      return MSSQL;
//    }
    return UNKNOWN;
  }


  public boolean isUnknown() {
    return false;
  }

  public abstract String getNowFunction();

  public abstract String getSqlResouceName();

  // ELECT-6934
  public boolean isSupportsMultipleColumnsInSubQuery() {
    return true;
  }

  public boolean isIgnoreSql(String statement) {
    return false;
  }

  protected static boolean isMysqlDeadlock(SQLException sex) {
    return sex != null && sex.getMessage() != null && (sex.getMessage()
        .contains("try restarting transaction") || sex.getErrorCode() == 1213 || "40001".equals(sex.getSQLState()));
  }

}
