/* BdfServer_Multi - Copyright (c) 2019-2022 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.commands;

import fr.exemole.bdfserver.multi.commands.fichotheque.FichothequeCreationCommand;
import fr.exemole.bdfserver.multi.MultiConf;
import fr.exemole.bdfserver.multi.api.Multi;
import fr.exemole.bdfserver.multi.api.MultiEditor;
import fr.exemole.bdfserver.multi.api.MultiMetadata;
import fr.exemole.bdfserver.multi.api.MultiMetadataEditor;
import fr.exemole.bdfserver.storage.directory.bdfdata.StartValues;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import net.fichotheque.EditOrigin;
import net.fichotheque.utils.EditOriginUtils;
import net.fichotheque.utils.SphereUtils;
import net.mapeadores.util.io.FileUtils;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.localisation.LangsUtils;
import net.mapeadores.util.logging.CommandMessage;
import net.mapeadores.util.logging.ErrorMessageException;
import net.mapeadores.util.logging.LogUtils;
import net.mapeadores.util.request.RequestMap;
import net.mapeadores.util.security.PasswordChecker;
import net.mapeadores.util.text.StringUtils;


/**
 *
 * @author Vincent Calame
 */
public class IniCommand extends AbstractMultiCommand {

    public final static String COMMAND_NAME = "Ini";
    public final static String LOGIN_PARAMNAME = "login";
    public final static String PASSWORD1_PARAMNAME = "password_1";
    public final static String PASSWORD2_PARAMNAME = "password_2";
    public final static String LANG_PARAMNAME = "lang";
    public final static String AUTHORITY_PARAMNAME = "authority";
    public final static String CREATEFICHOTHEQUE_PARAMNAME = "createfichotheque";

    public IniCommand(RequestMap requestMap, Multi multi) {
        super(multi, requestMap);
    }

    @Override
    public CommandMessage doCommand() throws ErrorMessageException {
        Result result = doIniCommand();
        return result.getCommandMessage();
    }

    public Result doIniCommand() {
        EditOrigin editOrigin = EditOriginUtils.newEditOrigin("multi-admin/init");
        List<String> iniLineList = new ArrayList<String>();
        MultiEditor multiEditor = multi.getMultiEditor(editOrigin);
        Result result = new Result();
        try {
            checkLineList(result, iniLineList, multiEditor.getMultiMetadataEditor());
            CreationParameters creationParameters = checkCreationParameters(result, multi.getMultiMetadata());
            writeIniFile(iniLineList);
            multi.getMultiConf().update();
            if (creationParameters != null) {
                multi.createFichotheque(creationParameters);
            }
            multiEditor.saveChanges();
            result.setCommandMessage(LogUtils.done("_ done.multi.ini"));
        } catch (ErrorMessageException eme) {
            result.setCommandMessage(eme.getErrorMessage());
        }
        return result;
    }

    private void checkLineList(Result result, List<String> iniLineList, MultiMetadataEditor multiMetadataEditor) throws ErrorMessageException {
        String authority = getMandatory(AUTHORITY_PARAMNAME);
        Lang lang = getLang();
        String login = getMandatory(LOGIN_PARAMNAME);
        String password1 = getMandatory(PASSWORD1_PARAMNAME);
        String password2 = getMandatory(PASSWORD2_PARAMNAME);
        if (!StringUtils.isAuthority(authority)) {
            throw new ErrorMessageException("_ error.wrong.authority", authority);
        }
        if (!SphereUtils.testLogin(login)) {
            throw new ErrorMessageException("_ error.wrong.login", login);
        }
        if (!password1.equals(password2)) {
            throw new ErrorMessageException("_ error.wrong.password_different");
        }
        result.setIni(login);
        addLine(iniLineList, MultiConf.LOGIN_PARAM, login);
        addLine(iniLineList, MultiConf.PASSWORD_PARAM, PasswordChecker.getHash(PasswordChecker.PBKDF2, password1));
        multiMetadataEditor.setAuthority(authority);
        multiMetadataEditor.setWorkingLangs(LangsUtils.wrap(lang));
    }

    private CreationParameters checkCreationParameters(Result result, MultiMetadata multiMetadata) throws ErrorMessageException {
        if (!multi.isEmpty()) {
            return null;
        }
        if (!requestMap.isTrue(CREATEFICHOTHEQUE_PARAMNAME)) {
            return null;
        }
        String fichothequeName = getFichothequeName(FichothequeCreationCommand.NEWFICHOTHEQUE_PARAMNAME);
        StartValues startValues = FichothequeCreationCommand.getStartValues(requestMap)
                .authority(multiMetadata.getAuthority())
                .basename(fichothequeName)
                .workingLangs(multiMetadata.getWorkingLangs());
        result.setCreation(fichothequeName, startValues);
        return CreationParameters.initNew(fichothequeName, startValues);
    }

    private void addLine(List<String> lineList, String name, String value) {
        lineList.add(name + "=" + value);
    }

    private Lang getLang() throws ErrorMessageException {
        String langValue = getMandatory(LANG_PARAMNAME);
        try {
            return Lang.parse(langValue);
        } catch (ParseException pe) {
            throw new ErrorMessageException("_ error.wrong.lang", langValue);
        }
    }

    private void writeIniFile(List<String> lineList) throws ErrorMessageException {
        try {
            FileUtils.writeLines(multi.getMultiConf().getInitFile(), "UTF-8", lineList);
        } catch (IOException ioe) {
            throw new ErrorMessageException("_ error.exception.io", ioe.getLocalizedMessage());
        }
    }


    public static class Result {

        private CommandMessage commandMessage;
        private String adminLogin;
        private String newFichothequeName;
        private StartValues startValues;


        private Result() {
        }

        public boolean hasError() {
            return commandMessage.isErrorMessage();
        }

        public CommandMessage getCommandMessage() {
            return commandMessage;
        }

        public boolean isWithNewFichotheque() {
            return (newFichothequeName != null);
        }

        public String getNewFichothequeName() {
            return newFichothequeName;
        }

        public String getAdminLogin() {
            return adminLogin;
        }

        public StartValues getStartValues() {
            return startValues;
        }

        private void setIni(String adminLogin) {
            this.adminLogin = adminLogin;
        }

        private void setCreation(String newFichothequeName, StartValues startValues) {
            this.newFichothequeName = newFichothequeName;
            this.startValues = startValues;
        }

        private void setCommandMessage(CommandMessage commandMessage) {
            this.commandMessage = commandMessage;
        }

    }

}
