/* BdfServer_DirectoryStorage - Copyright (c) 2006-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.storage.directory.bdfdata;

import fr.exemole.bdfserver.api.storage.BdfStorageException;
import fr.exemole.bdfserver.storage.directory.StorageDirectory;
import fr.exemole.bdfserver.tools.BdfServerUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import net.fichotheque.SubsetKey;
import net.fichotheque.addenda.VersionInfo;
import net.fichotheque.utils.AddendaUtils;
import net.mapeadores.util.io.FileUtils;
import net.mapeadores.util.io.IOUtils;
import net.mapeadores.util.text.StringUtils;


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

    private final int id;
    private final File dir;

    private DocumentDirectory(File dir, int id) {
        this.dir = dir;
        this.id = id;
    }

    public InputStream getInputStream(String extension) {
        File f = getFile(extension);
        if (!f.exists()) {
            return null;
        }
        try {
            return new FileInputStream(f);
        } catch (IOException ioe) {
            throw new BdfStorageException("file : " + f.getAbsolutePath(), ioe);
        }
    }

    public boolean linkTo(String extension, Path destination, boolean symbolicLink) throws IOException {
        File f = getFile(extension);
        if (!f.exists()) {
            return false;
        }
        Path source = f.toPath();
        if (symbolicLink) {
            Files.createSymbolicLink(destination, source);
        } else {
            Files.createLink(destination, source);
        }
        return true;
    }

    public VersionInfo saveInputStream(String extension, InputStream inputStream) {
        if (!AddendaUtils.testExtension(extension)) {
            throw new IllegalArgumentException("wrong extension value = " + extension);
        }
        File f = getFile(extension);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        try (OutputStream os = new FileOutputStream(f)) {
            IOUtils.copy(inputStream, os);
        } catch (IOException ioe) {
            throw new BdfStorageException("file : " + f.getAbsolutePath(), ioe);
        }
        try {
            return new VersionInfo(extension, f.length(), StringUtils.getMD5Checksum(f));
        } catch (IOException ioe) {
            throw new BdfStorageException("file : " + f.getAbsolutePath(), ioe);
        }
    }

    public boolean delete() {
        try {
            if (dir.exists()) {
                FileUtils.forceDelete(dir);
                return true;
            } else {
                return false;
            }
        } catch (IOException ioe) {
            throw new BdfStorageException(ioe);
        }
    }

    public boolean delete(String extension) {
        File f = getFile(extension);
        if (!f.exists()) {
            return false;
        }
        return f.delete();
    }

    public static DocumentDirectory getDocumentDirectory(StorageDirectory bdfdataDirectory, SubsetKey subsetKey, int id) {
        File docDir = bdfdataDirectory.getDataFile(getPath(subsetKey, id));
        DocumentDirectory documentDirectory = new DocumentDirectory(docDir, id);
        return documentDirectory;
    }

    public DocumentInfo getDocumentInfo() {
        List<VersionInfo> versionInfoList = new ArrayList<VersionInfo>();
        String prefix = "doc.";
        int prefixLength = prefix.length();
        for (File f : dir.listFiles()) {
            if (f.isDirectory()) {
                continue;
            }
            String name = f.getName();
            if (name.length() <= prefixLength) {
                continue;
            }
            if (!name.startsWith(prefix)) {
                continue;
            }
            String extension = name.substring(prefixLength);
            if (!AddendaUtils.testExtension(extension)) {
                continue;
            }
            try {
                versionInfoList.add(new VersionInfo(extension, f.length(), StringUtils.getMD5Checksum(f)));
            } catch (IOException ioe) {
                throw new BdfStorageException("file : " + f.getAbsolutePath(), ioe);
            }
        }
        return new DocumentInfo(id, versionInfoList);
    }

    /**
     * Retourne le chemin à partir du numéro
     */
    public static String getPath(SubsetKey subsetKey, int id) {
        StringBuilder buf = new StringBuilder();
        buf.append(BdfdataConstants.FICHOTHEQUE);
        buf.append(File.separatorChar);
        buf.append(SubsetKey.CATEGORY_ADDENDA_STRING);
        buf.append(File.separatorChar);
        buf.append(subsetKey.getSubsetName());
        buf.append(File.separatorChar);
        buf.append("d.");
        buf.append(BdfServerUtils.getMillier(id));
        buf.append(File.separatorChar);
        buf.append(id);
        return buf.toString();
    }

    public static List<DocumentInfo> getDocumentInfoList(StorageDirectory bdfdataDirectory, SubsetKey addendaKey) {
        List<DocumentInfo> list = new ArrayList<DocumentInfo>();
        File documentsDirectory = bdfdataDirectory.getDataFile(BdfdataConstants.FICHOTHEQUE + File.separator + SubsetKey.CATEGORY_ADDENDA_STRING + File.separator + addendaKey.getSubsetName());
        if ((!documentsDirectory.exists()) || (!documentsDirectory.isDirectory())) {
            return list;
        }
        for (File directory : documentsDirectory.listFiles()) {
            if (!directory.isDirectory()) {
                continue;
            }
            String name = directory.getName();
            if ((name.length() < 2) || (!name.startsWith("d."))) {
                continue;
            }
            try {
                int directoryNumber = Integer.parseInt(name.substring(2));
                addDocumentInfo(list, directory, directoryNumber);
            } catch (NumberFormatException nfe) {
            }
        }
        return list;
    }

    private static void addDocumentInfo(List<DocumentInfo> list, File intervalDirectory, int directoryNumber) {
        for (File docDir : intervalDirectory.listFiles()) {
            if (!docDir.isDirectory()) {
                continue;
            }
            String name = docDir.getName();
            String errorMessage = null;
            try {
                int documentid = Integer.parseInt(name);
                if (documentid < 1) {
                    errorMessage = "documentid < 1 (directoryNumber = " + directoryNumber;
                } else if (((documentid < 1000) && (directoryNumber != 0)) || (documentid / 1000 != directoryNumber)) {
                    errorMessage = "Wrong range : documentid = " + documentid + " / directoryNumber = " + directoryNumber;
                } else {
                    list.add((new DocumentDirectory(docDir, documentid)).getDocumentInfo());
                }
            } catch (NumberFormatException nfe) {
            }
            if (errorMessage != null) {
                System.out.println(errorMessage);
            }
        }
    }

    private File getFile(String extension) {
        return new File(dir, "doc." + extension);
    }


    public static class DocumentInfo {

        private final int id;
        private final List<VersionInfo> versionInfoList;

        private DocumentInfo(int id, List<VersionInfo> versionInfoList) {
            this.id = id;
            this.versionInfoList = versionInfoList;
        }

        public int getId() {
            return id;
        }

        public List<VersionInfo> getVersionInfoList() {
            return versionInfoList;
        }

    }

}
