/* BdfServer - Copyright (c) 2014-2017 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.groups.GroupDef;
import fr.exemole.bdfserver.api.managers.GroupManager;
import fr.exemole.bdfserver.api.storage.GroupStorage;
import java.util.AbstractList;
import java.util.Collections;
import java.util.List;
import java.util.RandomAccess;
import java.util.SortedMap;
import java.util.TreeMap;
import net.mapeadores.util.text.StringUtils;


/**
 *
 * @author Vincent Calame
 */
class GroupManagerImpl implements GroupManager {

    private final static List<GroupDef> EMPTY_LIST = Collections.emptyList();
    private final GroupStorage groupStorage;
    private final SortedMap<String, GroupDefImpl> groupDefImplMap = new TreeMap<String, GroupDefImpl>();
    private List<GroupDef> groupDefList = EMPTY_LIST;

    private GroupManagerImpl(GroupStorage groupStorage) {
        this.groupStorage = groupStorage;
    }

    static GroupManagerImpl build(GroupStorage groupStorage, List<GroupDef> groupDefList) {
        GroupManagerImpl impl = new GroupManagerImpl(groupStorage);
        impl.init(groupDefList);
        return impl;
    }

    private void init(List<GroupDef> groupDefList) {
        for (GroupDef groupDef : groupDefList) {
            String name = groupDef.getName();
            if (groupDefImplMap.containsKey(name)) {
                continue;
            }
            GroupDefImpl impl = new GroupDefImpl(name);
            impl.init(groupDef);
            groupDefImplMap.put(name, impl);
        }
        updateList();
    }

    @Override
    public List<GroupDef> getGroupDefList() {
        return groupDefList;
    }

    @Override
    public GroupDef getGroupDef(String name) {
        return groupDefImplMap.get(name);
    }

    boolean removeGroupDef(GroupDef groupDef) {
        GroupDefImpl old = groupDefImplMap.remove(groupDef.getName());
        if (old != null) {
            updateList();
            return true;
        } else {
            return false;
        }
    }

    GroupDefImpl createGroupDef(String name) {
        if (!StringUtils.isTechnicalName(name, true)) {
            throw new IllegalArgumentException("Not a technical name: " + name);
        }
        if (groupDefImplMap.containsKey(name)) {
            return groupDefImplMap.get(name);
        }
        GroupDefImpl impl = new GroupDefImpl(name);
        groupDefImplMap.put(name, impl);
        updateList();
        return impl;
    }

    void saveGroupDef(GroupDefImpl groupDefImpl) {
        groupStorage.saveGroupDef(groupDefImpl);
    }

    void removeGroupDef(String name) {
        groupStorage.removeGroupDef(name);
    }

    private void updateList() {
        this.groupDefList = new GroupDefList(groupDefImplMap.values().toArray(new GroupDef[groupDefImplMap.size()]));
    }


    private static class GroupDefList extends AbstractList<GroupDef> implements RandomAccess {

        private final GroupDef[] array;

        private GroupDefList(GroupDef[] array) {
            this.array = array;
        }

        @Override
        public int size() {
            return array.length;
        }

        @Override
        public GroupDef get(int index) {
            return array[index];
        }

    }

}
