package com.gss.gmo.cao.openfire.ldap;

import java.util.Collection;
import java.util.Set;
import java.util.TreeSet;

import javax.naming.ldap.LdapName;

import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.group.Group;
import org.jivesoftware.openfire.group.GroupNotFoundException;
import org.jivesoftware.openfire.ldap.LdapManager;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.PersistableMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.JID;

public class LdapGroupProvider extends org.jivesoftware.openfire.ldap.LdapGroupProvider {

	private static final Logger LOG = LoggerFactory.getLogger(LdapGroupProvider.class);

	private XMPPServer server = XMPPServer.getInstance();

	private UserManager userManager = server.getUserManager();

	private LdapManager ldapManager = LdapManager.getInstance();

	@Override
	public PersistableMap<String, String> loadProperties(Group group) {
		PersistableMap<String, String> result = super.loadProperties(group);
		if (result.isEmpty()) {
			LOG.debug("##### Original group properties: " + result.toString() + " #####");
			result.put("sharedRoster.displayName", group.getName());
			result.put("sharedRoster.showInRoster", "onlyGroup");
			result.put("sharedRoster.groupList", "");
			LOG.debug("##### Modified group properties: " + result.toString() + " #####");
		}

		return result;
	}

	@Override
	public Group getGroup(String groupName) throws GroupNotFoundException {
		Group group = super.getGroup(groupName);
		Set<JID> newMembers = new TreeSet<JID>();
		Collection<JID> members = group.getMembers();
		for (JID member : members) {
			if (server.isLocal(member)) {
				try {
					userManager.getUser(member.getNode());
					newMembers.add(member);
				} catch (UserNotFoundException unfe) {
					LOG.debug("########## Non-user JID: " + member.toBareJID());
					String subGroupDN = member.getNode();
					LOG.debug("########## Sub-group Node: " + subGroupDN);
					try {
						LdapName ldapName = new LdapName(subGroupDN);
						String subGroupName = ldapName.getRdn(ldapName.size() - 1).getValue().toString();
						LOG.debug("########## Sub-group name: " + subGroupName);
						Group subGroup = getGroup(subGroupName);
						newMembers.addAll(subGroup.getMembers());
					} catch (Exception e) {
						LOG.error(e.getMessage(), e);
					}
				}
			} else {
				newMembers.add(member);
			}
		}
		return new Group(group.getName(), group.getDescription(), newMembers, group.getAdmins());
	}

	@Override
	public Collection<String> getGroupNames(JID user) {
		Collection<String> groupNames = super.getGroupNames(user);
		Collection<String> allGroupNames = new TreeSet<String>();
		allGroupNames.addAll(groupNames);
		for (String groupName : groupNames) {
			allGroupNames.addAll(getParentGroupNames(groupName));
		}
		LOG.debug("########## All parent groups of " + user.getNode() + " are " + allGroupNames.toString());
		LOG.info("########## All parent groups of " + user.getNode() + " are " + allGroupNames.toString());
		return allGroupNames;
	}

	public Collection<String> getParentGroupNames(String groupName) {
		Set<String> allParentGroupNames = new TreeSet<String>();
		try {
			String groupDn = ldapManager.findGroupDN(groupName);
			LOG.debug("########## Group DN: " + groupDn);
			String fullGroupDn = groupDn + "," + ldapManager.getGroupsBaseDN(groupName);
			LOG.debug("########## Full Group DN: " + fullGroupDn);
			Collection<String> parentGroupNames = search(ldapManager.getGroupMemberField(), fullGroupDn);
			LOG.debug("########## Parent Group Names: " + parentGroupNames.toString());
			if (!parentGroupNames.isEmpty()) {
				allParentGroupNames.addAll(parentGroupNames);
				for (String parentGroupName : parentGroupNames) {
					allParentGroupNames.addAll(getParentGroupNames(parentGroupName));
				}
			}
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
		}
		LOG.debug("########## All parent groups of " + groupName + " are " + allParentGroupNames.toString());
		return allParentGroupNames;
	}

}
