/* BdfServer - Copyright (c) 2013-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.BdfServerEditor;
import fr.exemole.bdfserver.api.managers.PolicyManager;
import fr.exemole.bdfserver.api.policies.UserAllow;
import fr.exemole.bdfserver.api.storage.PolicyStorage;
import fr.exemole.bdfserver.api.storage.StorageCheck;
import fr.exemole.bdfserver.tools.policies.PolicyUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.fichotheque.Fichotheque;
import net.fichotheque.SubsetKey;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.thesaurus.policies.DynamicEditPolicy;
import net.fichotheque.tools.thesaurus.DynamicEditPolicyBuilder;
import net.fichotheque.utils.ThesaurusUtils;
import net.fichotheque.thesaurus.policies.PolicyProvider;


/**
 *
 * @author Vincent Calame
 */
class PolicyManagerImpl implements PolicyManager {

    private final UserAllowImpl userAllowImpl;
    private final Fichotheque fichotheque;
    private final PolicyStorage policyStorage;
    private final InternalPolicyProvider policyProvider = new InternalPolicyProvider();

    private PolicyManagerImpl(Fichotheque fichotheque, PolicyStorage policyStorage) {
        this.fichotheque = fichotheque;
        this.userAllowImpl = new UserAllowImpl(policyStorage);
        this.policyStorage = policyStorage;

    }

    static PolicyManagerImpl build(Fichotheque fichotheque, PolicyStorage policyStorage, StorageCheck storageCheck) {
        PolicyManagerImpl policyManagerImpl = new PolicyManagerImpl(fichotheque, policyStorage);
        policyManagerImpl.userAllowImpl.update(storageCheck.getUserAllow());
        Map<SubsetKey, Object> map = storageCheck.getSubsetPolicyMap();
        for (Map.Entry<SubsetKey, Object> entry : map.entrySet()) {
            policyManagerImpl.setSubsetPolicy(entry.getKey(), entry.getValue());
        }
        return policyManagerImpl;
    }

    @Override
    public UserAllow getUserAllow() {
        return userAllowImpl;
    }

    @Override
    public PolicyProvider getPolicyProvider() {
        return policyProvider;
    }

    void setSubsetPolicy(SubsetKey subsetKey, Object policyObject) {
        if (!subsetKey.isThesaurusSubset()) {
            return;
        }
        if (policyObject == null) {
            policyProvider.remove(subsetKey);
        } else {
            if (!(policyObject instanceof DynamicEditPolicy)) {
                throw new IllegalArgumentException("policyObject is not instance of DynamicEditPolicy");
            }
            Thesaurus thesaurus = (Thesaurus) fichotheque.getSubset(subsetKey);
            if (thesaurus != null) {
                policyProvider.put(thesaurus, (DynamicEditPolicy) policyObject);
            }
        }
    }

    void saveSubsetPolicy(SubsetKey subsetKey) {
        if (!subsetKey.isThesaurusSubset()) {
            policyStorage.removeSubsetPolicy(subsetKey);
            return;
        }
        DynamicEditPolicy policy = policyProvider.getDynamicEditPolicy(subsetKey);
        if (policy == null) {
            policyStorage.removeSubsetPolicy(subsetKey);
        } else {
            policyStorage.saveSubsetPolicy(subsetKey, policy);
        }
    }

    static void subsetRemoved(BdfServerEditor bdfServerEditor, SubsetKey subsetKey) {
        bdfServerEditor.setSubsetPolicy(subsetKey, null);
        PolicyManagerImpl impl = (PolicyManagerImpl) bdfServerEditor.getBdfServer().getPolicyManager();
        Map<SubsetKey, DynamicEditPolicy> policyMap = new HashMap<SubsetKey, DynamicEditPolicy>(impl.policyProvider.policyMap);
        for (Map.Entry<SubsetKey, DynamicEditPolicy> entry : policyMap.entrySet()) {
            SubsetKey current = entry.getKey();
            DynamicEditPolicy policy = entry.getValue();
            if (policy instanceof DynamicEditPolicy.Transfer) {
                DynamicEditPolicy.Transfer transferPolicy = (DynamicEditPolicy.Transfer) policy;
                if (transferPolicy.getTransferThesaurusKey().equals(subsetKey)) {
                    bdfServerEditor.setSubsetPolicy(current, ThesaurusUtils.NONE_POLICY);
                }
            } else if (policy instanceof DynamicEditPolicy.Check) {
                DynamicEditPolicy.Check checkPolicy = (DynamicEditPolicy.Check) policy;
                List<SubsetKey> list = new ArrayList<SubsetKey>();
                for (SubsetKey currentSubsetKey : checkPolicy.getCheckSubseKeyList()) {
                    if (!currentSubsetKey.equals(subsetKey)) {
                        list.add(currentSubsetKey);
                    }
                }
                int size = list.size();
                if (size != checkPolicy.getCheckSubseKeyList().size()) {
                    if (size == 0) {
                        bdfServerEditor.setSubsetPolicy(current, ThesaurusUtils.ALLOW_POLICY);
                    } else {
                        bdfServerEditor.setSubsetPolicy(current, DynamicEditPolicyBuilder.buildCheck(list));
                    }
                }
            }
        }
    }


    private class InternalPolicyProvider implements PolicyProvider {

        private final Map<SubsetKey, DynamicEditPolicy> policyMap = new HashMap<SubsetKey, DynamicEditPolicy>();

        private InternalPolicyProvider() {
        }

        private DynamicEditPolicy getDynamicEditPolicy(SubsetKey subsetKey) {
            DynamicEditPolicy policy = policyMap.get(subsetKey);
            if (policy != null) {
                return policy;
            } else {
                return ThesaurusUtils.NONE_POLICY;
            }
        }

        @Override
        public DynamicEditPolicy getDynamicEditPolicy(Thesaurus thesaurus) {
            return getDynamicEditPolicy(thesaurus.getSubsetKey());
        }

        private boolean remove(SubsetKey subsetKey) {
            DynamicEditPolicy current = policyMap.remove(subsetKey);
            return (current != null);
        }

        private void put(Thesaurus thesaurus, DynamicEditPolicy policy) {
            if (!PolicyUtils.isValid(thesaurus, policy)) {
                return;
            }
            policyMap.put(thesaurus.getSubsetKey(), policy);
        }

    }

}
