/* BdfServer_Multi - Copyright (c) 2023-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.impl;

import fr.exemole.bdfserver.multi.api.central.CentralSphere;
import fr.exemole.bdfserver.multi.api.central.CentralSphereEditor;
import fr.exemole.bdfserver.multi.api.central.CentralUser;
import fr.exemole.bdfserver.multi.api.central.CentralUserEditor;
import fr.exemole.bdfserver.multi.tools.dom.CentralSphereMetadataDOMReader;
import fr.exemole.bdfserver.multi.tools.dom.CentralUserDOMReader;
import fr.exemole.bdfserver.storage.directory.StorageDirectory;
import fr.exemole.bdfserver.tools.storage.StorageFile;
import java.io.File;
import java.text.ParseException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import net.fichotheque.EditOrigin;
import net.fichotheque.Metadata;
import net.fichotheque.MetadataEditor;
import net.fichotheque.SubsetKey;
import net.fichotheque.sphere.LoginKey;
import net.mapeadores.util.logging.LogUtils;
import org.w3c.dom.Document;


/**
 *
 * @author Vincent Calame
 */
public class CentralSphereImpl implements CentralSphere {

    private final StorageDirectory storageDirectory;
    private final SubsetKey sphereKey;
    private final CentralSphereMetadataImpl metadata;
    private final SortedMap<String, CentralUserImpl> centralUserMap = new TreeMap<String, CentralUserImpl>();
    private final Set<String> loginSet = Collections.unmodifiableSet(centralUserMap.keySet());

    public CentralSphereImpl(StorageDirectory storageDirectory, SubsetKey sphereKey) {
        this.storageDirectory = storageDirectory;
        this.sphereKey = sphereKey;
        this.metadata = new CentralSphereMetadataImpl();
    }

    @Override
    public SubsetKey getSphereKey() {
        return sphereKey;
    }

    @Override
    public Metadata getMetadata() {
        return metadata;
    }

    @Override
    public CentralUser getCentralUser(String login) {
        return centralUserMap.get(login);
    }

    @Override
    public Set<String> getLoginSet() {
        return loginSet;
    }

    public CentralSphereEditor getCentralSphereEditor(EditOrigin editOrigin) {
        return new InternalCentralSphereEditor(this, editOrigin);
    }

    public boolean saveChanges(CentralSphereEditor centralSphereEditor) {
        InternalCentralSphereEditor internalCentralSphereEditor = (InternalCentralSphereEditor) centralSphereEditor;
        return internalCentralSphereEditor.saveChanges(storageDirectory);
    }

    public static CentralSphereImpl build(StorageDirectory storageDirectory, String name) {
        SubsetKey sphereKey;
        try {
            sphereKey = SubsetKey.parse(SubsetKey.CATEGORY_SPHERE, name);
        } catch (ParseException pe) {
            throw new IllegalArgumentException("Invalid name: " + name);
        }
        CentralSphereImpl centralSphere = new CentralSphereImpl(storageDirectory, sphereKey);
        CentralSphereEditor centralSphereEditor = centralSphere.getCentralSphereEditor(null);
        StorageFile centralSphereMetadataFile = MultiStorageFileCatalog.centralSphereMetadata(storageDirectory, name);
        if (centralSphereMetadataFile.exists()) {
            Document document = centralSphereMetadataFile.readDocument();
            CentralSphereMetadataDOMReader reader = new CentralSphereMetadataDOMReader(centralSphereEditor.getMetadataEditor(), LogUtils.NULL_MESSAGEHANDLER);
            reader.read(document.getDocumentElement());
        }
        String usersPath = "spheres" + File.separator + name + File.separator + "users";
        File usersDir = storageDirectory.getDataDir(usersPath);
        if (usersDir.exists()) {
            for (File file : usersDir.listFiles()) {
                String userFileName = file.getName();
                if (userFileName.endsWith(".xml")) {
                    String login = userFileName.substring(0, userFileName.length() - 4);
                    try {
                        LoginKey loginKey = LoginKey.parse(sphereKey, login);
                        CentralUserImpl centralUserImpl = new CentralUserImpl(loginKey);
                        centralSphere.centralUserMap.put(loginKey.getLogin(), centralUserImpl);
                        StorageFile userStorageFile = storageDirectory.getStorageFile(usersPath + File.separator + userFileName);
                        Document document = userStorageFile.readDocument();
                        CentralUserDOMReader reader = new CentralUserDOMReader(centralUserImpl.getCentalUserEditor(null), LogUtils.NULL_MESSAGEHANDLER);
                        reader.read(document.getDocumentElement());
                    } catch (ParseException pe) {

                    }
                }
            }
        }
        return centralSphere;
    }


    private static class InternalCentralSphereEditor implements CentralSphereEditor {

        private final CentralSphereImpl centralSphere;
        private final EditOrigin editOrigin;
        private final Map<String, CentralUserImpl.CentralUserEditorImpl> userEditorMap = new HashMap<String, CentralUserImpl.CentralUserEditorImpl>();
        private CentralSphereMetadataImpl.CentralSphereMetadataEditorImpl metadataEditor = null;

        private InternalCentralSphereEditor(CentralSphereImpl centralSphere, EditOrigin editOrigin) {
            this.centralSphere = centralSphere;
            this.editOrigin = editOrigin;
        }

        @Override
        public CentralUserEditor createCentralUser(String login) {
            if (centralSphere.hasCentralUser(login)) {
                throw new IllegalArgumentException("existing login: " + login);
            }
            try {
                LoginKey loginKey = LoginKey.parse(centralSphere.getSphereKey(), login);
                CentralUserImpl centralUserImpl = new CentralUserImpl(loginKey);
                centralSphere.centralUserMap.put(loginKey.getLogin(), centralUserImpl);
                return getCentralUserEditor(login);
            } catch (ParseException pe) {
                throw new IllegalArgumentException("Wrong login: " + login);
            }
        }

        @Override
        public MetadataEditor getMetadataEditor() {
            if (metadataEditor == null) {
                metadataEditor = centralSphere.metadata.getSphereMetadataEditor(editOrigin);
            }
            return metadataEditor;
        }

        @Override
        public CentralUserEditor getCentralUserEditor(String login) {
            CentralUserImpl.CentralUserEditorImpl centralUserEditor = userEditorMap.get(login);
            if (centralUserEditor != null) {
                return centralUserEditor;
            }
            CentralUserImpl centralUser = centralSphere.centralUserMap.get(login);
            if (centralUser == null) {
                return null;
            }
            centralUserEditor = centralUser.getCentalUserEditor(editOrigin);
            userEditorMap.put(login, centralUserEditor);
            return centralUserEditor;
        }

        private boolean saveChanges(StorageDirectory bdfdataDirectory) {
            boolean done = false;
            if (metadataEditor != null) {
                boolean metadataSaved = metadataEditor.saveChanges(bdfdataDirectory, centralSphere.getName());
                if (metadataSaved) {
                    done = true;
                }
            }
            for (CentralUserImpl.CentralUserEditorImpl centralUserEditor : userEditorMap.values()) {
                boolean userSaved = centralUserEditor.saveChanges(bdfdataDirectory);
                if (userSaved) {
                    done = true;
                }
            }
            return true;
        }

    }


}
