/** 
 * @file llgroupactions.cpp
 * @brief Group-related actions (join, leave, new, delete, etc)
 *
 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 * 
 * This library 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * 
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */


#include "llviewerprecompiledheaders.h"

#include "llgroupactions.h"

#include "message.h"

#include "llagent.h"
#include "llcommandhandler.h"
#include "llfloaterreg.h"
#include "llfloatersidepanelcontainer.h"
#include "llgroupmgr.h"
#include "llfloaterimcontainer.h"
#include "llimview.h" // for gIMMgr
#include "llnotificationsutil.h"
#include "llstartup.h"
#include "llstatusbar.h"	// can_afford_transaction()
#include "groupchatlistener.h"
// [RLVa:KB] - Checked: 2011-03-28 (RLVa-1.3.0)
#include "llslurl.h"
#include "rlvactions.h"
#include "rlvcommon.h"
#include "rlvhandler.h"
// [/RLVa:KB]

// Firestorm includes
#include "exogroupmutelist.h"
#include "fscommon.h"
#include "fsdata.h"
#include "fsfloatercontacts.h"
#include "fsfloatergroup.h"
#include "fsfloaterim.h"
#include "llpanelgroup.h"
#include "llresmgr.h"

//
// Globals
//
static GroupChatListener sGroupChatListener;

class LLGroupHandler : public LLCommandHandler
{
public:
	// requires trusted browser to trigger
	LLGroupHandler() : LLCommandHandler("group", UNTRUSTED_THROTTLE) { }
	bool handle(const LLSD& tokens, const LLSD& query_map,
				LLMediaCtrl* web)
	{
		if (LLStartUp::getStartupState() < STATE_STARTED)
		{
			return true;
		}

		if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableGroupInfo"))
		{
			LLNotificationsUtil::add("NoGroupInfo", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
			return true;
		}

		if (tokens.size() < 1)
		{
			return false;
		}

		if (tokens[0].asString() == "create")
		{
			LLGroupActions::createGroup();
			return true;
		}

		if (tokens.size() < 2)
		{
			return false;
		}

		if (tokens[0].asString() == "list")
		{
			if (tokens[1].asString() == "show")
			{
				// <FS:Ansariel> Obey FSUseV2Friends setting where to open the group list
				//LLSD params;
				//params["people_panel_tab_name"] = "groups_panel";
				//LLFloaterSidePanelContainer::showPanel("people", "panel_people", params);
				if (gSavedSettings.getBOOL("FSUseV2Friends") && !FSCommon::isLegacySkin())
				{
					LLSD params;
					params["people_panel_tab_name"] = "groups_panel";
					LLFloaterSidePanelContainer::showPanel("people", "panel_people", params);
				}
				else
				{
					FSFloaterContacts::getInstance()->openTab("groups");
				}
				// </FS:Ansariel>
				return true;
			}
            return false;
		}

		LLUUID group_id;
		if (!group_id.set(tokens[0], FALSE))
		{
			return false;
		}

		if (tokens[1].asString() == "about")
		{
			if (group_id.isNull())
				return true;

			LLGroupActions::show(group_id);

			return true;
		}
		if (tokens[1].asString() == "inspect")
		{
			if (group_id.isNull())
				return true;
			LLGroupActions::inspect(group_id);
			return true;
		}
		return false;
	}
};
LLGroupHandler gGroupHandler;

// This object represents a pending request for specified group member information
// which is needed to check whether avatar can leave group
class LLFetchGroupMemberData : public LLGroupMgrObserver
{
public:
	LLFetchGroupMemberData(const LLUUID& group_id) : 
		mGroupId(group_id),
		mRequestProcessed(false),
		LLGroupMgrObserver(group_id) 
	{
		LL_INFOS() << "Sending new group member request for group_id: "<< group_id << LL_ENDL;
		LLGroupMgr* mgr = LLGroupMgr::getInstance();
		// register ourselves as an observer
		mgr->addObserver(this);
		// send a request
		mgr->sendGroupPropertiesRequest(group_id);
		mgr->sendCapGroupMembersRequest(group_id);
	}

	~LLFetchGroupMemberData()
	{
		if (!mRequestProcessed)
		{
			// Request is pending
			LL_WARNS() << "Destroying pending group member request for group_id: "
				<< mGroupId << LL_ENDL;
		}
		// Remove ourselves as an observer
		LLGroupMgr::getInstance()->removeObserver(this);
	}

	void changed(LLGroupChange gc)
	{
		if (gc == GC_PROPERTIES && !mRequestProcessed)
		{
			LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupId);
			if (!gdatap)
			{
				LL_WARNS() << "LLGroupMgr::getInstance()->getGroupData() was NULL" << LL_ENDL;
			} 
			else if (!gdatap->isMemberDataComplete())
			{
				LL_WARNS() << "LLGroupMgr::getInstance()->getGroupData()->isMemberDataComplete() was FALSE" << LL_ENDL;
				processGroupData();
				mRequestProcessed = true;
			}
		}
	}

	LLUUID getGroupId() { return mGroupId; }
	virtual void processGroupData() = 0;
protected:
	LLUUID mGroupId;
private:
	bool mRequestProcessed;
};

class LLFetchLeaveGroupData: public LLFetchGroupMemberData
{
public:
	 LLFetchLeaveGroupData(const LLUUID& group_id)
		 : LLFetchGroupMemberData(group_id)
	 {}
	 void processGroupData()
	 {
		 LLGroupActions::processLeaveGroupDataResponse(mGroupId);
	 }
};

LLFetchLeaveGroupData* gFetchLeaveGroupData = NULL;

// static
void LLGroupActions::search()
{
	// <FS:Ansariel> Open groups search panel instead of invoking presumed failed websearch
	//LLFloaterReg::showInstance("search");
	LLFloaterReg::showInstance("search", LLSD().with("tab", "groups"));
	// </FS:Ansariel>
}

// static
void LLGroupActions::startCall(const LLUUID& group_id)
{
	// create a new group voice session
	LLGroupData gdata;

	if (!gAgent.getGroupData(group_id, gdata))
	{
		LL_WARNS() << "Error getting group data" << LL_ENDL;
		return;
	}

// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9)
	if (!RlvActions::canStartIM(group_id))
	{
		make_ui_sound("UISndInvalidOp");
		RlvUtil::notifyBlocked(RlvStringKeys::Blocked::StartIm, LLSD().with("RECIPIENT", LLSLURL("group", group_id, "about").getSLURLString()));
		return;
	}
// [/RLVa:KB]

	LLUUID session_id = gIMMgr->addSession(gdata.mName, IM_SESSION_GROUP_START, group_id, true);
	if (session_id == LLUUID::null)
	{
		LL_WARNS() << "Error adding session" << LL_ENDL;
		return;
	}

	// start the call
	gIMMgr->autoStartCallOnStartup(session_id);

	make_ui_sound("UISndStartIM");
}

// static
void LLGroupActions::join(const LLUUID& group_id)
{
	if (!gAgent.canJoinGroups())
	{
		LLNotificationsUtil::add("JoinedTooManyGroups");
		return;
	}

	// <FS:Techwolf Lupindo> fsdata support
	if (FSData::instance().isSupportGroup(group_id) && FSData::instance().isAgentFlag(gAgentID, FSData::NO_SUPPORT))
	{
		return;
	}
	// </FS:Techwolf Lupindo>

	LLGroupMgrGroupData* gdatap = 
		LLGroupMgr::getInstance()->getGroupData(group_id);

	if (gdatap)
	{
		S32 cost = gdatap->mMembershipFee;
		LLSD args;
		args["COST"] = llformat("%d", cost);
		args["NAME"] = gdatap->mName;
		LLSD payload;
		payload["group_id"] = group_id;

		if (can_afford_transaction(cost))
		{
			if(cost > 0)
				LLNotificationsUtil::add("JoinGroupCanAfford", args, payload, onJoinGroup);
			else
				LLNotificationsUtil::add("JoinGroupNoCost", args, payload, onJoinGroup);
				
		}
		else
		{
			LLNotificationsUtil::add("JoinGroupCannotAfford", args, payload);
		}
	}
	else
	{
		LL_WARNS() << "LLGroupMgr::getInstance()->getGroupData(" << group_id 
			<< ") was NULL" << LL_ENDL;
	}
}

// static
bool LLGroupActions::onJoinGroup(const LLSD& notification, const LLSD& response)
{
	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);

	if (option == 1)
	{
		// user clicked cancel
		return false;
	}

	LLGroupMgr::getInstance()->
		sendGroupMemberJoin(notification["payload"]["group_id"].asUUID());
	return false;
}

// static
void LLGroupActions::leave(const LLUUID& group_id)
{
//	if (group_id.isNull())
// [RLVa:KB] - Checked: RLVa-1.3.0
	if ( (group_id.isNull()) || ((gAgent.getGroupID() == group_id) && (!RlvActions::canChangeActiveGroup())) )
// [/RLVa:KB]
	{
		return;
	}

	LLGroupData group_data;
	if (gAgent.getGroupData(group_id, group_data))
	{
		LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id);
		if (!gdatap || !gdatap->isMemberDataComplete())
		{
			if (gFetchLeaveGroupData != NULL)
			{
				delete gFetchLeaveGroupData;
				gFetchLeaveGroupData = NULL;
			}
			gFetchLeaveGroupData = new LLFetchLeaveGroupData(group_id);
		}
		else
		{
			processLeaveGroupDataResponse(group_id);
		}
	}
}

//static
void LLGroupActions::processLeaveGroupDataResponse(const LLUUID group_id)
{
	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id);
	LLUUID agent_id = gAgent.getID();
	LLGroupMgrGroupData::member_list_t::iterator mit = gdatap->mMembers.find(agent_id);
	//get the member data for the group
	if ( mit != gdatap->mMembers.end() )
	{
		LLGroupMemberData* member_data = (*mit).second;

		if ( member_data && member_data->isOwner() && gdatap->mMemberCount == 1)
		{
			LLNotificationsUtil::add("OwnerCannotLeaveGroup");
			return;
		}
	}
	LLSD args;
	args["GROUP"] = gdatap->mName;
	LLSD payload;
	payload["group_id"] = group_id;
	// <FS:Ansariel> FIRE-17676: Add special group leave notification in case of join fees
	if (gdatap->mMembershipFee > 0)
	{
		args["AMOUNT"] = LLResMgr::getInstance()->getMonetaryString(gdatap->mMembershipFee);
		LLNotificationsUtil::add("GroupLeaveConfirmMemberWithFee", args, payload, onLeaveGroup);
		return;
	}
	// </FS:Ansariel>
	LLNotificationsUtil::add("GroupLeaveConfirmMember", args, payload, onLeaveGroup);
}

// static
void LLGroupActions::activate(const LLUUID& group_id)
{
// [RLVa:KB] - Checked: RLVa-1.3.0
	if ( (!RlvActions::canChangeActiveGroup()) && (gRlvHandler.getAgentGroup() != group_id) )
	{
		return;
	}
// [/RLVa:KB]

	LLMessageSystem* msg = gMessageSystem;
	msg->newMessageFast(_PREHASH_ActivateGroup);
	msg->nextBlockFast(_PREHASH_AgentData);
	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
	msg->addUUIDFast(_PREHASH_GroupID, group_id);
	gAgent.sendReliableMessage();
}

static bool isGroupUIVisible()
{
	static LLPanel* panel = 0;
	if(!panel)
		panel = LLFloaterSidePanelContainer::getPanel("people", "panel_group_info_sidetray");
	if(!panel)
		return false;
	return panel->isInVisibleChain();
}

// static 
void LLGroupActions::inspect(const LLUUID& group_id)
{
	LLFloaterReg::showInstance("inspect_group", LLSD().with("group_id", group_id));
}

// static
void LLGroupActions::show(const LLUUID& group_id)
{
	if (group_id.isNull())
		return;

	LLSD params;
	params["group_id"] = group_id;
	params["open_tab_name"] = "panel_group_info_sidetray";

	// <FS:Ansariel> Standalone group floaters
	//LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params);
    //LLFloater *floater = LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>("people");
    //if (!floater->isFrontmost())
    //{
    //    floater->setVisibleAndFrontmost(TRUE, params);
    //}
	LLFloater* floater = NULL;
	if (gSavedSettings.getBOOL("FSUseStandaloneGroupFloater")) 
	{
		floater = FSFloaterGroup::openGroupFloater(group_id);
	}
	else
	{
		LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params);
		LLFloaterSidePanelContainer* floater_people = LLFloaterReg::findTypedInstance<LLFloaterSidePanelContainer>("people");
		if (floater_people)
		{
			LLPanel* group_info_panel = floater_people->getPanel("people", "panel_group_info_sidetray");
			if (group_info_panel && group_info_panel->getVisible())
			{
				floater = floater_people;
			}
		}
	}

	if (floater)
	{
		if (floater->isMinimized())
		{
			floater->setMinimized(FALSE);
		}
		if (!floater->hasFocus())
		{
			floater->setFocus(TRUE);
		}
	}
	// </FS:Ansariel>
}

// static
void LLGroupActions::show(const LLUUID& group_id, const std::string& tab_name)
{
	if (group_id.isNull())
		return;

	LLSD params;
	params["group_id"] = group_id;
	params["open_tab_name"] = tab_name;

	// <FS:Ansariel> Standalone group floaters
	//LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params);
	LLFloater* floater = NULL;
	if (gSavedSettings.getBOOL("FSUseStandaloneGroupFloater")) 
	{
		floater = FSFloaterGroup::openGroupFloater(params);
	}
	else
	{
		LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params);
		LLFloaterSidePanelContainer* floater_people = LLFloaterReg::findTypedInstance<LLFloaterSidePanelContainer>("people");
		if (floater_people)
		{
			LLPanel* group_info_panel = floater_people->getPanel("people", "panel_group_info_sidetray");
			if (group_info_panel && group_info_panel->getVisible())
			{
				floater = floater_people;
			}
		}
	}

	if (floater && floater->isMinimized())
	{
		floater->setMinimized(FALSE);
	}
	// </FS:Ansariel>
}

// <FS:Ansariel> Standalone group floaters
//void LLGroupActions::refresh_notices()
void LLGroupActions::refresh_notices(const LLUUID& group_id /*= LLUUID::null*/)
{
	// <FS:Ansariel> Standalone group floaters
	//if(!isGroupUIVisible())
	//	return;
	// </FS:Ansariel>

	LLSD params;
	params["group_id"] = LLUUID::null;
	params["open_tab_name"] = "panel_group_info_sidetray";
	params["action"] = "refresh_notices";

	// <FS:Ansariel> Standalone group floaters
	//LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params);
	if (gSavedSettings.getBOOL("FSUseStandaloneGroupFloater")) 
	{
		if (FSFloaterGroup::isFloaterVisible(group_id))
		{
			FSFloaterGroup::openGroupFloater(LLSD().with("group_id", group_id).with("open_tab_name", "panel_group_info_sidetray").with("action", "refresh_notices"));
		}
	}
	else
	{
		if (isGroupUIVisible())
		{
			LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params);
		}
	}
	// </FS:Ansariel>
}

//static 
void LLGroupActions::refresh(const LLUUID& group_id)
{
	// <FS:Ansariel> Standalone group floaters
	//if(!isGroupUIVisible())
	//	return;
	// </FS:Ansariel>

	LLSD params;
	params["group_id"] = group_id;
	params["open_tab_name"] = "panel_group_info_sidetray";
	params["action"] = "refresh";

	// <FS:Ansariel> Standalone group floaters
	//LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params);
	if (gSavedSettings.getBOOL("FSUseStandaloneGroupFloater")) 
	{
		if (FSFloaterGroup::isFloaterVisible(group_id))
		{
			FSFloaterGroup::openGroupFloater(params);
		}
	}
	else
	{
		if (isGroupUIVisible())
		{
			LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params);
		}
	}
	// </FS:Ansariel>
}

//static 
void LLGroupActions::createGroup()
{
	LLSD params;
	params["group_id"] = LLUUID::null;
	params["open_tab_name"] = "panel_group_creation_sidetray";
	params["action"] = "create";

	// <FS:Ansariel> Standalone group floaters
	//LLFloaterSidePanelContainer::showPanel("people", "panel_group_creation_sidetray", params);
	if (gSavedSettings.getBOOL("FSUseStandaloneGroupFloater"))
	{
		FSFloaterGroup::openGroupFloater(params);
	}
	else
	{
		LLFloaterSidePanelContainer::showPanel("people", "panel_group_creation_sidetray", params);
	}
	// </FS:Ansariel>
}
//static
void LLGroupActions::closeGroup(const LLUUID& group_id)
{
	// <FS:Ansariel> Standalone group floaters
	//if(!isGroupUIVisible())
	//	return;
	// </FS:Ansariel>

	LLSD params;
	params["group_id"] = group_id;
	params["open_tab_name"] = "panel_group_info_sidetray";
	params["action"] = "close";

	// <FS:Ansariel> Standalone group floaters
	//LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params);
	if (gSavedSettings.getBOOL("FSUseStandaloneGroupFloater")) 
	{
		FSFloaterGroup::closeGroupFloater(group_id);
	}
	else
	{
		if (isGroupUIVisible())
		{
			LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params);
		}
	}
	// </FS:Ansariel>
}

// static
LLUUID LLGroupActions::startIM(const LLUUID& group_id)
{
	if (group_id.isNull()) return LLUUID::null;

// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9)
	if (!RlvActions::canStartIM(group_id))
	{
		make_ui_sound("UISndInvalidOp");
		RlvUtil::notifyBlocked(RlvStringKeys::Blocked::StartIm, LLSD().with("RECIPIENT", LLSLURL("group", group_id, "about").getSLURLString()));
		return LLUUID::null;
	}
// [/RLVa:KB]

	LLGroupData group_data;
	if (gAgent.getGroupData(group_id, group_data))
	{
		// <exodus>
		// Unmute the group if the user tries to start a session with it.
		exoGroupMuteList::instance().remove(group_id);
		// </exodus>
		LLUUID session_id = gIMMgr->addSession(
			group_data.mName,
			IM_SESSION_GROUP_START,
			group_id);
		if (session_id != LLUUID::null)
		{
			// <FS:Ansariel> [FS communication UI]
			//LLFloaterIMContainer::getInstance()->showConversation(session_id);
			FSFloaterIM::show(session_id);
			// </FS:Ansariel> [FS communication UI]
		}
		make_ui_sound("UISndStartIM");
		return session_id;
	}
	else
	{
		// this should never happen, as starting a group IM session
		// relies on you belonging to the group and hence having the group data
		make_ui_sound("UISndInvalidOp");
		return LLUUID::null;
	}
}

// [SL:KB] - Patch: Chat-GroupSnooze | Checked: 2012-06-17 (Catznip-3.3)
static void snooze_group_im(const LLUUID& group_id, S32 duration = -1)
{
	LLUUID session_id = gIMMgr->computeSessionID(IM_SESSION_GROUP_START, group_id);
	if (session_id.notNull())
	{
		LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id);

		if (!session)
		{
			LL_WARNS() << "Empty session." << LL_ENDL;
			return;
		}

		session->mSnoozeTime = duration;
		session->mCloseAction = LLIMModel::LLIMSession::CLOSE_SNOOZE;

		gIMMgr->leaveSession(session_id);
	}
}

static void snooze_group_im_duration_callback(const LLSD& notification, const LLSD& response, const LLUUID& group_id)
{
	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
	if (0 == option)
	{
		std::istringstream duration_str(response["duration"].asString());
		S32 duration(-1);
		if (duration_str >> duration && duration >= 0)
		{
			snooze_group_im(group_id, duration);
		}
		else
		{
			LLNotificationsUtil::add("SnoozeDurationInvalidInput");
		}
	}
}

static void confirm_group_im_snooze(const LLUUID& group_id)
{
	if (group_id.isNull())
	{
		return;
	}

	if (gSavedSettings.getBOOL("FSEnablePerGroupSnoozeDuration"))
	{
		LLSD args;
		args["DURATION"] = gSavedSettings.getS32("GroupSnoozeTime");

		LLNotificationsUtil::add("SnoozeDuration", args, LLSD(), boost::bind(&snooze_group_im_duration_callback, _1, _2, group_id));
		return;
	}

	snooze_group_im(group_id);
}

static void close_group_im(const LLUUID& group_id, LLIMModel::LLIMSession::SCloseAction close_action)
{
	if (group_id.isNull())
	{
		return;
	}
	
	LLUUID session_id = gIMMgr->computeSessionID(IM_SESSION_GROUP_START, group_id);
	if (session_id.notNull())
	{
		LLIMModel::LLIMSession* pIMSession = LLIMModel::getInstance()->findIMSession(session_id);
		if (pIMSession)
		{
			pIMSession->mCloseAction = close_action;
		}
		gIMMgr->leaveSession(session_id);
	}
}

void LLGroupActions::leaveIM(const LLUUID& group_id)
{
	close_group_im(group_id, LLIMModel::LLIMSession::CLOSE_LEAVE);
}

void LLGroupActions::snoozeIM(const LLUUID& group_id)
{
	confirm_group_im_snooze(group_id);
}

void LLGroupActions::endIM(const LLUUID& group_id)
{
	close_group_im(group_id, LLIMModel::LLIMSession::CLOSE_DEFAULT);
}

// [/SL:KB]
//// static
//void LLGroupActions::endIM(const LLUUID& group_id)
//{
//	if (group_id.isNull())
//		return;
//	
//	LLUUID session_id = gIMMgr->computeSessionID(IM_SESSION_GROUP_START, group_id);
//	if (session_id != LLUUID::null)
//	{
//		gIMMgr->leaveSession(session_id);
//	}
//}

// static
bool LLGroupActions::isInGroup(const LLUUID& group_id)
{
	// *TODO: Move all the LLAgent group stuff into another class, such as
	// this one.
	return gAgent.isInGroup(group_id);
}

// static
bool LLGroupActions::isAvatarMemberOfGroup(const LLUUID& group_id, const LLUUID& avatar_id)
{
	if(group_id.isNull() || avatar_id.isNull())
	{
		return false;
	}

	LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(group_id);
	if(!group_data)
	{
		return false;
	}

	if(group_data->mMembers.end() == group_data->mMembers.find(avatar_id))
	{
		return false;
	}

	return true;
}

// [SL:KB] - Patch: Chat-GroupSessionEject | Checked: 2012-02-04 (Catznip-3.2.1) | Added: Catznip-3.2.1
bool LLGroupActions::canEjectFromGroup(const LLUUID& idGroup, const LLUUID& idAgent)
{
	if (gAgent.isGodlike())
	{
		return true;
	}

	if (gAgent.hasPowerInGroup(idGroup, GP_MEMBER_EJECT))
	{
		const LLGroupMgrGroupData* pGroupData = LLGroupMgr::getInstance()->getGroupData(idGroup);
		if ( (!pGroupData) || (!pGroupData->isMemberDataComplete()) )
		{
			// There is no (or not enough) information on this group but the user does have the group eject power
			return true;
		}

		LLGroupMgrGroupData::member_list_t::const_iterator itMember = pGroupData->mMembers.find(idAgent);
		if (pGroupData->mMembers.end() != itMember)
		{
			const LLGroupMemberData* pMemberData = (*itMember).second;
			if ( (pGroupData->isRoleDataComplete()) && (pGroupData->isRoleMemberDataComplete()) )
			{
				for (LLGroupMemberData::role_list_t::const_iterator itRole = pMemberData->roleBegin(); 
						itRole != pMemberData->roleEnd(); ++itRole)
				{
					if ((*itRole).first.notNull())
					{
						// Someone who belongs to any roles other than "Everyone" can't be ejected
						return false;
					}
				}
			}
			// Owners can never be ejected
			return (itMember->second) && (!itMember->second->isOwner());
		}
	}
	return false;
}

void LLGroupActions::ejectFromGroup(const LLUUID& idGroup, const LLUUID& idAgent)
{
	LLSD args;
	LLSD payload;
	payload["avatar_id"] = idAgent;
	payload["group_id"] = idGroup;
	// <FS:Ansariel> Show complete name in eject dialog
	//std::string fullname = LLSLURL("agent", idAgent, "inspect").getSLURLString();
	std::string fullname = LLSLURL("agent", idAgent, "completename").getSLURLString();
	// </FS:Ansariel>
	args["AVATAR_NAME"] = fullname;
	LLNotificationsUtil::add("EjectGroupMemberWarning",
							 args,
							 payload,
							 callbackEject);
}

bool LLGroupActions::callbackEject(const LLSD& notification, const LLSD& response)
{
	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
	if (2 == option) // Cancel button
	{
		return false;
	}
	if (0 == option) // Eject button
	{
		LLUUID idAgent = notification["payload"]["avatar_id"].asUUID();
		LLUUID idGroup = notification["payload"]["group_id"].asUUID();
		
		if (!canEjectFromGroup(idGroup, idAgent))
			return false;
		
		uuid_vec_t idAgents;
		idAgents.push_back(idAgent);
		LLGroupMgr::instance().sendGroupMemberEjects(idGroup, idAgents);
	}
	return false;
}
// [/SL:KB]

//-- Private methods ----------------------------------------------------------

// static
bool LLGroupActions::onLeaveGroup(const LLSD& notification, const LLSD& response)
{
	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
	LLUUID group_id = notification["payload"]["group_id"].asUUID();
	if(option == 0)
	{
		// <FS:Ansariel> Standalone group floaters
		if (gSavedSettings.getBOOL("FSUseStandaloneGroupFloater")) 
		{
			FSFloaterGroup::closeGroupFloater(group_id);
		}
		// </FS:Ansariel>
		LLMessageSystem* msg = gMessageSystem;
		msg->newMessageFast(_PREHASH_LeaveGroupRequest);
		msg->nextBlockFast(_PREHASH_AgentData);
		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
		msg->nextBlockFast(_PREHASH_GroupData);
		msg->addUUIDFast(_PREHASH_GroupID, group_id);
		gAgent.sendReliableMessage();
	}
	return false;
}
