/*
// This software is subject to the terms of the Eclipse Public License v1.0
// Agreement, available at the following URL:
// http://www.eclipse.org/legal/epl-v10.html.
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 1999-2005 Julian Hyde
// Copyright (C) 2005-2012 Pentaho and others
// All Rights Reserved.
*/

package mondrian.olap;

import mondrian.resource.MondrianResource;

import java.util.ArrayList;
import java.util.List;

/**
 * This class implements object of type GrantCube to apply permissions
 * on user's MDX query
 *
 * @author lkrivopaltsev, 01 November, 1999
 */
public class CubeAccess {

    private boolean hasRestrictions;
    /** array of hierarchies with no access */
    private Hierarchy[] noAccessHierarchies;
    /** array of members which have limited access */
    private Member[]  limitedMembers;
    private final List<Hierarchy> hierarchyList = new ArrayList<Hierarchy>();
    private final List<Member> memberList = new ArrayList<Member>();
    private final Cube mdxCube;

    /**
     * Creates a CubeAccess object.
     *
     * <p>User's code should be responsible for
     * filling cubeAccess with restricted hierarchies and restricted
     * members by calling addSlicer(). Do NOT forget to call
     * {@link #normalizeCubeAccess()} after you done filling cubeAccess.
     */
    public CubeAccess(Cube mdxCube) {
        this.mdxCube = mdxCube;
        noAccessHierarchies = null;
        limitedMembers = null;
        hasRestrictions = false;
    }

    public boolean hasRestrictions() {
        return hasRestrictions;
    }

    public Hierarchy[] getNoAccessHierarchies() {
        return noAccessHierarchies;
    }

    public Member[] getLimitedMembers() {
        return limitedMembers;
    }

    public List<Hierarchy> getNoAccessHierarchyList() {
        return hierarchyList;
    }

    public List<Member> getLimitedMemberList() {
        return memberList;
    }

    public boolean isHierarchyAllowed(Hierarchy mdxHierarchy) {
        String hierName = mdxHierarchy.getUniqueName();
        if (noAccessHierarchies == null || hierName == null) {
            return true;
        }
        for (Hierarchy noAccessHierarchy : noAccessHierarchies) {
            if (hierName.equalsIgnoreCase(noAccessHierarchy.getUniqueName())) {
                return false;
            }
        }
        return true;
    }

    public Member getLimitedMemberForHierarchy(Hierarchy mdxHierarchy) {
        String hierName = mdxHierarchy.getUniqueName();
        if (limitedMembers == null || hierName == null) {
            return null;
        }
        for (Member limitedMember : limitedMembers) {
            Hierarchy limitedHierarchy = limitedMember.getHierarchy();
            if (hierName.equalsIgnoreCase(limitedHierarchy.getUniqueName())) {
                return limitedMember;
            }
        }
        return null;
    }

    /**
     * Adds  restricted hierarchy or limited member based on bMember
     */
    public void addGrantCubeSlicer(
        String sHierarchy,
        String sMember,
        boolean bMember)
    {
        if (bMember) {
            boolean fail = false;
            List<Id.Segment> sMembers = Util.parseIdentifier(sMember);
            SchemaReader schemaReader = mdxCube.getSchemaReader(null);
            Member member = schemaReader.getMemberByUniqueName(sMembers, fail);
            if (member == null) {
                throw MondrianResource.instance().MdxCubeSlicerMemberError.ex(
                    sMember, sHierarchy, mdxCube.getUniqueName());
            }
            // there should be only slicer per hierarchy; ignore the rest
            if (getLimitedMemberForHierarchy(member.getHierarchy()) == null) {
                memberList.add(member);
            }
        } else {
            boolean fail = false;
            Hierarchy hierarchy =
                mdxCube.lookupHierarchy(
                    new Id.NameSegment(sHierarchy),
                    fail);
            if (hierarchy == null) {
                throw MondrianResource.instance().MdxCubeSlicerHierarchyError
                    .ex(sHierarchy, mdxCube.getUniqueName());
            }
            hierarchyList.add(hierarchy);
        }
    }

    /**
     * Initializes internal arrays of restricted hierarchies and limited
     * members. It has to be called  after all 'addSlicer()' calls.
     */
    public void normalizeCubeAccess() {
        if (memberList.size() > 0) {
            limitedMembers = memberList.toArray(new Member[memberList.size()]);
            hasRestrictions = true;
        }
        if (hierarchyList.size() > 0) {
            noAccessHierarchies =
                hierarchyList.toArray(
                    new Hierarchy[hierarchyList.size()]);
            hasRestrictions = true;
        }
    }

    public boolean equals(Object object) {
        if (!(object instanceof CubeAccess)) {
            return false;
        }
        CubeAccess cubeAccess = (CubeAccess) object;
        List<Hierarchy> hierarchyList = cubeAccess.getNoAccessHierarchyList();
        List<Member> limitedMemberList = cubeAccess.getLimitedMemberList();

        if ((this.hierarchyList.size() != hierarchyList.size())
            || (this.memberList.size() != limitedMemberList.size()))
        {
            return false;
        }
        for (Hierarchy o : hierarchyList) {
            if (!this.hierarchyList.contains(o)) {
                return false;
            }
        }
        for (Member member : limitedMemberList) {
            if (!this.memberList.contains(member)) {
                return false;
            }
        }
        return true;
    }

    public int hashCode() {
        int h = mdxCube.hashCode();
        h = Util.hash(h, hierarchyList);
        h = Util.hash(h, memberList);
        h = Util.hashArray(h, noAccessHierarchies);
        h = Util.hashArray(h, limitedMembers);
        return h;
    }
}

// End CubeAccess.java
