/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2024 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * 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.
 */

package org.jboss.installer.postinstall.task.secdom;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class KerberosConfig {
    // serialization keys
    private static final String KERBEROS_SECURITY_FACTORY_NAME = "kerberos-security-factory";
    private static final String PRINCIPAL = "principal";
    private static final String KEYTAB_PATH = "keytab";
    private static final String MECHANISM_NAME = "mechanism-name-";
    private static final String MECHANISM_NAMES_COUNT = "mechanism-names-count";
    private static final String MECHANISM_OID = "mechanism-oid-";
    private static final String MECHANISM_OIDS_COUNT = "mechanism-oids-count";
    private static final String KRB5_CONF = "krb5.conf";
    private static final String FILESYSTEM_REALM_NAME = "filesystemRealmName";
    private static final String FILESYSTEM_REALM_PATH = "filesystemRealmPath";
    private static final String FILESYSTEM_REALM_STANDALONE_PATH = "filesystemRealmStandalonePath";
    private static final String FILESYSTEM_REALM_DOMAIN_PATH = "filesystemRealmDomainPath";
    private static final String IDENTITY_NAME = "identityName";
    private static final String IDENTITY_ATTRIBUTE_NAME = "identityAttribute";
    private static final String IDENTITY_ATTRIBUTE_VALUE = "identity-attribute-value-";
    private static final String IDENTITY_ATTRIBUTE_VALUE_COUNT = "identity-attribute-value-count";
    private static final String SIMPLE_ROLE_DECODER_NAME = "simpleRoleDecoderName";
    private static final String SIMPLE_ROLE_DECODER_VALUE = "simpleRoleDecoderAttribute";
    // end of serialization keys
    private String kerberosSecurityFactoryName;
    private String principal;
    private Path keyTabPath;
    private String[] mechanismNames;
    private String[] mechanismOids;
    private Path krb5Conf;
    private String fileSystemRealmName;
    private String fileSystemRealmPath;
    private Path fileSystemRealmStandalonePath;
    private Path fileSystemRealmDomainPath;
    private String identityName;
    private String identityAttributeName;
    private String[] identityAttributeValue;
    private String simpleRoleDecoderName;
    private String simpleRoleDecoderAttribute;

    public KerberosConfig() {
    }

    public KerberosConfig(Map<String, String> attributes) {
        this.kerberosSecurityFactoryName = attributes.get(KERBEROS_SECURITY_FACTORY_NAME);
        this.principal = attributes.get(PRINCIPAL);
        this.keyTabPath = Paths.get(attributes.get(KEYTAB_PATH));
        final int mechanismNamesCount = Integer.parseInt(attributes.get(MECHANISM_NAMES_COUNT));
        if (mechanismNamesCount > 0) {
            final List<String> mechanismNames = new ArrayList<>(mechanismNamesCount);
            for (int i = 0; i < mechanismNamesCount; i++) {
                mechanismNames.add(attributes.get(MECHANISM_NAME + i));
            }
            this.mechanismNames = mechanismNames.toArray(String[]::new);
        } else {
            this.mechanismNames = new String[]{};
        }
        final int mechanismOidsCount = Integer.parseInt(attributes.get(MECHANISM_OIDS_COUNT));
        if (mechanismOidsCount > 0) {
            final List<String> mechanismOids = new ArrayList<>(mechanismOidsCount);
            for (int i = 0; i < mechanismOidsCount; i++) {
                mechanismOids.add(attributes.get(MECHANISM_OID + i));
            }
            this.mechanismOids = mechanismOids.toArray(String[]::new);
        } else {
            this.mechanismOids = new String[]{};
        }
        this.krb5Conf = Paths.get(attributes.get(KRB5_CONF));
        this.fileSystemRealmName = attributes.get(FILESYSTEM_REALM_NAME);
        this.fileSystemRealmPath = attributes.get(FILESYSTEM_REALM_PATH);
        this.fileSystemRealmStandalonePath = Paths.get(attributes.get(FILESYSTEM_REALM_STANDALONE_PATH));
        this.fileSystemRealmDomainPath = Paths.get(attributes.get(FILESYSTEM_REALM_DOMAIN_PATH));
        this.identityName = attributes.get(IDENTITY_NAME);
        this.identityAttributeName = attributes.get(IDENTITY_ATTRIBUTE_NAME);
        final int identityAttributeValueCount = Integer.parseInt(attributes.get(IDENTITY_ATTRIBUTE_VALUE_COUNT));
        if (identityAttributeValueCount > 0) {
            final List<String> identityAttributeValue = new ArrayList<>(identityAttributeValueCount);
            for (int i = 0; i < identityAttributeValueCount; i++) {
                identityAttributeValue.add(attributes.get(IDENTITY_ATTRIBUTE_VALUE + i));
            }
            this.identityAttributeValue = identityAttributeValue.toArray(String[]::new);
        } else {
            this.identityAttributeValue = new String[]{};
        }
        this.simpleRoleDecoderName = attributes.get(SIMPLE_ROLE_DECODER_NAME);
        this.simpleRoleDecoderAttribute = attributes.get(SIMPLE_ROLE_DECODER_VALUE);
    }

    public String getKerberosSecurityFactoryName() {
        return kerberosSecurityFactoryName;
    }

    public void setKerberosSecurityFactoryName(String kerberosSecurityFactoryName) {
        this.kerberosSecurityFactoryName = kerberosSecurityFactoryName;
    }

    public String getPrincipal() {
        return principal;
    }

    public void setPrincipal(String principal) {
        this.principal = principal;
    }

    public Path getKeyTabPath() {
        return keyTabPath;
    }

    public void setKeyTabPath(Path keyTabPath) {
        this.keyTabPath = keyTabPath;
    }

    public String[] getMechanismNames() {
        return mechanismNames;
    }

    public void setMechanismNames(String[] mechanismNames) {
        this.mechanismNames = mechanismNames;
    }

    public String[] getMechanismOids() {
        return mechanismOids;
    }

    public void setMechanismOids(String[] mechanismOids) {
        this.mechanismOids = mechanismOids;
    }

    public Path getKrb5Conf() {
        return krb5Conf;
    }

    public void setKrb5Conf(Path krb5Conf) {
        this.krb5Conf = krb5Conf;
    }

    public String getFileSystemRealmName() {
        return fileSystemRealmName;
    }

    public void setFileSystemRealmName(String fileSystemRealmName) {
        this.fileSystemRealmName = fileSystemRealmName;
    }

    public String getFileSystemRealmPath() {
        return fileSystemRealmPath;
    }

    public void setFileSystemRealmPath(String fileSystemRealmPath) {
        this.fileSystemRealmPath = fileSystemRealmPath;
    }

    public Path getFileSystemRealmStandalonePath() {
        return fileSystemRealmStandalonePath;
    }

    public void setFileSystemRealmStandalonePath(Path fileSystemRealmStandalonePath) {
        this.fileSystemRealmStandalonePath = fileSystemRealmStandalonePath;
    }

    public Path getFileSystemRealmDomainPath() {
        return fileSystemRealmDomainPath;
    }

    public void setFileSystemRealmDomainPath(Path fileSystemRealmDomainPath) {
        this.fileSystemRealmDomainPath = fileSystemRealmDomainPath;
    }

    public String getIdentityName() {
        return identityName;
    }

    public void setIdentityName(String identityName) {
        this.identityName = identityName;
    }

    public String getIdentityAttributeName() {
        return identityAttributeName;
    }

    public void setIdentityAttributeName(String identityAttributeName) {
        this.identityAttributeName = identityAttributeName;
    }

    public String[] getIdentityAttributeValue() {
        return identityAttributeValue;
    }

    public void setIdentityAttributeValue(String[] identityAttributeValue) {
        this.identityAttributeValue = identityAttributeValue;
    }

    public String getSimpleRoleDecoderName() {
        return simpleRoleDecoderName;
    }

    public void setSimpleRoleDecoderName(String simpleRoleDecoderName) {
        this.simpleRoleDecoderName = simpleRoleDecoderName;
    }

    public String getSimpleRoleDecoderAttribute() {
        return simpleRoleDecoderAttribute;
    }

    public void setSimpleRoleDecoderAttribute(String simpleRoleDecoderAttribute) {
        this.simpleRoleDecoderAttribute = simpleRoleDecoderAttribute;
    }

    public Map<String, String> toAttributes() {
        final Map<String, String> attrs = new HashMap<>();
        attrs.put(KERBEROS_SECURITY_FACTORY_NAME, kerberosSecurityFactoryName);
        attrs.put(PRINCIPAL, principal);
        attrs.put(KEYTAB_PATH, keyTabPath.toString());
        if (mechanismNames.length > 0) {
            for (int i = 0; i < mechanismNames.length; i++) {
                attrs.put(MECHANISM_NAME + i, mechanismNames[i]);
            }
            attrs.put(MECHANISM_NAMES_COUNT, String.valueOf(mechanismNames.length));
        }
        if (mechanismOids.length > 0) {
            for (int i = 0; i < mechanismOids.length; i++) {
                attrs.put(MECHANISM_OID + i, mechanismOids[i]);
            }
            attrs.put(MECHANISM_OIDS_COUNT, String.valueOf(mechanismOids.length));
        }
        attrs.put(KRB5_CONF, krb5Conf.toString());
        attrs.put(FILESYSTEM_REALM_NAME, fileSystemRealmName);
        attrs.put(FILESYSTEM_REALM_PATH, fileSystemRealmPath);
        attrs.put(FILESYSTEM_REALM_STANDALONE_PATH, fileSystemRealmStandalonePath.toString());
        attrs.put(FILESYSTEM_REALM_DOMAIN_PATH, fileSystemRealmDomainPath.toString());
        attrs.put(IDENTITY_NAME, identityName);
        attrs.put(IDENTITY_ATTRIBUTE_NAME, identityAttributeName);
        if (identityAttributeValue.length > 0) {
            for (int i = 0; i < identityAttributeValue.length; i++) {
                attrs.put(IDENTITY_ATTRIBUTE_VALUE + i, identityAttributeValue[i]);
            }
            attrs.put(IDENTITY_ATTRIBUTE_VALUE_COUNT, String.valueOf(identityAttributeValue.length));
        }
        attrs.put(SIMPLE_ROLE_DECODER_NAME, simpleRoleDecoderName);
        attrs.put(SIMPLE_ROLE_DECODER_VALUE, simpleRoleDecoderAttribute);
        return attrs;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        KerberosConfig that = (KerberosConfig) o;
        return Objects.equals(kerberosSecurityFactoryName, that.kerberosSecurityFactoryName) && Objects.equals(principal, that.principal) && Objects.equals(keyTabPath, that.keyTabPath) && Arrays.equals(mechanismNames, that.mechanismNames) && Arrays.equals(mechanismOids, that.mechanismOids) && Objects.equals(krb5Conf, that.krb5Conf) && Objects.equals(fileSystemRealmName, that.fileSystemRealmName) && Objects.equals(fileSystemRealmPath, that.fileSystemRealmPath) && Objects.equals(fileSystemRealmStandalonePath, that.fileSystemRealmStandalonePath) && Objects.equals(fileSystemRealmDomainPath, that.fileSystemRealmDomainPath) && Objects.equals(identityName, that.identityName) && Objects.equals(identityAttributeName, that.identityAttributeName) && Arrays.equals(identityAttributeValue, that.identityAttributeValue) && Objects.equals(simpleRoleDecoderName, that.simpleRoleDecoderName) && Objects.equals(simpleRoleDecoderAttribute, that.simpleRoleDecoderAttribute);
    }

    @Override
    public int hashCode() {
        int result = Objects.hash(kerberosSecurityFactoryName, principal, keyTabPath, krb5Conf, fileSystemRealmName, fileSystemRealmPath, fileSystemRealmStandalonePath, fileSystemRealmDomainPath, identityName, identityAttributeName, simpleRoleDecoderName, simpleRoleDecoderAttribute);
        result = 31 * result + Arrays.hashCode(mechanismNames);
        result = 31 * result + Arrays.hashCode(mechanismOids);
        result = 31 * result + Arrays.hashCode(identityAttributeValue);
        return result;
    }
}
