/**
 * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of the Liferay Enterprise
 * Subscription License ("License"). You may not use this file except in
 * compliance with the License. You can obtain a copy of the License by
 * contacting Liferay, Inc. See the License for the specific language governing
 * permissions and limitations under the License, including but not limited to
 * distribution rights of the Software.
 *
 *
 *
 */

package com.liferay.portlet.announcements.util;

import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.ListUtil;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.PropsUtil;
import com.liferay.portal.model.Group;
import com.liferay.portal.model.Organization;
import com.liferay.portal.model.Role;
import com.liferay.portal.model.RoleConstants;
import com.liferay.portal.model.Team;
import com.liferay.portal.model.User;
import com.liferay.portal.model.UserGroup;
import com.liferay.portal.model.UserGroupGroupRole;
import com.liferay.portal.model.UserGroupRole;
import com.liferay.portal.security.permission.ActionKeys;
import com.liferay.portal.service.GroupLocalServiceUtil;
import com.liferay.portal.service.OrganizationLocalServiceUtil;
import com.liferay.portal.service.RoleLocalServiceUtil;
import com.liferay.portal.service.TeamLocalServiceUtil;
import com.liferay.portal.service.UserGroupGroupRoleLocalServiceUtil;
import com.liferay.portal.service.UserGroupLocalServiceUtil;
import com.liferay.portal.service.UserGroupRoleLocalServiceUtil;
import com.liferay.portal.service.UserLocalServiceUtil;
import com.liferay.portal.service.permission.GroupPermissionUtil;
import com.liferay.portal.service.permission.OrganizationPermissionUtil;
import com.liferay.portal.service.permission.RolePermissionUtil;
import com.liferay.portal.service.permission.UserGroupPermissionUtil;
import com.liferay.portal.theme.ThemeDisplay;
import com.liferay.portal.util.PortalUtil;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;

/**
 * @author Raymond Augé
 */
public class AnnouncementsUtil {

	/**
	 * @deprecated As of 6.2.0, replaced by {@link #getAnnouncementScopes(User)}
	 */
	@Deprecated
	public static LinkedHashMap<Long, long[]> getAnnouncementScopes(long userId)
		throws PortalException, SystemException {

		return getAnnouncementScopes(UserLocalServiceUtil.getUserById(userId));
	}

	public static LinkedHashMap<Long, long[]> getAnnouncementScopes(User user)
		throws PortalException, SystemException {

		long userId = user.getUserId();

		LinkedHashMap<Long, long[]> scopes = new LinkedHashMap<Long, long[]>();

		// General announcements

		scopes.put(new Long(0), new long[] {0});

		// Personal announcements

		scopes.put(_USER_CLASS_NAME_ID, new long[] {userId});

		// Organization announcements

		List<Group> groupsList = new ArrayList<Group>();

		List<Organization> organizations =
			OrganizationLocalServiceUtil.getUserOrganizations(userId);

		if (!organizations.isEmpty()) {
			List<Organization> organizationsList =
				new ArrayList<Organization>();

			organizationsList.addAll(organizations);

			for (Organization organization : organizations) {
				groupsList.add(organization.getGroup());

				List<Organization> parentOrganizations =
					OrganizationLocalServiceUtil.getParentOrganizations(
						organization.getOrganizationId());

				for (Organization parentOrganization : parentOrganizations) {
					organizationsList.add(parentOrganization);
					groupsList.add(parentOrganization.getGroup());
				}
			}

			scopes.put(
				_ORGANIZATION_CLASS_NAME_ID,
				_getOrganizationIds(organizationsList));
		}

		// Site announcements

		List<Group> groups = GroupLocalServiceUtil.getUserGroups(userId, true);

		if (!groups.isEmpty()) {
			scopes.put(_GROUP_CLASS_NAME_ID, _getGroupIds(groups));

			groupsList.addAll(groups);
		}

		// User group announcements

		List<UserGroup> userGroups =
			UserGroupLocalServiceUtil.getUserUserGroups(userId);

		if (!userGroups.isEmpty()) {
			scopes.put(_USER_GROUP_CLASS_NAME_ID, _getUserGroupIds(userGroups));

			for (UserGroup userGroup : userGroups) {
				groupsList.add(userGroup.getGroup());
			}
		}

		// Role announcements

		Set<Long> roleIds = new HashSet<Long>();

		if (!groupsList.isEmpty()) {
			List<Role> roles = RoleLocalServiceUtil.getUserRelatedRoles(
				userId, groupsList);

			for (Role role : roles) {
				roleIds.add(role.getRoleId());
			}
		}
		else {
			List<Role> roles = RoleLocalServiceUtil.getUserRoles(userId);

			for (Role role : roles) {
				roleIds.add(role.getRoleId());
			}
		}

		if (!groups.isEmpty() || !organizations.isEmpty()) {
			List<UserGroupRole> userGroupRoles =
				UserGroupRoleLocalServiceUtil.getUserGroupRoles(userId);

			for (UserGroupRole userGroupRole : userGroupRoles) {
				roleIds.add(userGroupRole.getRoleId());
			}
		}

		if (!userGroups.isEmpty()) {
			List<UserGroupGroupRole> userGroupGroupRoles =
				UserGroupGroupRoleLocalServiceUtil.getUserGroupGroupRolesByUser(
					userId);

			for (UserGroupGroupRole userGroupGroupRole : userGroupGroupRoles) {
				roleIds.add(userGroupGroupRole.getRoleId());
			}
		}

		List<Team> teams = TeamLocalServiceUtil.getUserTeams(userId);

		long[] teamIds = ListUtil.toLongArray(teams, Team.TEAM_ID_ACCESSOR);

		long companyId = user.getCompanyId();

		if (teamIds.length > 0) {
			List<Role> teamRoles = RoleLocalServiceUtil.getTeamsRoles(
				companyId, teamIds);

			for (Role teamRole : teamRoles) {
				roleIds.add(teamRole.getRoleId());
			}
		}

		if (_PERMISSIONS_CHECK_GUEST_ENABLED) {
			Role guestRole = RoleLocalServiceUtil.getRole(
				companyId, RoleConstants.GUEST);

			roleIds.add(guestRole.getRoleId());
		}

		if (roleIds.size() > 0) {
			scopes.put(_ROLE_CLASS_NAME_ID, ArrayUtil.toLongArray(roleIds));
		}

		return scopes;
	}

	public static List<Group> getGroups(ThemeDisplay themeDisplay)
		throws Exception {

		List<Group> filteredGroups = new ArrayList<Group>();

		List<Group> groups = GroupLocalServiceUtil.getUserGroups(
			themeDisplay.getUserId(), true);

		for (Group group : groups) {
			if (((group.isOrganization() && group.isSite()) ||
				 group.isRegularSite()) &&
				GroupPermissionUtil.contains(
					themeDisplay.getPermissionChecker(), group.getGroupId(),
					ActionKeys.MANAGE_ANNOUNCEMENTS)) {

				filteredGroups.add(group);
			}
		}

		return filteredGroups;
	}

	public static List<Organization> getOrganizations(ThemeDisplay themeDisplay)
		throws Exception {

		List<Organization> filteredOrganizations =
			new ArrayList<Organization>();

		List<Organization> organizations =
			OrganizationLocalServiceUtil.getUserOrganizations(
				themeDisplay.getUserId());

		for (Organization organization : organizations) {
			if (OrganizationPermissionUtil.contains(
					themeDisplay.getPermissionChecker(),
					organization.getOrganizationId(),
					ActionKeys.MANAGE_ANNOUNCEMENTS)) {

				filteredOrganizations.add(organization);
			}
		}

		return filteredOrganizations;
	}

	public static List<Role> getRoles(ThemeDisplay themeDisplay)
		throws Exception {

		List<Role> filteredRoles = new ArrayList<Role>();

		List<Role> roles = RoleLocalServiceUtil.getRoles(
			themeDisplay.getCompanyId());

		for (Role role : roles) {
			if (role.isTeam()) {
				Team team = TeamLocalServiceUtil.getTeam(role.getClassPK());

				if (GroupPermissionUtil.contains(
						themeDisplay.getPermissionChecker(), team.getGroupId(),
						ActionKeys.MANAGE_ANNOUNCEMENTS) ||
					RolePermissionUtil.contains(
						themeDisplay.getPermissionChecker(),
						themeDisplay.getScopeGroupId(), role.getRoleId(),
						ActionKeys.MANAGE_ANNOUNCEMENTS)) {

					filteredRoles.add(role);
				}
			}
			else if (RolePermissionUtil.contains(
						themeDisplay.getPermissionChecker(), role.getRoleId(),
						ActionKeys.MANAGE_ANNOUNCEMENTS)) {

				filteredRoles.add(role);
			}
		}

		return filteredRoles;
	}

	public static List<UserGroup> getUserGroups(ThemeDisplay themeDisplay)
		throws Exception {

		List<UserGroup> filteredUserGroups = new ArrayList<UserGroup>();

		List<UserGroup> userGroups = UserGroupLocalServiceUtil.getUserGroups(
			themeDisplay.getCompanyId());

		for (UserGroup userGroup : userGroups) {
			if (UserGroupPermissionUtil.contains(
					themeDisplay.getPermissionChecker(),
					userGroup.getUserGroupId(),
					ActionKeys.MANAGE_ANNOUNCEMENTS)) {

				filteredUserGroups.add(userGroup);
			}
		}

		return filteredUserGroups;
	}

	private static long[] _getGroupIds(List<Group> groups) {
		long[] groupIds = new long[groups.size()];

		int i = 0;

		for (Group group : groups) {
			groupIds[i++] = group.getGroupId();
		}

		return groupIds;
	}

	private static long[] _getOrganizationIds(
		List<Organization> organizations) {

		long[] organizationIds = new long[organizations.size()];

		int i = 0;

		for (Organization organization : organizations) {
			organizationIds[i++] = organization.getOrganizationId();
		}

		return organizationIds;
	}

	private static long[] _getUserGroupIds(List<UserGroup> userGroups) {
		long[] userGroupIds = new long[userGroups.size()];

		int i = 0;

		for (UserGroup userGroup : userGroups) {
			userGroupIds[i++] = userGroup.getUserGroupId();
		}

		return userGroupIds;
	}

	private static final long _GROUP_CLASS_NAME_ID = PortalUtil.getClassNameId(
		Group.class.getName());

	private static final long _ORGANIZATION_CLASS_NAME_ID =
		PortalUtil.getClassNameId(Organization.class.getName());

	private static final boolean _PERMISSIONS_CHECK_GUEST_ENABLED =
		GetterUtil.getBoolean(
			PropsUtil.get(PropsKeys.PERMISSIONS_CHECK_GUEST_ENABLED));

	private static final long _ROLE_CLASS_NAME_ID = PortalUtil.getClassNameId(
		Role.class.getName());

	private static final long _USER_CLASS_NAME_ID = PortalUtil.getClassNameId(
		User.class.getName());

	private static final long _USER_GROUP_CLASS_NAME_ID =
		PortalUtil.getClassNameId(UserGroup.class.getName());

}