/* FichothequeLib_Tools - Copyright (c) 2011-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 net.fichotheque.tools.parsers.junction;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import net.fichotheque.ExistingIdException;
import net.fichotheque.FichothequeEditor;
import net.fichotheque.SubsetItem;
import net.fichotheque.SubsetKey;
import net.fichotheque.album.Album;
import net.fichotheque.album.AlbumConstants;
import net.fichotheque.album.AlbumEditor;
import net.fichotheque.album.Illustration;
import net.fichotheque.include.IncludeKey;
import net.fichotheque.tools.junction.JunctionChangeEngine;
import net.fichotheque.tools.junction.TieBuffer;
import net.fichotheque.utils.AlbumUtils;
import net.mapeadores.util.exceptions.NestedIOException;
import net.mapeadores.util.exceptions.ShouldNotOccurException;
import net.mapeadores.util.logging.ErrorMessageException;
import net.mapeadores.util.request.FileValue;
import net.mapeadores.util.text.FileName;
import net.mapeadores.util.text.StringUtils;
import net.fichotheque.junction.JunctionEditor;


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

    private final SubsetItem mainSubsetItem;
    private final List<IllustrationRemoveToken> illustrationRemoveTokenList = new ArrayList<IllustrationRemoveToken>();
    private final List<IllustrationMultipartToken> multipartTokenList = new ArrayList<IllustrationMultipartToken>();
    private final List<TmpFileToken> tmpFileTokenList = new ArrayList<TmpFileToken>();
    private final Set<Illustration> removeSet = new HashSet<Illustration>();
    private final List<UpdateToken> updateTokenList = new ArrayList<UpdateToken>();
    private final File tmpDirectory;

    public IllustrationTokenParser(SubsetItem mainSubsetItem, File tmpDirectory) {
        this.mainSubsetItem = mainSubsetItem;
        this.tmpDirectory = tmpDirectory;
    }

    public void addFromMultipart(TokenKey subtokenParameter, FileValue[] fileValues) {
        IncludeKey includeKey = subtokenParameter.getIncludeKey();
        SubsetKey albumKey = includeKey.getSubsetKey();
        if (!albumKey.isAlbumSubset()) {
            throw new IllegalArgumentException("not an album Parameter: " + subtokenParameter.getParamName());
        }
        Album album = (Album) mainSubsetItem.getFichotheque().getSubset(albumKey);
        if (album == null) {
            return;
        }
        String mode = includeKey.getMode();
        int weight = includeKey.getWeightFilter();
        for (FileValue fileValue : fileValues) {
            if (fileValue.length() < 1) {
                fileValue.free();
                continue;
            }
            FileName fileName;
            String extension = null;
            try {
                fileName = FileName.parse(fileValue.getName(), "octetstream");
                extension = AlbumUtils.checkExtension(fileName.toString());
                if (extension == null) {
                    fileName = null;
                }
            } catch (ParseException pe) {
                fileName = null;
            }
            if (fileName == null) {
                fileValue.free();
                continue;
            }
            multipartTokenList.add(new IllustrationMultipartToken(album, extension, mode, weight, fileValue));
        }
    }

    public void parse(TokenKey tokenKey, String[] parameterValues) {
        IncludeKey includeKey = tokenKey.getIncludeKey();
        SubsetKey albumKey = includeKey.getSubsetKey();
        if (!albumKey.isAlbumSubset()) {
            throw new IllegalArgumentException("not an album Parameter: " + tokenKey.getParamName());
        }
        Album album = (Album) mainSubsetItem.getFichotheque().getSubset(albumKey);
        if (album == null) {
            return;
        }
        String[] values = tokenize(parameterValues);
        if (values.length == 0) {
            return;
        }
        String subname = tokenKey.getSubname();
        if (subname.equals("create")) {
            int weightFilter = includeKey.getWeightFilter();
            String mode = includeKey.getMode();
            for (String value : values) {
                TmpFileToken tmpFileToken = new TmpFileToken(value, album, mode, weightFilter);
                tmpFileTokenList.add(tmpFileToken);
            }
        } else if (subname.equals("remove")) {
            for (String value : values) {
                IllustrationRemoveToken illustrationRemoveToken = IllustrationRemoveToken.parse(value, album, includeKey);
                if (illustrationRemoveToken != null) {
                    illustrationRemoveTokenList.add(illustrationRemoveToken);
                    removeSet.add(illustrationRemoveToken.getIllustration());
                }
            }
        } else if (subname.equals("update")) {
            for (String value : values) {
                int sepIndex = value.indexOf('=');
                if (sepIndex == -1) {
                    continue;
                }
                try {
                    int illustrationid = Integer.parseInt(value.substring(0, sepIndex));
                    Illustration illustration = album.getIllustrationById(illustrationid);
                    if (illustration != null) {
                        String tmpFileName = value.substring(sepIndex + 1);
                        updateTokenList.add(new UpdateToken(illustration, tmpFileName));
                    }
                } catch (NumberFormatException nfe) {
                }
            }
        } else {
            throw new IllegalArgumentException("Unknown action: '" + subname + "', not an album Parameter: " + tokenKey.getParamName());
        }
    }

    private static String[] tokenize(String[] values) {
        Set<String> tokenSet = new LinkedHashSet<String>();
        int length = values.length;
        for (int i = 0; i < length; i++) {
            String[] tokens = StringUtils.getTechnicalTokens(values[i], false);
            int tokenCount = tokens.length;
            for (int j = 0; j < tokenCount; j++) {
                tokenSet.add(tokens[j]);
            }
        }
        return tokenSet.toArray(new String[tokenSet.size()]);
    }

    public void save(FichothequeEditor fichothequeEditor) {
        JunctionEditor junctionEditor = fichothequeEditor.getJunctionEditor();
        for (UpdateToken updateToken : updateTokenList) {
            updateToken.updateIllustration(fichothequeEditor);
        }
        if ((!tmpFileTokenList.isEmpty()) || (!multipartTokenList.isEmpty()) || (!illustrationRemoveTokenList.isEmpty())) {
            JunctionChangeEngine junctionChangeEngine = JunctionChangeEngine.appendOrWeightReplaceEngine(mainSubsetItem);
            for (IllustrationRemoveToken illustrationRemoveToken : illustrationRemoveTokenList) {
                junctionChangeEngine.removeTie(illustrationRemoveToken.getIllustration(), illustrationRemoveToken.getMode());
            }
            for (IllustrationMultipartToken illustrationMultipartToken : multipartTokenList) {
                TieBuffer tieBuffer = illustrationMultipartToken.createIllustration(fichothequeEditor);
                if (tieBuffer != null) {
                    junctionChangeEngine.addTie(tieBuffer);
                }
            }
            for (TmpFileToken tmpFileToken : tmpFileTokenList) {
                TieBuffer tieBuffer = tmpFileToken.createIllustration(fichothequeEditor);
                if (tieBuffer != null) {
                    junctionChangeEngine.addTie(tieBuffer);
                }
            }
            junctionEditor.updateJunctions(mainSubsetItem, junctionChangeEngine.toJunctionChanges());
        }
        for (Illustration illustration : removeSet) {
            fichothequeEditor.getAlbumEditor(illustration.getSubsetKey()).removeIllustration(illustration);
        }

    }


    private class UpdateToken {

        private final Illustration illustration;
        private final String tmpFileName;

        private UpdateToken(Illustration illustration, String tmpFileName) {
            this.illustration = illustration;
            this.tmpFileName = tmpFileName;
        }

        private void updateIllustration(FichothequeEditor fichothequeEditor) {
            AlbumEditor albumEditor = fichothequeEditor.getAlbumEditor(illustration.getSubsetKey());
            int idx = tmpFileName.lastIndexOf(".");
            String extension = tmpFileName.substring(idx + 1);
            File f = new File(tmpDirectory, tmpFileName);
            if (!f.exists()) {
                return;
            }
            String formatType = AlbumConstants.checkFormatType(extension);
            try (InputStream is = new FileInputStream(f)) {
                albumEditor.updateIllustration(illustration, is, formatType);
            } catch (IOException ioe) {
                throw new NestedIOException(ioe);
            } catch (ErrorMessageException eme) {

            }
        }

    }


    private class TmpFileToken {

        private final int weight;
        private final String mode;
        private final String tmpFileName;
        private final Album album;

        private TmpFileToken(String tmpFileName, Album album, String mode, int weight) {
            if (weight > 1) {
                this.weight = weight;
            } else {
                this.weight = 1;
            }
            this.mode = mode;
            this.album = album;
            this.tmpFileName = tmpFileName;
        }

        private TieBuffer createIllustration(FichothequeEditor fichothequeEditor) {
            AlbumEditor albumEditor = fichothequeEditor.getAlbumEditor(album);
            if (albumEditor == null) {
                return null;
            }
            int idx = tmpFileName.lastIndexOf(".");
            String extension = tmpFileName.substring(idx + 1);
            File f = new File(tmpDirectory, tmpFileName);
            if (!f.exists()) {
                return null;
            }
            String formatType = AlbumConstants.checkFormatType(extension);
            Illustration illustration;
            try {
                illustration = albumEditor.createIllustration(-1, formatType);
            } catch (ExistingIdException eie) {
                throw new ShouldNotOccurException(eie);
            }
            try (InputStream is = new FileInputStream(f)) {
                albumEditor.updateIllustration(illustration, is, formatType);
            } catch (IOException ioe) {
                throw new NestedIOException(ioe);
            } catch (ErrorMessageException eme) {

            }
            return new TieBuffer(illustration, mode, weight);
        }

    }

}
