/* BdfServer_Multi - Copyright (c) 2015-2025 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.multi.api.Multi;
import fr.exemole.bdfserver.multi.api.MultiConstants;
import fr.exemole.bdfserver.multi.api.central.CentralSphere;
import fr.exemole.bdfserver.multi.api.central.CentralUser;
import fr.exemole.bdfserver.multi.commands.IniCommand;
import fr.exemole.bdfserver.multi.htmlproducers.AdminHtmlProducer;
import fr.exemole.bdfserver.multi.htmlproducers.AppHtmlProducer;
import fr.exemole.bdfserver.multi.htmlproducers.CentralLoginHtmlProducer;
import fr.exemole.bdfserver.multi.htmlproducers.CentralSphereHtmlProducer;
import fr.exemole.bdfserver.multi.htmlproducers.IndexHtmlProducer;
import fr.exemole.bdfserver.multi.htmlproducers.IniFormHtmlProducer;
import fr.exemole.bdfserver.multi.htmlproducers.IniResultHtmlProducer;
import fr.exemole.bdfserver.multi.htmlproducers.MultiHtmlProducer;
import fr.exemole.bdfserver.multi.htmlproducers.MultiMessageHtmlProducer;
import fr.exemole.bdfserver.multi.jsonproducers.MultiJsonProducer;
import fr.exemole.bdfserver.multi.jsonproducers.MultiJsonProducerFactory;
import fr.exemole.bdfserver.multi.streamproducers.SynthesisOdsProducer;
import fr.exemole.bdfserver.multi.subscribe.SubscribeEngine;
import fr.exemole.bdfserver.multi.subscribe.SubscribeParameters;
import fr.exemole.bdfserver.tools.apps.AppConf;
import java.text.ParseException;
import net.mapeadores.util.exceptions.SwitchException;
import net.mapeadores.util.html.HtmlProducer;
import net.mapeadores.util.io.DocStream;
import net.mapeadores.util.json.JsonProducer;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.localisation.LangPreference;
import net.mapeadores.util.localisation.LangPreferenceBuilder;
import net.mapeadores.util.logging.CommandMessage;
import net.mapeadores.util.logging.ErrorMessageException;
import net.mapeadores.util.logging.LogUtils;
import net.mapeadores.util.request.OutputInfo;
import net.mapeadores.util.request.RequestConstants;
import net.mapeadores.util.request.RequestMap;
import net.mapeadores.util.request.RequestUtils;
import net.mapeadores.util.servlets.ResponseHandler;
import net.mapeadores.util.servlets.exceptions.NotFoundException;
import net.mapeadores.util.servlets.handlers.DocStreamResponseHandler;
import net.mapeadores.util.servlets.handlers.HtmlResponseHandler;
import net.mapeadores.util.servlets.handlers.JsonResponseHandler;
import net.mapeadores.util.servlets.handlers.ResponseHandlerFactory;
import net.mapeadores.util.servlets.handlers.StreamResponseHandler;
import net.mapeadores.util.text.RelativePath;


/**
 *
 * @author Vincent Calame
 */
public final class MultiInstructions {

    private MultiInstructions() {

    }

    public static ResponseHandler checkInitError(Multi multi, OutputInfo outputInfo, RequestMap requestMap) {
        CommandMessage initErrorMessage = multi.getMultiConf().getInitErrorMessage();
        if (initErrorMessage != null) {
            if (outputInfo.getType() == OutputInfo.JSON_TYPE) {
                return ResponseHandlerFactory.getJsonInstance(multi.getAdminMessageLocalisation(), requestMap, initErrorMessage);
            } else if (outputInfo.getType() == OutputInfo.STREAM_TYPE) {
                return ResponseHandlerFactory.getTextInstance(multi.getAdminMessageLocalisation(), initErrorMessage);
            } else if (initErrorMessage.getMessageKey().equals(MultiConf.MISSING_FILE_ERROR)) {
                return checkIni(multi, requestMap);
            } else {
                return ResponseHandlerFactory.getHtmlInstance(multi.getAdminMessageLocalisation(), initErrorMessage);
            }
        } else {
            return null;
        }
    }

    public static ResponseHandler getSphereIndex(Multi multi, CentralUser centralUser, OutputInfo outputInfo, RequestMap requestMap) {
        switch (outputInfo.getType()) {
            case OutputInfo.JSON_TYPE: {
                String output = outputInfo.getOutput();
                if (output == null) {
                    output = "";
                }
                JsonProducer jsonProducer = MultiJsonProducerFactory.getJsonProducer(multi, output, requestMap, centralUser);
                return JsonResponseHandler.build(jsonProducer, requestMap);
            }
            default: {
                return HtmlResponseHandler.init(new IndexHtmlProducer(multi, centralUser));
            }
        }
    }

    public static ResponseHandler getCentralLogin(Multi multi, String sphereName, OutputInfo outputInfo, RequestMap requestMap, CommandMessage commandMessage) {
        LangPreference langPreference = getLangPreference(multi, requestMap);
        switch (outputInfo.getType()) {
            case OutputInfo.JSON_TYPE: {
                MultiJsonProducer jsonProducer = MultiJsonProducer.init(false, multi.getMessageLocalisationProvider().getMessageLocalisation(langPreference))
                        .setCommandMessage(commandMessage);
                return JsonResponseHandler.build(jsonProducer, requestMap);
            }
            default: {
                return HtmlResponseHandler.init(new CentralLoginHtmlProducer(multi, sphereName, langPreference));
            }
        }
    }

    public static ResponseHandler getNoAuthentificationApp(Multi multi, AppConf appConf) {
        return HtmlResponseHandler.init(new AppHtmlProducer(multi, appConf));
    }

    public static ResponseHandler getApp(Multi multi, AppConf appConf, CentralUser centralUser) {
        return HtmlResponseHandler.init(new AppHtmlProducer(multi, appConf, centralUser));
    }

    public static ResponseHandler getResource(Multi multi, String path) {
        RelativePath relativePath;
        try {
            relativePath = RelativePath.parse(path);
        } catch (ParseException pe) {
            return null;
        }
        DocStream docStream = multi.getWebappsResourceStorages().getResourceDocStream(relativePath);
        if (docStream == null) {
            return null;
        }
        return DocStreamResponseHandler.init(docStream);
    }

    public static ResponseHandler doAuthentificationCheckedAction(Multi multi, String action, short authentificationCheck, RequestMap requestMap, OutputInfo outputInfo) {
        switch (outputInfo.getType()) {
            case OutputInfo.JSON_TYPE: {
                String output = outputInfo.getOutput();
                if (output == null) {
                    output = MultiConstants.PING_JSON;
                }
                MultiJsonProducer jsonProducer = null;
                switch (authentificationCheck) {
                    case MultiConf.AUTHREQUIRED_STATE:
                        jsonProducer = MultiJsonProducerFactory.unauthentified(multi);
                        break;
                    case MultiConf.AUTHFAILED_STATE:
                        jsonProducer = MultiJsonProducerFactory.unauthentified(multi).setCommandMessage(LogUtils.error("_ warning.multi.authentification_failed"));
                        break;
                    case MultiConf.CONNECTED_STATE:
                        CommandMessage commandMessage = MultiCommands.run(multi, requestMap);
                        jsonProducer = MultiJsonProducerFactory.getJsonProducer(multi, output, requestMap, commandMessage);
                        break;
                    default:
                        throw new SwitchException("Unknown check: " + authentificationCheck);
                }
                return JsonResponseHandler.build(jsonProducer, requestMap);
            }
            case OutputInfo.STREAM_TYPE: {
                String output = outputInfo.getOutput();
                switch (output) {
                    case MultiConstants.SYNTHESIS_STREAM:
                        if (multi.isPersonManagementAllowed()) {
                            return StreamResponseHandler.init(new SynthesisOdsProducer(multi, MultiUtils.getSynthesis(multi)));
                        } else {
                            return ResponseHandlerFactory.getHtmlErrorInstance(multi.getAdminMessageLocalisation(), "_ error.unsupported.personmanagementnotallowed");
                        }
                    default:
                        return ResponseHandlerFactory.getHtmlErrorInstance(multi.getAdminMessageLocalisation(), "_ error.unknown.parametervalue", RequestConstants.STREAM_PARAMETER, output);
                }
            }
            default: {
                HtmlProducer htmlProducer = null;
                if (authentificationCheck == MultiConf.CONNECTED_STATE) {
                    CommandMessage commandMessage = MultiCommands.run(multi, requestMap);
                    if (commandMessage != null) {
                        htmlProducer = new MultiMessageHtmlProducer(multi, commandMessage);
                    }
                }
                if (htmlProducer == null) {
                    try {
                        switch (action) {
                            case "admin":
                                htmlProducer = new AdminHtmlProducer(multi);
                                break;
                            case "sphere":
                                CentralSphere centralSphere = MultiUtils.getCentralSphere(multi, requestMap);
                                htmlProducer = new CentralSphereHtmlProducer(multi, centralSphere);
                                break;
                            default:
                                throw new SwitchException("Unknown action: " + action);
                        }

                    } catch (ErrorMessageException eme) {
                        htmlProducer = new MultiMessageHtmlProducer(multi, eme.getErrorMessage());
                    }
                }
                return HtmlResponseHandler.init(htmlProducer);
            }
        }
    }

    public static ResponseHandler doSubscribe(SubscribeParameters subscribeParameters, OutputInfo outputInfo) {
        if (!subscribeParameters.subscribeManager().isActive()) {
            throw new NotFoundException();
        }
        return SubscribeEngine.run(subscribeParameters, outputInfo);
    }

    public static ResponseHandler doRun(Multi multi, RequestMap requestMap) {
        String fileName = requestMap.getParameter("file");
        if (fileName == null) {
            return ResponseHandlerFactory.getTextErrorInstance(multi.getAdminMessageLocalisation(), "_ error.empty.mandatoryparameter", "file");
        }
        try {
            RelativePath relativePath = RelativePath.parse(fileName);
            CommandMessage commandMessage = MultiCommands.runFromFile(multi, relativePath);
            return ResponseHandlerFactory.getTextInstance(multi.getAdminMessageLocalisation(), commandMessage);
        } catch (ParseException pe) {
            return ResponseHandlerFactory.getTextErrorInstance(multi.getAdminMessageLocalisation(), "_ error.wrong.parametervalue", "file", fileName);
        }
    }

    public static LangPreference getLangPreference(Multi multi, RequestMap requestMap) {
        return RequestUtils.checkLangPreference(requestMap, new LangPreferenceBuilder())
                .addLangs(multi.getMultiMetadata().getWorkingLangs())
                .addLang(Lang.build("fr"))
                .toLangPreference();
    }

    private static ResponseHandler checkIni(Multi multi, RequestMap requestMap) {
        String cmd = requestMap.getParameter(RequestConstants.COMMAND_PARAMETER);
        IniCommand.Result result = null;
        if ((cmd != null) && (cmd.equals(IniCommand.COMMAND_NAME))) {
            IniCommand iniCommand = new IniCommand(requestMap, multi);
            result = iniCommand.doIniCommand();
        }
        MultiHtmlProducer htmlProducer;
        if ((result != null) && (!result.hasError())) {
            htmlProducer = new IniResultHtmlProducer(multi, result);
        } else {
            htmlProducer = new IniFormHtmlProducer(multi, requestMap);
        }
        if (result != null) {
            htmlProducer.setCommandMessage(result.getCommandMessage());
        }
        return HtmlResponseHandler.init(htmlProducer);
    }

}
