/* BdfServer - Copyright (c) 2013-2024 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.tools.roles;

import fr.exemole.bdfserver.api.roles.FichePermission;
import fr.exemole.bdfserver.api.roles.Permission;
import fr.exemole.bdfserver.api.roles.Role;
import fr.exemole.bdfserver.api.roles.RoleDef;
import fr.exemole.bdfserver.api.roles.SphereSupervisor;
import fr.exemole.bdfserver.api.users.BdfUser;
import java.util.AbstractList;
import java.util.Collections;
import java.util.List;
import java.util.RandomAccess;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.permission.PermissionSummary;
import net.fichotheque.sphere.Redacteur;
import net.fichotheque.utils.SphereUtils;
import net.mapeadores.util.exceptions.SwitchException;


/**
 *
 * @author Vincent Calame
 */
public final class RoleUtils {

    public final static List<Role> EMPTY_ROLELIST = Collections.emptyList();
    public final static Permission NONE_PERMISSION = new DefaultPermission(Permission.NONE_LEVEL, null);
    public final static Permission STANDARD_PERMISSION = new DefaultPermission(Permission.STANDARD_LEVEL, null);
    public final static Permission ADMIN_PERMISSION = new DefaultPermission(Permission.ADMIN_LEVEL, null);
    public final static SphereSupervisor ALL_SPHERESUPERVISOR = new AllSphereSupervisor();

    private RoleUtils() {
    }

    public static boolean isDefaultRole(Role role) {
        return (role.getName().equals(Role.DEFAULT_ROLE));
    }


    public static Permission toPermission(short permissionLevel, Permission.CustomPermission customPermission) {
        switch (permissionLevel) {
            case Permission.NONE_LEVEL:
                return NONE_PERMISSION;
            case Permission.STANDARD_LEVEL:
                return STANDARD_PERMISSION;
            case Permission.CUSTOM_LEVEL:
                if (customPermission == null) {
                    throw new IllegalArgumentException("customPermission is null");
                }
                return new DefaultPermission(Permission.CUSTOM_LEVEL, customPermission);
            case Permission.ADMIN_LEVEL:
                return ADMIN_PERMISSION;
            default:
                throw new SwitchException("unknown permissionLevel: " + permissionLevel);
        }
    }

    public static FichePermission toFichePermission(boolean create, short read, short write) {
        switch (read) {
            case FichePermission.NONE:
                throw new IllegalArgumentException("read cannot be none");
            case FichePermission.OWN:
            case FichePermission.SPHERE:
            case FichePermission.ALL:
                break;
            default:
                throw new SwitchException("unknon read permissionType: " + create);
        }
        switch (write) {
            case FichePermission.NONE:
            case FichePermission.OWN:
            case FichePermission.SPHERE:
            case FichePermission.ALL:
                break;
            default:
                throw new SwitchException("unknon create permissionType: " + write);
        }
        if (write > read) {
            write = read;
        }
        if (write == FichePermission.NONE) {
            create = false;
        }
        return new DefaultFichePermission(create, read, write);
    }

    public static boolean resolveFichePermissionType(short fichePermissionType, Redacteur redacteur, FicheMeta ficheMeta) {
        switch (fichePermissionType) {
            case FichePermission.ALL:
                return true;
            case FichePermission.NONE:
                return false;
            case FichePermission.OWN:
                return ficheMeta.belongsTo(redacteur.getGlobalId());
            case FichePermission.SPHERE:
                return SphereUtils.ownsToSphere(ficheMeta, redacteur.getSphere());
            default:
                throw new SwitchException("corpusPermissionType = " + fichePermissionType);
        }
    }

    public static boolean resolveReadPermission(Permission permission, Redacteur redacteur, FicheMeta ficheMeta) {
        switch (permission.getLevel()) {
            case Permission.ADMIN_LEVEL:
            case Permission.STANDARD_LEVEL:
                return true;
            case Permission.CUSTOM_LEVEL:
                return resolveFichePermissionType(((FichePermission) permission.getCustomPermission()).read(), redacteur, ficheMeta);
            default:
                return false;
        }
    }

    public static boolean resolveWritePermission(Permission permission, Redacteur redacteur, FicheMeta ficheMeta) {
        switch (permission.getLevel()) {
            case Permission.ADMIN_LEVEL:
            case Permission.STANDARD_LEVEL:
                return resolveFichePermissionType(FichePermission.OWN, redacteur, ficheMeta);
            case Permission.CUSTOM_LEVEL:
                return resolveFichePermissionType(((FichePermission) permission.getCustomPermission()).write(), redacteur, ficheMeta);
            default:
                return false;
        }
    }

    public static boolean matchStandardPermission(FichePermission fichePermission) {
        return ((fichePermission.create()) && (fichePermission.read() == FichePermission.ALL) && (fichePermission.write() == FichePermission.OWN));
    }

    public static String levelToString(short level) {
        switch (level) {
            case Permission.NONE_LEVEL:
                return "none";
            case Permission.STANDARD_LEVEL:
                return "standard";
            case Permission.CUSTOM_LEVEL:
                return "custom";
            case Permission.ADMIN_LEVEL:
                return "admin";
            default:
                throw new IllegalArgumentException("type = " + level);
        }
    }

    public static short levelToShort(String level) {
        switch (level) {
            case "none":
                return Permission.NONE_LEVEL;
            case "standard":
                return Permission.STANDARD_LEVEL;
            case "custom":
                return Permission.CUSTOM_LEVEL;
            case "admin":
                return Permission.ADMIN_LEVEL;
            default:
                throw new IllegalArgumentException("type = " + level);
        }
    }

    public static String fichePermissionTypeToString(short type) {
        switch (type) {
            case FichePermission.ALL:
                return "all";
            case FichePermission.NONE:
                return "none";
            case FichePermission.OWN:
                return "own";
            case FichePermission.SPHERE:
                return "sphere";
            default:
                throw new IllegalArgumentException("type = " + type);
        }
    }

    public static short fichePermissionTypeToShort(String type) {
        if (type.equals("all")) {
            return FichePermission.ALL;
        } else if (type.equals("none")) {
            return FichePermission.NONE;
        } else if (type.equals("own")) {
            return FichePermission.OWN;
        } else if (type.equals("sphere")) {
            return FichePermission.SPHERE;
        } else {
            throw new IllegalArgumentException("type = " + type);
        }
    }

    public static String permissionSummaryLevelToString(int level) {
        switch (level) {
            case PermissionSummary.SUMMARYLEVEL_0_NONE:
                return "none";
            case PermissionSummary.SUMMARYLEVEL_1_FICHE_OWN:
                return "own";
            case PermissionSummary.SUMMARYLEVEL_2_FICHE_SPHERE:
                return "sphere";
            case PermissionSummary.SUMMARYLEVEL_3_CROISEMENT_TEST:
                return "croisement";
            case PermissionSummary.SUMMARYLEVEL_4_ALL:
                return "all";
            case PermissionSummary.SUMMARYLEVEL_5_ADMIN:
                return "admin";
            default:
                throw new IllegalArgumentException("level= " + level);
        }
    }

    public static List<Role> wrap(Role[] array) {
        return new RoleList(array);
    }

    public static List<RoleDef.SubsetEntry> wrap(RoleDef.SubsetEntry[] array) {
        return new RoleDefSubsetEntryList(array);
    }

    public static RoleDef.SubsetEntry toSubsetEntry(SubsetKey subsetKey, Permission permission) {
        return new InternalSubsetEntry(subsetKey, permission);
    }


    private static class DefaultPermission implements Permission {

        private final short level;
        private final Permission.CustomPermission customPermission;

        private DefaultPermission(short level, Permission.CustomPermission customPermission) {
            this.level = level;
            this.customPermission = customPermission;
        }

        @Override
        public short getLevel() {
            return level;
        }

        @Override
        public CustomPermission getCustomPermission() {
            return customPermission;
        }

    }


    private static class DefaultFichePermission implements FichePermission {

        private final boolean create;
        private final short read;
        private final short write;

        private DefaultFichePermission(boolean create, short read, short write) {
            this.create = create;
            this.read = read;
            this.write = write;
        }

        @Override
        public boolean create() {
            return create;
        }

        @Override
        public short read() {
            return read;
        }

        @Override
        public short write() {
            return write;
        }

    }


    private static class RoleList extends AbstractList<Role> implements RandomAccess {

        private final Role[] array;

        private RoleList(Role[] array) {
            this.array = array;
        }

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

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

    }


    private static class RoleDefSubsetEntryList extends AbstractList<RoleDef.SubsetEntry> implements RandomAccess {

        private final RoleDef.SubsetEntry[] array;

        private RoleDefSubsetEntryList(RoleDef.SubsetEntry[] array) {
            this.array = array;
        }

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

        @Override
        public RoleDef.SubsetEntry get(int index) {
            return array[index];
        }

    }


    private static class InternalSubsetEntry implements RoleDef.SubsetEntry {

        private final SubsetKey subsetKey;
        private final Permission permission;

        private InternalSubsetEntry(SubsetKey subsetKey, Permission permission) {
            this.subsetKey = subsetKey;
            this.permission = permission;
        }

        @Override
        public SubsetKey getSubsetKey() {
            return subsetKey;
        }

        @Override
        public Permission getPermission() {
            return permission;
        }

    }


    private static class AllSphereSupervisor implements SphereSupervisor {

        private AllSphereSupervisor() {

        }

        @Override
        public boolean allowCoreChange(BdfUser bdfUser, String sphereName) {
            return true;
        }

    }


}
