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

import fr.exemole.bdfserver.api.BdfServer;
import fr.exemole.bdfserver.api.BdfServerEditor;
import fr.exemole.bdfserver.api.configuration.LangConfiguration;
import fr.exemole.bdfserver.api.groups.GroupDef;
import fr.exemole.bdfserver.api.policies.UserAllow;
import fr.exemole.bdfserver.api.roles.Permission;
import fr.exemole.bdfserver.api.roles.Role;
import fr.exemole.bdfserver.api.roles.RoleEditor;
import fr.exemole.bdfserver.api.subsettree.SubsetTree;
import fr.exemole.bdfserver.api.ui.UiComponent;
import fr.exemole.bdfserver.api.ui.UiComponents;
import fr.exemole.bdfserver.api.users.BdfUserPrefs;
import fr.exemole.bdfserver.api.users.BdfUserPrefsEditor;
import java.text.ParseException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.fichotheque.ExistingIdException;
import net.fichotheque.SubsetKey;
import net.fichotheque.sphere.Redacteur;
import net.mapeadores.util.attr.Attribute;
import net.mapeadores.util.attr.AttributeKey;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.text.Label;


/**
 *
 * @author Vincent Calame
 */
class BdfServerEditorImpl implements BdfServerEditor {

    private final BdfServer bdfServer;
    private final Set<Object> changedObjectSet = new HashSet<Object>();
    private final Set<String> removedGroupDefSet = new HashSet<String>();
    private final Set<SubsetKey> subsetPolicySet = new HashSet<SubsetKey>();
    private final Set<String> permissionChangedSet = new HashSet<String>();
    private RoleEditorImpl roleEditor;

    BdfServerEditorImpl(BdfServer bdfServer) {
        this.bdfServer = bdfServer;
    }

    @Override
    public BdfServer getBdfServer() {
        return bdfServer;
    }

    @Override
    public RoleEditor getRoleEditor() {
        if (roleEditor == null) {
            roleEditor = new RoleEditorImpl();
        }
        return roleEditor;
    }

    @Override
    public BdfUserPrefsEditor getBdfUserPrefsEditor(BdfUserPrefs bdfUserPrefs) {
        BdfUserPrefsImpl impl = (BdfUserPrefsImpl) bdfUserPrefs;
        addChangedObject(impl);
        return impl.getBdfUserPrefsEditor(bdfServer);
    }

    @Override
    public boolean removeAttribute(Object attributesHolder, AttributeKey attributeKey) {
        boolean done = false;
        if (attributesHolder instanceof BdfUserPrefsImpl) {
            done = ((BdfUserPrefsImpl) attributesHolder).removeAttribute(attributeKey);
        }
        if (attributesHolder instanceof GroupDefImpl) {
            done = ((GroupDefImpl) attributesHolder).removeAttribute(attributeKey);
        }
        if (attributesHolder instanceof RoleImpl) {
            done = ((RoleImpl) attributesHolder).removeAttribute(attributeKey);
        }
        if (done) {
            addChangedObject(attributesHolder);
        }
        return done;
    }

    @Override
    public boolean putAttribute(Object attributesHolder, Attribute attribute) {
        boolean done = false;
        if (attributesHolder instanceof BdfUserPrefsImpl) {
            done = ((BdfUserPrefsImpl) attributesHolder).putAttribute(attribute);
        }
        if (attributesHolder instanceof GroupDefImpl) {
            done = ((GroupDefImpl) attributesHolder).putAttribute(attribute);
        }
        if (attributesHolder instanceof RoleImpl) {
            done = ((RoleImpl) attributesHolder).putAttribute(attribute);
        }
        if (done) {
            addChangedObject(attributesHolder);
        }
        return done;
    }

    @Override
    public boolean putLabel(Object labelHolder, Label label) {
        boolean done = false;
        if (labelHolder instanceof GroupDefImpl) {
            done = ((GroupDefImpl) labelHolder).putLabel(label);
        }
        if (labelHolder instanceof RoleImpl) {
            done = ((RoleImpl) labelHolder).putLabel(label);
        }
        if (done) {
            addChangedObject(labelHolder);
        }
        return done;
    }

    @Override
    public boolean removeLabel(Object labelHolder, Lang langInteger) {
        boolean done = false;
        if (labelHolder instanceof GroupDefImpl) {
            done = ((GroupDefImpl) labelHolder).removeLabel(langInteger);
        }
        if (labelHolder instanceof RoleImpl) {
            done = ((RoleImpl) labelHolder).removeLabel(langInteger);
        }
        if (done) {
            addChangedObject(labelHolder);
        }
        return done;
    }


    void saveChanges() {
        PermissionManagerImpl permissionManager = (PermissionManagerImpl) bdfServer.getPermissionManager();
        TreeManagerImpl treeManager = (TreeManagerImpl) bdfServer.getTreeManager();
        GroupManagerImpl groupManager = (GroupManagerImpl) bdfServer.getGroupManager();
        UiManagerImpl uiManager = (UiManagerImpl) bdfServer.getUiManager();
        for (Object obj : changedObjectSet) {
            if (obj instanceof BdfUserPrefsImpl) {
                BdfUserPrefsImpl bdfUserPrefs = (BdfUserPrefsImpl) obj;
                bdfServer.getBdfUserStorage().saveBdfUserPrefs(bdfUserPrefs.getRedacteur(), bdfUserPrefs);
            } else if (obj instanceof GroupDefImpl) {
                groupManager.saveGroupDef((GroupDefImpl) obj);
            } else if (obj instanceof Short) {
                treeManager.saveSubsetTree((Short) obj);
            } else if (obj instanceof LangConfigurationImpl) {
                ((LangConfigurationImpl) obj).save();
            } else if (obj instanceof UserAllowImpl) {
                ((UserAllowImpl) obj).save();
            } else if (obj instanceof RoleImpl) {
                permissionManager.saveRole((RoleImpl) obj);
            } else if (obj instanceof UiComponentsImpl) {
                uiManager.saveUiComponents((UiComponentsImpl) obj);
            } else if (obj instanceof ExtensionManagerImpl) {
                ((ExtensionManagerImpl) obj).save();
            }
        }
        if (!removedGroupDefSet.isEmpty()) {
            for (String name : removedGroupDefSet) {
                groupManager.removeGroupDef(name);
            }
        }
        if (!subsetPolicySet.isEmpty()) {
            PolicyManagerImpl policyManagerImpl = (PolicyManagerImpl) bdfServer.getPolicyManager();
            for (SubsetKey subsetKey : subsetPolicySet) {
                policyManagerImpl.saveSubsetPolicy(subsetKey);
            }
        }
        if (!permissionChangedSet.isEmpty()) {
            for (String name : permissionChangedSet) {
                permissionManager.saveRedacteurList(name);
            }
        }
        if (roleEditor != null) {
            for (String roleName : roleEditor.removedRoleSet) {
                permissionManager.removeRole(roleName);
            }
        }
    }

    @Override
    public void removeGroupDef(GroupDef groupDef) {
        GroupManagerImpl groupManager = (GroupManagerImpl) bdfServer.getGroupManager();
        if (groupManager.removeGroupDef(groupDef)) {
            removedGroupDefSet.add(groupDef.getName());
        }
    }

    @Override
    public GroupDef createGroupDef(String name) {
        GroupManagerImpl groupManager = (GroupManagerImpl) bdfServer.getGroupManager();
        GroupDefImpl groupeDef = groupManager.createGroupDef(name);
        addChangedObject(groupeDef);
        return groupeDef;
    }

    @Override
    public void setSubsetTree(short subsetCategory, SubsetTree subsetTree) {
        TreeManagerImpl treeManagerImpl = (TreeManagerImpl) bdfServer.getTreeManager();
        treeManagerImpl.updateSubsetTree(subsetCategory, subsetTree);
        addChangedObject(subsetCategory);
    }

    @Override
    public void setLangConfiguration(LangConfiguration langConfiguration) {
        LangConfigurationImpl langConfigurationImpl = (LangConfigurationImpl) bdfServer.getLangConfiguration();
        langConfigurationImpl.update(langConfiguration);
        bdfServer.getTransformationManager().update();
        addChangedObject(langConfigurationImpl);
    }

    @Override
    public void setActiveExtensionList(List<String> activeExtensionList) {
        ExtensionManagerImpl extensionManagerImpl = (ExtensionManagerImpl) bdfServer.getExtensionManager();
        extensionManagerImpl.update(activeExtensionList);
        addChangedObject(extensionManagerImpl);
    }

    @Override
    public void setSubsetPolicy(SubsetKey subsetKey, Object policyObject) {
        PolicyManagerImpl policyManagerImpl = (PolicyManagerImpl) bdfServer.getPolicyManager();
        policyManagerImpl.setSubsetPolicy(subsetKey, policyObject);
        subsetPolicySet.add(subsetKey);
    }

    @Override
    public boolean setUserAllow(UserAllow userAllow) {
        UserAllowImpl userAllowImpl = (UserAllowImpl) bdfServer.getPolicyManager().getUserAllow();
        boolean done = userAllowImpl.update(userAllow);
        if (done) {
            addChangedObject(userAllowImpl);
        }
        return done;
    }

    @Override
    public boolean setAdmin(String redacteurGlobalId, boolean isAdmin) {
        PermissionManagerImpl permissionManagerImpl = (PermissionManagerImpl) bdfServer.getPermissionManager();
        boolean done = permissionManagerImpl.setAdmin(redacteurGlobalId, isAdmin);
        if (done) {
            permissionChangedSet.add("admin");
        }
        return done;
    }

    @Override
    public boolean link(Redacteur redacteur, Role role) {
        PermissionManagerImpl permissionManagerImpl = (PermissionManagerImpl) bdfServer.getPermissionManager();
        boolean done = permissionManagerImpl.link(redacteur, role);
        if (done) {
            permissionChangedSet.add("role_" + role.getName());
        }
        return done;
    }

    @Override
    public boolean unlink(String redacteurGlobalId, Role role) {
        PermissionManagerImpl permissionManagerImpl = (PermissionManagerImpl) bdfServer.getPermissionManager();
        boolean done = permissionManagerImpl.unlink(redacteurGlobalId, role);
        if (done) {
            permissionChangedSet.add("role_" + role.getName());
        }
        return done;
    }

    @Override
    public boolean removeComponentUi(UiComponents uiComponents, String name) {
        UiComponentsImpl uiComponentsImpl = (UiComponentsImpl) uiComponents;
        boolean done = uiComponentsImpl.removeComponentUi(name, false);
        if (done) {
            addChangedObject(uiComponentsImpl);
        }
        return done;
    }

    @Override
    public boolean putComponentUi(UiComponents uiComponents, UiComponent componentUi) {
        UiComponentsImpl uiComponentsImpl = (UiComponentsImpl) uiComponents;
        boolean done = uiComponentsImpl.putComponentUi(componentUi);
        if (done) {
            addChangedObject(uiComponentsImpl);
        }
        return done;
    }

    @Override
    public boolean setPositionArray(UiComponents uiComponents, String[] nameArray) {
        UiComponentsImpl uiComponentsImpl = (UiComponentsImpl) uiComponents;
        boolean done = uiComponentsImpl.setPositionArray(nameArray);
        if (done) {
            addChangedObject(uiComponentsImpl);
        }
        return done;
    }

    void addChangedObject(Object obj) {
        changedObjectSet.add(obj);
    }


    private class RoleEditorImpl implements RoleEditor {

        private final Set<String> removedRoleSet = new HashSet<String>();

        private RoleEditorImpl() {
        }

        @Override
        public Role createRole(String name) throws ParseException, ExistingIdException {
            PermissionManagerImpl permissionManagerImpl = (PermissionManagerImpl) bdfServer.getPermissionManager();
            RoleImpl role = permissionManagerImpl.createRole(name);
            addChangedObject(role);
            return role;
        }

        @Override
        public void removeRole(Role role) {
            PermissionManagerImpl permissionManagerImpl = (PermissionManagerImpl) bdfServer.getPermissionManager();
            String roleName = role.getName();
            if (permissionManagerImpl.prepareRoleToRemove(roleName)) {
                removedRoleSet.add(roleName);
            }
        }

        @Override
        public void putSubsetPermission(Role role, SubsetKey subsetKey, Permission permission) {
            ((RoleImpl) role).putSubsetPermission(subsetKey, permission);
            addChangedObject(role);
        }

        @Override
        public void removeSubsetPermission(Role role, SubsetKey subsetKey) {
            ((RoleImpl) role).removeSubsetPermission(subsetKey);
            addChangedObject(role);
        }

    }

}
