/* Copyright (C) 2013  Johannes Gutenberg-Universitaet Mainz
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
package org.kramerlab.seitan.api.impl.manager;

import org.kramerlab.seitan.api.impl.Permission;
import org.kramerlab.seitan.api.impl.database.accessors.GroupManagerAccessor;
import org.kramerlab.seitan.api.impl.exceptions.AccessDeniedException;
import org.kramerlab.seitan.api.impl.exceptions.SEITANException;
import org.kramerlab.seitan.api.impl.objects.Group;
import org.kramerlab.seitan.api.impl.objects.User;

import java.net.URI;
import java.util.HashSet;
import java.util.Set;

/**
 * The group manager provides method for group managing e.g. creating new groups
 * or getting groups.
 */
public class GroupManager extends SEITANManager {

    /**
     * The accessor to connect to the database.
     */
    private GroupManagerAccessor accessor;

    /**
     * Constructor.
     *
     * @param newCaller The caller
     */
    public GroupManager(final User newCaller) {
        super(newCaller);
        accessor = new GroupManagerAccessor();
    }

    /**
     * Gets group by name.
     *
     * @param name     name
     * @param nameonly name only?
     * @return the group
     * @throws SEITANException Something went wrong
     */
    public final Group getGroupByName(final String name, final boolean nameonly)
            throws SEITANException {
        Group g = this.accessor.getGroupByName(name);
        return this.getGroupById(g.getUri(), nameonly);
    }

    /**
     * Get group by ID.
     *
     * @param groupURI group URI
     * @param nameonly name only?
     * @return the group
     * @throws SEITANException Something went wrong
     */
    public final Group getGroupById(final URI groupURI, final boolean nameonly)
            throws SEITANException {
        Group g = this.accessor.getGroupById(groupURI);

        if (nameonly) {
            return new Group(g.getUri(), Permission.NAMEONLY);
        }

        if (caller.isAdmin() || g.isOwner(caller)) {
            return adjustPermission(g.getUri(), Permission.ALL);
        } else if (g.isWriter(caller)) {
            return adjustPermission(g.getUri(), Permission.READWRITE);
        } else if (g.isReader(caller)) {
            return g;
        } else {
            throw new AccessDeniedException(
                    "Getting group failed because of insufficient rights!");
        }

    }

    /**
     * Returns all groups.
     *
     * @return A HashSet of all groups
     * @throws SEITANException Something went wrong
     */
    public final Set<Group> getAllGroups() throws SEITANException {
        Set<Group> groups = this.accessor.getGroups();
        Set<Group> result = new HashSet<Group>();

        for (Group g : groups) {

            if (caller.isAdmin() || g.isOwner(caller)) {
                result.add(adjustPermission(g.getUri(), Permission.ALL));
            } else if (g.isWriter(caller)) {
                result.add(adjustPermission(g.getUri(), Permission.READWRITE));
            } else if (g.isReader(caller)) {
                result.add(g);
            } else {
                result.add(new Group(g.getUri(), Permission.NAMEONLY));
            }

        }

        return result;
    }

    /**
     * Adjusts permissions of a given group
     *
     * @param databaseId group uri
     * @param permission permissions
     * @return Group
     * @throws SEITANException
     */
    private Group adjustPermission(final URI databaseId,
                                   final Permission permission) throws SEITANException {
        return new Group(databaseId, permission);
    }

}
