/* BdfServer_Multi - Copyright (c) 2015-2024 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package fr.exemole.bdfserver.multi;

import fr.exemole.bdfserver.api.storage.BdfStorageException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import net.mapeadores.util.ini.IniParser;
import net.mapeadores.util.io.FileUtils;
import net.mapeadores.util.logging.CommandMessage;
import net.mapeadores.util.logging.LogUtils;
import net.mapeadores.util.request.RequestMap;
import net.mapeadores.util.security.PasswordChecker;


/**
 *
 * @author Vincent Calame
 */
public class MultiConf {

    public final static String MISSING_FILE_ERROR = "_ error.empty.inifile";
    public final static String LOGIN_PARAM = "login";
    public final static String PASSWORD_PARAM = "password";
    public final static String LANG_PARAM = "lang";
    public final static String AUTHORITY_PARAM = "authority";
    public final static String DEFAULT_FICHOTHEQUE_PARAM = "default_fichotheque";
    public final static short CONNECTED_STATE = 1;
    public final static short AUTHREQUIRED_STATE = 2;
    public final static short AUTHFAILED_STATE = 3;
    private final File iniFile;
    private final Map<String, String> confMap = new HashMap<String, String>();
    private CommandMessage initErrorMessage;
    private String login;
    private String passwordHash;

    private MultiConf(File iniFile) {
        this.iniFile = iniFile;
    }

    public void update() {
        if (iniFile.exists()) {
            confMap.clear();
            Map<String, String> map = new HashMap<String, String>();
            try (InputStream is = new FileInputStream(iniFile)) {
                IniParser.parseIni(is, map);
            } catch (IOException ioe) {
                throw new BdfStorageException(ioe);
            }
            login = null;
            passwordHash = null;
            initErrorMessage = null;
            for (Map.Entry<String, String> entry : map.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue().trim();
                switch (entry.getKey()) {
                    case LOGIN_PARAM:
                        if (!value.isEmpty()) {
                            login = value;
                        }
                        break;
                    case PASSWORD_PARAM:
                        if (!value.isEmpty()) {
                            passwordHash = value;
                        }
                        break;
                    case "uuid":
                        confMap.put("authority", value);
                        break;
                    default:
                        confMap.put(key, value);
                }
            }
            if (login == null) {
                initErrorMessage = LogUtils.error("_ error.empty.mandatoryparameter", LOGIN_PARAM);
            } else if (passwordHash == null) {
                initErrorMessage = LogUtils.error("_ error.empty.mandatoryparameter", PASSWORD_PARAM);
            } else {
                passwordHash = checkPasswordHash(passwordHash, iniFile);
            }
        } else {
            initErrorMessage = LogUtils.error(MISSING_FILE_ERROR, iniFile.getName());
        }
    }

    public File getInitFile() {
        return iniFile;
    }

    public CommandMessage getInitErrorMessage() {
        return initErrorMessage;
    }

    public String getParam(String name) {
        return confMap.get(name);
    }

    public short checkAuthentification(RequestMap requestMap, boolean passwordDisabled) {
        if (initErrorMessage != null) {
            throw new IllegalStateException("multiAdmin has init error");
        }
        String loginValue = requestMap.getParameter(LOGIN_PARAM);
        if (loginValue == null) {
            return AUTHREQUIRED_STATE;
        }
        if (!loginValue.equals(login)) {
            return AUTHFAILED_STATE;
        }
        if (!passwordDisabled) {
            String passwordValue = requestMap.getParameter(PASSWORD_PARAM);
            if (passwordValue == null) {
                return AUTHREQUIRED_STATE;
            }
            if (!PasswordChecker.check(passwordValue, passwordHash)) {
                return AUTHFAILED_STATE;
            }
        }
        return CONNECTED_STATE;
    }

    private static String checkPasswordHash(String passwordHash, File iniFile) {
        String mode = PasswordChecker.getHashMode(passwordHash);
        if (!mode.equals(PasswordChecker.CLEAR)) {
            return passwordHash;
        }
        String newHash = PasswordChecker.getHash(PasswordChecker.PBKDF2, passwordHash.substring(PasswordChecker.CLEAR.length() + 1));
        try {
            String iniString = FileUtils.readFileToString(iniFile, "UTF-8");
            iniString = iniString.replace(passwordHash, newHash);
            FileUtils.writeStringToFile(iniFile, iniString, "UTF-8");
        } catch (IOException ioe) {

        }
        return newHash;
    }

    public static MultiConf build(File iniFile) {
        MultiConf multiConf = new MultiConf(iniFile);
        multiConf.update();
        return multiConf;
    }


}
