/* BdfServer_Get - Copyright (c) 2009-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.get.instructions;

import fr.exemole.bdfserver.api.BdfServer;
import fr.exemole.bdfserver.api.instruction.BdfInstruction;
import fr.exemole.bdfserver.api.instruction.BdfInstructionConstants;
import fr.exemole.bdfserver.api.instruction.BdfParameters;
import fr.exemole.bdfserver.api.users.BdfUser;
import fr.exemole.bdfserver.get.streamproducers.LexieDistributionOdsProducer;
import fr.exemole.bdfserver.get.streamproducers.LexieDistributionXmlProducer;
import fr.exemole.bdfserver.get.streamproducers.StatsThesaurusOdsProducer;
import fr.exemole.bdfserver.get.streamproducers.transformation.TransformationFactory;
import fr.exemole.bdfserver.tools.BdfServerUtils;
import fr.exemole.bdfserver.tools.instruction.DefaultBdfParameters;
import java.text.ParseException;
import java.util.function.Predicate;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.exportation.transformation.TransformationKey;
import net.fichotheque.extraction.ExtractionContext;
import net.fichotheque.permission.PermissionSummary;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.tools.misc.MotcleLexieDistributionFactory;
import net.fichotheque.utils.FichothequeUtils;
import net.mapeadores.util.io.StreamProducer;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.request.RequestMap;
import net.mapeadores.util.servlets.ResponseHandler;
import net.mapeadores.util.servlets.exceptions.ForbiddenException;
import net.mapeadores.util.servlets.handlers.StreamResponseHandler;
import net.mapeadores.util.servlets.handlers.XmlResponseHandler;
import net.mapeadores.util.text.FileName;
import net.mapeadores.util.text.lexie.LexieDistribution;
import net.mapeadores.util.text.lexie.xml.LexieDistributionXMLPart;


/**
 *
 * @author Vincent Calame
 */
public class MotclesInstruction implements BdfInstruction {

    public final static short STATS_OPTION = 1;
    public final static short STATSSEL_OPTION = 2;
    public final static short INVERSE_OPTION = 3;
    private final BdfServer bdfServer;
    private final RequestMap requestMap;
    private final String filePath;
    private Thesaurus thesaurus;
    private short outputOption = 0;
    private String baseName;
    private String extension;

    public MotclesInstruction(BdfServer bdfServer, String filePath, RequestMap requestMap) {
        this.bdfServer = bdfServer;
        this.filePath = filePath;
        this.requestMap = requestMap;
    }

    @Override
    public short getBdfUserNeed() {
        return BdfInstructionConstants.MANDATORY_BDFUSER;
    }

    @Override
    public ResponseHandler runInstruction(BdfUser bdfUser) {
        BdfParameters bdfParameters = new DefaultBdfParameters(bdfServer, bdfUser);
        PermissionSummary permissionSummary = bdfParameters.getPermissionSummary();
        FileName fileName;
        try {
            fileName = FileName.parse(filePath);
        } catch (ParseException pe) {
            return null;
        }
        baseName = fileName.getBasename();
        extension = fileName.getExtension();
        boolean optionInit = initOption(permissionSummary);
        if (!optionInit) {
            return null;
        }
        TransformationKey transformationKey = getTransformationKey(outputOption);
        if (outputOption == INVERSE_OPTION) {
            return getInverseResponseHandler(bdfParameters);
        }
        Predicate<FicheMeta> fichePredicate = getFichePredicate(bdfUser);
        ExtractionContext extractionContext = bdfParameters.getDefaultExtractionContext();
        TransformationFactory transformationFactory = TransformationFactory.init(bdfParameters)
                .extractionContext(extractionContext)
                .transformationKey(transformationKey)
                .dynamicObject(thesaurus)
                .fichePredicate(fichePredicate);
        if (extension.equals("xml")) {
            switch (outputOption) {
                case STATS_OPTION:
                case STATSSEL_OPTION:
                    return XmlResponseHandler.init(transformationFactory.getSourceXmlProducer());
                default:
                    return null;
            }
        } else if (extension.equals("html")) {
            switch (outputOption) {
                case STATS_OPTION:
                case STATSSEL_OPTION:
                    return StreamResponseHandler.init(transformationFactory.getStreamProducer());
                default:
                    return null;
            }
        } else if (extension.equals("ods")) {
            StreamProducer streamProducer;
            switch (outputOption) {
                case STATS_OPTION:
                case STATSSEL_OPTION:
                    streamProducer = new StatsThesaurusOdsProducer(null, thesaurus, permissionSummary, BdfServerUtils.checkLangDisponibility(bdfServer, thesaurus, bdfUser.getWorkingLang()), fichePredicate);
                    break;
                default:
                    return null;
            }
            return StreamResponseHandler.init(streamProducer);
        } else {
            return null;
        }
    }

    private ResponseHandler getInverseResponseHandler(BdfParameters bdfParameters) {
        TransformationKey transformationKey = TransformationKey.INVERSETHESAURUS_INSTANCE;
        Lang thesaurusLang = BdfServerUtils.checkLangDisponibility(bdfServer, thesaurus, bdfParameters.getWorkingLang());
        LexieDistribution lexieDistribution = MotcleLexieDistributionFactory.getLexieDistribution(thesaurus, thesaurusLang);
        if (extension.equals("xml")) {
            return XmlResponseHandler.init(new LexieDistributionXmlProducer(lexieDistribution));
        } else if (extension.equals("html")) {
            TransformationFactory transformationFactory = TransformationFactory.init(bdfParameters)
                    .sourceString(LexieDistributionXMLPart.toString(lexieDistribution, false, false))
                    .transformationKey(transformationKey);
            return StreamResponseHandler.init(transformationFactory.getStreamProducer());
        } else if (extension.equals("ods")) {
            return StreamResponseHandler.init(new LexieDistributionOdsProducer(null, lexieDistribution, thesaurus));
        } else {
            return null;
        }
    }

    private boolean initOption(PermissionSummary permissionSummary) {
        int idx = baseName.indexOf('-');
        String outputString = null;
        if (idx != -1) {
            outputString = baseName.substring(idx + 1);
            baseName = baseName.substring(0, idx);

        }
        thesaurus = FichothequeUtils.getThesaurus(bdfServer.getFichotheque(), baseName);
        if ((thesaurus == null) || (outputString == null)) {
            return false;
        }
        if (!permissionSummary.hasAccess(thesaurus)) {
            throw new ForbiddenException();
        }
        outputOption = toShort(outputString);
        return (outputOption != 0);
    }

    private Predicate<FicheMeta> getFichePredicate(BdfUser bdfUser) {
        switch (outputOption) {
            case STATSSEL_OPTION:
                return bdfUser.getSelectedFiches();
            default:
                return null;
        }
    }

    private static short toShort(String optionString) {
        switch (optionString) {
            case "stats":
                return STATS_OPTION;
            case "statssel":
                return STATSSEL_OPTION;
            case "inverse":
                return INVERSE_OPTION;
            default:
                return 0;
        }
    }

    private static TransformationKey getTransformationKey(short outputOption) {
        switch (outputOption) {
            case STATS_OPTION:
                return TransformationKey.STATTHESAURUS_INSTANCE;
            case STATSSEL_OPTION:
                return TransformationKey.STATTHESAURUS_INSTANCE;
            case INVERSE_OPTION:
                return TransformationKey.INVERSETHESAURUS_INSTANCE;
            default:
                return null;
        }
    }

}
