package com.atlassian.stash.internal.db;

import com.google.common.collect.ImmutableList;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;

import static com.google.common.collect.Lists.transform;

/**
 * An adapter (wrapper) for {@link DbType} instances for use within Soy templates.
 * <p>
 * Soy templates treat enums as strings, but the {@code DbType} enum is much more than a static set of strings; it
 * has a bunch of methods, some of which are overridden by particular elements of the enum. The upshot of this is that
 * we need to wrap any instance of {@code DbType} that we want to use in a Soy template.
 * <p>
 * You should be careful about deleting, or changing the names of, the methods of this class; they may not be used
 * by Java code, but they are used within Soy templates
 */
@SuppressWarnings("unused")
public class DbTypeBean {

    /**
     * The DbTypeBean that should be set as the default on forms that let the use choose a database type.
     */
    public static final DbTypeBean DEFAULT = new DbTypeBean(DbType.POSTGRES);
    /**
     * A list containing one DbTypeBean instance for each of the {@link DbType DB types}.
     */
    public static final List<DbTypeBean> ALL = ImmutableList.copyOf(transform(DbType.AS_LIST, DbTypeBean::new));

    private final DbType adaptee;

    private DbTypeBean(DbType adaptee) {
        this.adaptee = adaptee;
    }

    /**
     * Returns a DbTypeBean that wraps the DbType corresponding to the given key.
     *
     * @return a View DB Type, or null if there is no DB type for the given key
     */
    @Nullable
    public static DbTypeBean forKey(@Nonnull String key) {
        return DbType.forKey(key).map(DbTypeBean::new).orElse(null);
    }

    @Nonnull
    public String generateUrl(String hostName, String databaseNameOrSid, int port) {
        return adaptee.generateUrl(hostName, databaseNameOrSid, port);
    }

    @Nonnull
    public String getDefaultDatabaseName() {
        return adaptee.getDefaultDatabaseName().orElse("");
    }

    @Nonnull
    public String getDefaultHostName() {
        return adaptee.getDefaultHostName().orElse("");
    }

    @Nonnull
    public String getDefaultPort() {
        return adaptee.getDefaultPort().map(String::valueOf).orElse("");
    }

    @Nonnull
    public String getDefaultUserName() {
        return adaptee.getDefaultUserName().orElse("");
    }

    @Nonnull
    public String getDisplayNameKey() {
        return adaptee.getDisplayNameKey();
    }

    @Nonnull
    public String getDriverClassName() {
        return adaptee.getDriverClassName();
    }

    @Nonnull
    public String getKey() {
        return adaptee.getKey();
    }

    @Nonnull
    public String getHelpKey() {
        return adaptee.getHelpKey();
    }

    @Nonnull
    public String getProtocol() {
        return adaptee.getProtocol();
    }

    public boolean getUsesSid() {
        return adaptee.usesSid();
    }

    public boolean isClusterable() {
        return adaptee.isClusterable();
    }

    public boolean isDriverAvailable() {
        return adaptee.isDriverAvailable();
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (!(o instanceof DbTypeBean)) {
            return false;
        }
        DbTypeBean other = (DbTypeBean) o;
        return adaptee.equals(other.adaptee);
    }

    @Override
    public int hashCode() {
        return adaptee.hashCode();
    }

    @Override
    public String toString() {
        return adaptee.toString();
    }
}