"Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
      
      Methods that run without errors, but do not have the intended result should return as:
      
      return array('succeed' => 'false', 'message' => 'No Groups Found', 'params' => var_export($params, TRUE));
      
      or if applicable:
      
      return array('succeed' => 'false', 'message' => 'What went wrong', 'params' => var_export($params, TRUE), 'sql' => $sql);
    */
	// Modified by Fumi.Iseki '09 5/31
	// Modified by Fumi.Iseki '14 3/4
	// Modified by Fumi.Iseki '14 5/15 for MySQLi
	// Modified by Fumi.Iseki '16 7/14
    include(dirname(__FILE__).'/phpxmlrpclib/xmlrpc.inc');
    include(dirname(__FILE__).'/phpxmlrpclib/xmlrpcs.inc');
    
	// Global
	$osagent               = XMLGROUP_ACTIVE_TBL;
	$osgroup               = XMLGROUP_LIST_TBL;
	$osgroupinvite         = XMLGROUP_INVITE_TBL;
	$osgroupmembership     = XMLGROUP_MEMBERSHIP_TBL;
	$osgroupnotice         = XMLGROUP_NOTICE_TBL;
	$osgrouprolemembership = XMLGROUP_ROLE_MEMBER_TBL;
	$osrole                = XMLGROUP_ROLE_TBL;
	
	$groupPowers = array(
        'None' => 0,
        /// Can send invitations to groups default role
        'Invite' => 1,
        /// Can eject members from group
        'Eject' => 2,
        /// Can toggle 'Open Enrollment' and change 'Signup fee'
        'ChangeOptions' => 4,
        /// Can create new roles
        'CreateRole' => 8,
        /// Can delete existing roles
        'DeleteRole' => 16,
        /// Can change Role names, titles and descriptions
        'RoleProperties' => 32,
        /// Can assign other members to assigners role
        'AssignMemberLimited' => 64,
        /// Can assign other members to any role
        'AssignMember' => 128,
        /// Can remove members from roles
        'RemoveMember' => 256,
        /// Can assign and remove abilities in roles
        'ChangeActions' => 512,
        /// Can change group Charter, Insignia, 'Publish on the web' and which
        /// members are publicly visible in group member listings
        'ChangeIdentity' => 1024,
        /// Can buy land or deed land to group
        'LandDeed' => 2048,
        /// Can abandon group owned land to Governor Linden on mainland, or Estate owner for
        /// private estates
        'LandRelease' => 4096,
        /// Can set land for-sale information on group owned parcels
        'LandSetSale' => 8192,
        /// Can subdivide and join parcels
        'LandDivideJoin' => 16384,
        /// Can join group chat sessions
        'JoinChat' => 32768,
        /// Can toggle "Show in Find Places" and set search category
        'FindPlaces' => 65536,
        /// Can change parcel name, description, and 'Publish on web' settings
        'LandChangeIdentity' => 131072,
        /// Can set the landing point and teleport routing on group land
        'SetLandingPoint' => 262144,
        /// Can change music and media settings
        'ChangeMedia' => 524288,
        /// Can toggle 'Edit Terrain' option in Land settings
        'LandEdit' => 1048576,
        /// Can toggle various About Land > Options settings
        'LandOptions' => 2097152,
        /// Can always terraform land, even if parcel settings have it turned off
        'AllowEditLand' => 4194304,
        /// Can always fly while over group owned land
        'AllowFly' => 8388608,
        /// Can always rez objects on group owned land
        'AllowRez' => 16777216,
        /// Can always create landmarks for group owned parcels
        'AllowLandmark' => 33554432,
        /// Can use voice chat in Group Chat sessions
        'AllowVoiceChat' => 67108864,
        /// Can set home location on any group owned parcel
        'AllowSetHome' => 134217728,
        /// Can modify public access settings for group owned parcels
        'LandManageAllowed' => 268435456,
        /// Can manager parcel ban lists on group owned land
        'LandManageBanned' => 536870912,
        /// Can manage pass list sales information
        'LandManagePasses' => 1073741824,
        /// Can eject and freeze other avatars on group owned land
        'LandEjectAndFreeze' => 2147483648,
        /// Can return objects set to group
        'ReturnGroupSet' => 4294967296,
        /// Can return non-group owned/set objects
        'ReturnNonGroup' => 8589934592,
        /// Can landscape using Linden plants
        'LandGardening' => 17179869184,
        /// Can deed objects to group
        'DeedObject' => 34359738368,
        /// Can moderate group chat sessions
        'ModerateChat' => 68719476736,
        /// Can move group owned objects
        'ObjectManipulate' => 137438953472,
        /// Can set group owned objects for-sale
        'ObjectSetForSale' => 274877906944,
        /// Pay group liabilities and receive group dividends
        'Accountable' => 549755813888,
        /// Can send group notices
        'SendNotices' => 1099511627776,
        /// Can receive group notices
        'ReceiveNotices' => 2199023255552,
        /// Can create group proposals
        'StartProposal' => 4398046511104,
        /// Can vote on group proposals
        'VoteOnProposal' => 8796093022208,
        /// Can return group owned objects
        'ReturnGroupOwned' => 17592186044416
		);
	
	
    $uuidZero = "00000000-0000-0000-0000-000000000000";
    
    $groupDBCon = mysqli_connect($XMLGRP_DB_HOST, $XMLGRP_DB_USER, $XMLGRP_DB_PASS, $XMLGRP_DB_NAME);
    if (!$groupDBCon)
    {
        die('Could not connect: ' . mysqli_connect_error());
    }
	// This is filled in by secure()
	$requestingAgent = $uuidZero;
    
    function test() 
    {
        return array('name' => 'Joe','age' => 27);
    }
    // Use a common signature for all the group functions  ->  struct foo($struct)
    $common_sig = array(array($xmlrpcStruct, $xmlrpcStruct));
    function createGroup($params)
    {
		if( is_array($error = secureRequest($params, TRUE)) )
		{
			return $error;
		}
	 
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $groupID = $params["GroupID"];
        $name = addslashes( $params["Name"] );
        $charter = addslashes( $params["Charter"] );
        $insigniaID = $params["InsigniaID"];
        $founderID = $params["FounderID"];
        $membershipFee = $params["MembershipFee"];
        $openEnrollment = $params["OpenEnrollment"];
        $showInList = $params["ShowInList"];
        $allowPublish = $params["AllowPublish"];
        $maturePublish = $params["MaturePublish"];
        $ownerRoleID = $params["OwnerRoleID"];
        $everyonePowers = $params["EveryonePowers"];
        $ownersPowers = $params["OwnersPowers"];
        
        // Create group
        $sql = "INSERT INTO $osgroup
                (GroupID, Name, Charter, InsigniaID, FounderID, MembershipFee, OpenEnrollment, ShowInList, AllowPublish, MaturePublish, OwnerRoleID)
                VALUES
                ('$groupID','$name','$charter','$insigniaID','$founderID',$membershipFee,$openEnrollment,$showInList,$allowPublish,$maturePublish,'$ownerRoleID')";
        
        if (!mysqli_query($groupDBCon, $sql))
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        // Create Everyone Role
		// NOTE: FIXME: This is a temp fix until the libomv enum for group powers is fixed in OpenSim
		$everyonePowers = 8796495740928;
        $result = _addRoleToGroup(array('GroupID' => $groupID, 'RoleID' => $uuidZero, 'Name' => 'Everyone', 
										'Description' => 'Everyone in the group is in the everyone role.', 'Title' => "Member of $name", 'Powers' => $everyonePowers));
        if( isset($result['error']) )
        {
            return $result;
        }
        // Create Owner Role
        $result = _addRoleToGroup(array('GroupID' => $groupID, 'RoleID' => $ownerRoleID, 'Name' => 'Owners', 
										'Description' => "Owners of $name", 'Title' => "Owner of $name", 'Powers' => $ownersPowers));
        if( isset($result['error']) )
        {
            return $result;
        }
        // Add founder to group, will automatically place them in the Everyone Role, also places them in specified Owner Role
        $result = _addAgentToGroup(array('AgentID' => $founderID, 'GroupID' => $groupID, 'RoleID' => $ownerRoleID));
        if( isset($result['error']) )
        {
            return $result;
        }
        
        // Select the owner's role for the founder
        $result = _setAgentGroupSelectedRole(array('AgentID' => $founderID, 'RoleID' => $ownerRoleID, 'GroupID' => $groupID));
        if( isset($result['error']) )
        {
            return $result;
        }
        
        // Set the new group as the founder's active group
        $result = _setAgentActiveGroup(array('AgentID' => $founderID, 'GroupID' => $groupID));
        if( isset($result['error']) )
        {
            return $result;
        }
        
        
        return getGroup(array("GroupID"=>$groupID));
    }
    
	// Private method, does not include security, to only be called from places that have already verified security
    function _addRoleToGroup($params)
    {
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $groupID = $params['GroupID'];
        $roleID  = $params['RoleID'];
        $name    = addslashes( $params['Name'] );
        $desc    = addslashes( $params['Description'] );
        $title   = addslashes( $params['Title'] );
        $powers  = $params['Powers'];
        
        $sql = " INSERT INTO $osrole (GroupID, RoleID, Name, Description, Title, Powers) VALUES "
              ." ('$groupID', '$roleID', '$name', '$desc', '$title', $powers)";
        if (!mysqli_query($groupDBCon, $sql))
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon)
                       , 'method' => 'addRoleToGroup'
                       , 'params' => var_export($params, TRUE));
        }
        
        return array("success" => "true");
    }
	
	
    function addRoleToGroup($params)
    {
		if( is_array($error = secureRequest($params, TRUE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
        $groupID = $params['GroupID'];
        
		// Verify the requesting agent has permission
		if( is_array($error = checkGroupPermission($groupID, $groupPowers['CreateRole'])) )
		{
			return $error;
		}
		return _addRoleToGroup($params);
    }
    
    function updateGroupRole($params)
    {
		if( is_array($error = secureRequest($params, TRUE)) )
		{
			return $error;
		}
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $groupID = $params['GroupID'];
        $roleID  = $params['RoleID'];
        $name    = addslashes( $params['Name'] );
        $desc    = addslashes( $params['Description'] );
        $title   = addslashes( $params['Title'] );
        $powers  = $params['Powers'];
        
		// Verify the requesting agent has permission
		if( is_array($error = checkGroupPermission($groupID, $groupPowers['RoleProperties'])) )
		{
			return $error;
		}
		
		
        $sql = " UPDATE $osrole SET RoleID = '$roleID' ";
        if( isset($params['Name']) )
        {
            $sql .= ", Name = '$name'";
        }
        if( isset($params['Description']) )
        {
            $sql .= ", Description = '$desc'";
        }
        if( isset($params['Title']) )
        {
            $sql .= ", Title = '$title'";
        }
        if( isset($params['Powers']) )
        {
            $sql .= ", Powers = $powers";
        }
        
        $sql .= " WHERE GroupID = '$groupID' AND RoleID = '$roleID'";
        if (!mysqli_query($groupDBCon, $sql))
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        return array("success" => "true");
    }
    
    function removeRoleFromGroup($params)
    {
		if( is_array($error = secureRequest($params, TRUE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $groupID = $params['GroupID'];
        $roleID  = $params['RoleID'];
        
		if( is_array($error = checkGroupPermission($groupID, $groupPowers['RoleProperties'])) )
		{
			return $error;
		}
		
        /// 1. Remove all members from Role
        /// 2. Set selected Role to uuidZero for anyone that had the role selected
        /// 3. Delete roll
        
        $sql = "DELETE FROM $osgrouprolemembership WHERE GroupID = '$groupID' AND RoleID = '$roleID'";
        if (!mysqli_query($groupDBCon, $sql))
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        $sql = "UPDATE $osgroupmembership SET SelectedRoleID = '$uuidZero' WHERE GroupID = '$groupID' AND SelectedRoleID = '$roleID'";
        if (!mysqli_query($groupDBCon, $sql))
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        $sql = "DELETE FROM $osrole WHERE GroupID = '$groupID' AND RoleID = '$roleID'";
        if (!mysqli_query($groupDBCon, $sql))
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        return array("success" => "true");
    }
    
    function getGroup($params)
    {
		if( is_array($error = secureRequest($params, FALSE)) )
		{
			return $error;
		}
		
		return _getGroup($params);
	}
    function _getGroup($params)
    {
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $sql = " SELECT $osgroup.GroupID, $osgroup.Name, Charter, InsigniaID, FounderID, MembershipFee, OpenEnrollment, ShowInList, AllowPublish, MaturePublish, OwnerRoleID"
              ." , count($osrole.RoleID) as GroupRolesCount, count($osgroupmembership.AgentID) as GroupMembershipCount "
              ." FROM $osgroup "
              ." LEFT JOIN $osrole ON ($osgroup.GroupID = $osrole.GroupID)"
              ." LEFT JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID)"
              ." WHERE ";
        if( isset($params['GroupID']) )
        {
            $sql .= "$osgroup.GroupID = '".$params['GroupID']."'";
            
        } else if( isset($params['Name']) ) 
        {
            $sql .= "$osgroup.Name = '".addslashes($params['Name'])."'";
        } else {
            return array("error" => "Must specify GroupID or Name");
        }
        
        $sql .= " GROUP BY $osgroup.GroupID, $osgroup.name, charter, insigniaID, founderID, membershipFee, openEnrollment, showInList, allowPublish, maturePublish, ownerRoleID";
        
        $result = mysqli_query($groupDBCon, $sql);
        
        if (!$result) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        if (mysqli_num_rows($result) == 0) 
        {
            return array('succeed' => 'false', 'error' => 'Group Not Found', 'params' => var_export($params, TRUE), 'sql' => $sql);
        }
        
        return mysqli_fetch_assoc($result);
    }        
    
    function updateGroup($params)
    {
		if( is_array($error = secureRequest($params, TRUE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $groupID = $params["GroupID"];
        $charter = addslashes( $params["Charter"] );
        $insigniaID = $params["InsigniaID"];
        $membershipFee = $params["MembershipFee"];
        $openEnrollment = $params["OpenEnrollment"];
        $showInList = $params["ShowInList"];
        $allowPublish = $params["AllowPublish"];
        $maturePublish = $params["MaturePublish"];
        
		if( is_array($error = checkGroupPermission($groupID, $groupPowers['ChangeOptions'])) )
		{
			return $error;
		}
		
        // Create group
        $sql = "UPDATE $osgroup
                SET
                    Charter = '$charter'
                    , InsigniaID = '$insigniaID'
                    , MembershipFee = $membershipFee
                    , OpenEnrollment= $openEnrollment
                    , ShowInList    = $showInList
                    , AllowPublish  = $allowPublish
                    , MaturePublish = $maturePublish
                WHERE
                    GroupID = '$groupID'";
        
        if (!mysqli_query($groupDBCon, $sql))
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        return array('success' => 'true');
    }
    
    function findGroups($params)
    {
		if( is_array($error = secureRequest($params, FALSE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $search = addslashes( $params['Search'] );
        
		// FULLTEXT indexes is not supported in InnoDB :(
        $sql = " SELECT $osgroup.GroupID, $osgroup.Name, count($osgroupmembership.AgentID) as Members "
              ." FROM $osgroup LEFT JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID) "
              ." WHERE "
	//		  ." ( MATCH ($osgroup.name) AGAINST ('$search' IN BOOLEAN MODE)"
    //          ."   OR $osgroup.name LIKE '%$search%'"
    //          ."   OR $osgroup.name REGEXP '$search'"
	//		  ." ) AND ShowInList = 1" 
              ." (    $osgroup.name LIKE '%$search%'"
              ."   OR $osgroup.name REGEXP '$search'"
			  ." ) AND ShowInList = 1" 
              ." GROUP BY $osgroup.GroupID, $osgroup.Name";
        
        $result = mysqli_query($groupDBCon, $sql);
        
        if (!$result) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        if( mysqli_num_rows($result) == 0 )
        {
            return array('succeed' => 'false', 'error' => 'No groups found.', 'params' => var_export($params, TRUE), 'sql' => $sql);
        }
        
        $results = array();
        while ($row = mysqli_fetch_assoc($result)) 
        {
            $groupID = $row['GroupID'];
            $results[$groupID] = $row;
        }
        
        return array('results' => $results, 'success' => TRUE);
    }
    
    function _setAgentActiveGroup($params)
    {
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
		$agentID = $params['AgentID'];
		$groupID = $params['GroupID'];
		
        $sql = " UPDATE $osagent "
              ." SET ActiveGroupID = '$groupID'"
              ." WHERE AgentID = '$agentID'";
    
        if (!mysqli_query($groupDBCon, $sql))
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        if( mysqli_affected_rows($groupDBCon) == 0 )
        {
            $sql = " INSERT INTO $osagent (ActiveGroupID, AgentID) VALUES "
                  ." ('$groupID', '$agentID')";
        
            if (!mysqli_query($groupDBCon, $sql))
            {
                return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
            }
        }
    
        return array("success" => "true");
    }
    function setAgentActiveGroup($params)
    {
		if( is_array($error = secureRequest($params, TRUE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		$agentID = $params['AgentID'];
		$groupID = $params['GroupID'];
		
		if( isset($requestingAgent) && ($requestingAgent != $uuidZero) && ($requestingAgent != $agentID) )
		{
            return array('error' => "Agent can only change their own Selected Group Role", 'params' => var_export($params, TRUE));
		}
		
		return _setAgentActiveGroup($params);
    }
    
    function addAgentToGroup($params)
    {
		if( is_array($error = secureRequest($params, TRUE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $groupID = $params["GroupID"];
        $agentID = $params["AgentID"];
		
		if( is_array($error = checkGroupPermission($groupID, $groupPowers['AssignMember'])) )
		{
			// If they don't have direct permission, check to see if the group is marked for open enrollment
			$groupInfo = _getGroup( array ('GroupID'=>$groupID) );
			
			if( isset($groupInfo['error']))
			{
				return $groupInfo;
			}
			if($groupInfo['OpenEnrollment'] != 1)
			{
				// Group is not open enrollment, check if the specified agentid has an invite
		        $sql = " SELECT GroupID, RoleID, AgentID FROM $osgroupinvite"
		              ." WHERE $osgroupinvite.AgentID = '$agentID' AND $osgroupinvite.GroupID = '$groupID'";
		              
		        $results = mysqli_query($groupDBCon, $sql);
		        if (!$results) 
		        {
		            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
		        }
		        
		        if( mysqli_num_rows($results) == 1 )
		        {
					// if there is an invite, make sure we're adding the user to the role specified in the invite
		            $inviteInfo = mysqli_fetch_assoc($results);
					$params['RoleID'] = $inviteInfo['RoleID'];
		        } else {
					// Not openenrollment, not invited, return permission denied error
					return $error;
				}
				
			} 
		}
		return _addAgentToGroup($params);
    }
    
	// Private method, does not include security, to only be called from places that have already verified security
    function _addAgentToGroup($params)
    {
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $agentID = $params["AgentID"];
        $groupID = $params["GroupID"];
        
        $roleID  = $uuidZero;
        if( isset($params["RoleID"]) )
        {
            $roleID = $params["RoleID"];
        }
    
        // Check if agent already a member
        $sql = " SELECT count(AgentID) as isMember FROM $osgroupmembership WHERE AgentID = '$agentID' AND GroupID = '$groupID'";
        $result = mysqli_query($groupDBCon, $sql);
        if (!$result)
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        // If not a member, add membership, select role (defaults to uuidZero, or everyone role)
        //if( mysql_result($result, 0) == 0 )
        $row = mysqli_fetch_row($result);
        if(is_array($row) and $row[0]==0)
        {
            $sql = " INSERT INTO $osgroupmembership (GroupID, AgentID, Contribution, ListInProfile, AcceptNotices, SelectedRoleID) VALUES "
                  ."('$groupID','$agentID', 0, 1, 1,'$roleID')";
        
            if (!mysqli_query($groupDBCon, $sql))
            {
                return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
            }
        }
        
        // Make sure they're in the Everyone role
        $result = _addAgentToGroupRole(array("GroupID" => $groupID, "RoleID" => $uuidZero, "AgentID" => $agentID));
        if( isset($result['error']) )
        {
            return $result;
        }
        
        // Make sure they're in specified role, if they were invited
        if( $roleID != $uuidZero )
        {
            $result = _addAgentToGroupRole(array("GroupID" => $groupID, "RoleID" => $roleID, "AgentID" => $agentID));
            if( isset($result['error']) )
            {
                return $result;
            }
        }
        
        return array("success" => "true");
    }
    
    function removeAgentFromGroup($params)
    {
		if( is_array($error = secureRequest($params, TRUE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $agentID = $params["AgentID"];
        $groupID = $params["GroupID"];
		if( is_array($error = checkGroupPermission($groupID, $groupPowers['RemoveMember'])) )
		{
			return $error;
		}
		
        // 1. If group is agent's active group, change active group to uuidZero
        // 2. Remove Agent from group (osgroupmembership)
        // 3. Remove Agent from all of the groups roles (osgrouprolemembership)
        
        $sql = " UPDATE $osagent "
              ." SET ActiveGroupID = '$uuidZero'"
              ." WHERE AgentID = '$agentID' AND ActiveGroupID = '$groupID'";
        if (!mysqli_query($groupDBCon, $sql))
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        $sql = " DELETE FROM $osgroupmembership "
              ." WHERE AgentID = '$agentID' AND GroupID = '$groupID'";
        if (!mysqli_query($groupDBCon, $sql))
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        $sql = " DELETE FROM $osgrouprolemembership "
              ." WHERE AgentID = '$agentID' AND GroupID = '$groupID'";
        if (!mysqli_query($groupDBCon, $sql))
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        return array("success" => "true");
    }
    
    function _addAgentToGroupRole($params)
    {
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $agentID = $params["AgentID"];
        $groupID = $params["GroupID"];
        $roleID  = $params["RoleID"];
    
        // Check if agent already a member
        $sql = " SELECT count(AgentID) as isMember FROM $osgrouprolemembership WHERE AgentID = '$agentID' AND RoleID = '$roleID' AND GroupID = '$groupID'";
        $result = mysqli_query($groupDBCon, $sql);
        if (!$result)
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
    
        //if( mysql_result($result, 0) == 0 )
        $row = mysqli_fetch_row($result);
        if(is_array($row) and $row[0]==0)
        {
            $sql = " INSERT INTO $osgrouprolemembership (GroupID, RoleID, AgentID) VALUES "
                  ."('$groupID', '$roleID', '$agentID')";
        
            if (!mysqli_query($groupDBCon, $sql))
            {
                return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
            }
        }
    
        return array("success" => "true");
    }
    
    function addAgentToGroupRole($params)
    {
		if( is_array($error = secureRequest($params, TRUE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $agentID = $params["AgentID"];
        $groupID = $params["GroupID"];
        $roleID  = $params["RoleID"];
    
		// Check if being assigned to Owners role, assignments to an owners role can only be requested by owners.
		$sql = " SELECT OwnerRoleID, AgentID "
		      ." FROM $osgroup LEFT JOIN $osgrouprolemembership ON ($osgroup.GroupID = $osgrouprolemembership.GroupID AND $osgroup.OwnerRoleID = $osgrouprolemembership.RoleID) "
			  ." WHERE $osgrouprolemembership.AgentID = '$agentID' AND $osgroup.GroupID = '$groupID'";
			  
		$results = mysqli_query($groupDBCon, $sql);
		if (!$results) 
		{
			return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
		}
		
        if( mysqli_num_rows($results) != 0 )
        {
			$ownerRoleInfo = mysqli_fetch_assoc($results);
			if( ($ownerRoleInfo['OwnerRoleID'] == $roleID) && ($ownerRoleInfo['AgentID'] != $requestingAgent) )
			{
				return array('error' => "Requesting agent $requestingAgent is not a member of the Owners Role and cannot add members to the owners role.", 
							 'params' => var_export($params, TRUE));
			}
		}
	
		if( is_array($error = checkGroupPermission($groupID, $groupPowers['AssignMember'])) )
		{
			return $error;
		}
	
		return _addAgentToGroupRole($params);
    }
    
    function removeAgentFromGroupRole($params)
    {
		if( is_array($error = secureRequest($params, TRUE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $agentID = $params["AgentID"];
        $groupID = $params["GroupID"];
        $roleID  = $params["RoleID"];
		if( is_array($error = checkGroupPermission($groupID, $groupPowers['AssignMember'])) )
		{
			return $error;
		}
		
        // If agent has this role selected, change their selection to everyone (uuidZero) role
        $sql = " UPDATE $osgroupmembership SET SelectedRoleID = '$uuidZero' WHERE AgentID = '$agentID' AND GroupID = '$groupID' AND SelectedRoleID = '$roleID'";
        $result = mysqli_query($groupDBCon, $sql);
        if (!$result)
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        $sql = " DELETE FROM $osgrouprolemembership WHERE AgentID = '$agentID' AND GroupID = '$groupID' AND RoleID = '$roleID'";
    
        if (!mysqli_query($groupDBCon, $sql))
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        return array("success" => "true");
    }
    
    function _setAgentGroupSelectedRole($params)
    {
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $agentID = $params["AgentID"];
        $groupID = $params["GroupID"];
        $roleID = $params["RoleID"];
    
        $sql = " UPDATE $osgroupmembership SET SelectedRoleID = '$roleID' WHERE AgentID = '$agentID' AND GroupID = '$groupID'";
        $result = mysqli_query($groupDBCon, $sql);
        if (!$result)
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
    
        return array('success' => 'true');
    }
    function setAgentGroupSelectedRole($params)
    {
		if( is_array($error = secureRequest($params, TRUE)) )
		{
			return $error;
		}
		
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
        $agentID = $params["AgentID"];
        $groupID = $params["GroupID"];
        $roleID = $params["RoleID"];
    
		if( isset($requestingAgent) && ($requestingAgent != $uuidZero) && ($requestingAgent != $agentID) )
		{
            return array('error' => "Agent can only change their own Selected Group Role", 'params' => var_export($params, TRUE));
		}
	
        return _setAgentGroupSelectedRole($params);
    }
	
    function getAgentGroupMembership($params)
    {
		if( is_array($error = secureRequest($params, FALSE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $groupID = $params['GroupID'];
        $agentID = $params['AgentID'];
        
        $sql = " SELECT $osgroup.GroupID, $osgroup.Name as GroupName, $osgroup.Charter, $osgroup.InsigniaID, $osgroup.FounderID"
			  ." , $osgroup.MembershipFee, $osgroup.OpenEnrollment, $osgroup.ShowInList, $osgroup.AllowPublish, $osgroup.MaturePublish"
              ." , $osgroupmembership.Contribution, $osgroupmembership.ListInProfile, $osgroupmembership.AcceptNotices"
              ." , $osgroupmembership.SelectedRoleID, $osrole.Title"
              ." , $osagent.ActiveGroupID "
              ." FROM $osgroup JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID)"
              ."               JOIN $osrole ON ($osgroupmembership.SelectedRoleID = $osrole.RoleID AND $osgroupmembership.GroupID = $osrole.GroupID)"
              ."               JOIN $osagent ON ($osagent.AgentID = $osgroupmembership.AgentID)"
              ." WHERE $osgroup.GroupID = '$groupID' AND $osgroupmembership.AgentID = '$agentID'";
        
        $groupmembershipResult = mysqli_query($groupDBCon, $sql);
        if (!$groupmembershipResult) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        if( mysqli_num_rows($groupmembershipResult) == 0 )
        {
            return array('succeed' => 'false', 'error' => 'None Found', 'params' => var_export($params, TRUE), 'sql' => $sql);
        }
        
        $groupMembershipInfo = mysqli_fetch_assoc($groupmembershipResult);
        
        $sql = " SELECT BIT_OR($osrole.Powers) AS GroupPowers"
              ." FROM $osgrouprolemembership JOIN $osrole ON ($osgrouprolemembership.GroupID = $osrole.GroupID AND $osgrouprolemembership.RoleID = $osrole.RoleID)"
              ." WHERE $osgrouprolemembership.GroupID = '$groupID' AND $osgrouprolemembership.AgentID = '$agentID'";
        $groupPowersResult = mysqli_query($groupDBCon, $sql);
        if (!$groupPowersResult) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        $groupPowersInfo = mysqli_fetch_assoc($groupPowersResult);
        
        return array_merge($groupMembershipInfo, $groupPowersInfo);
    }
    function getAgentGroupMemberships($params)
    {
		if( is_array($error = secureRequest($params, FALSE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $agentID = $params['AgentID'];
        
        $sql = " SELECT $osgroup.GroupID, $osgroup.Name as GroupName, $osgroup.Charter, $osgroup.InsigniaID, $osgroup.FounderID"
			  ." , $osgroup.MembershipFee, $osgroup.OpenEnrollment, $osgroup.ShowInList, $osgroup.AllowPublish, $osgroup.MaturePublish"
              ." , $osgroupmembership.Contribution, $osgroupmembership.ListInProfile, $osgroupmembership.AcceptNotices"
              ." , $osgroupmembership.SelectedRoleID, $osrole.Title"
              ." , IFNULL($osagent.ActiveGroupID, '$uuidZero') AS ActiveGroupID"
              ." FROM $osgroup JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID)"
              ."              JOIN $osrole ON ($osgroupmembership.SelectedRoleID = $osrole.RoleID AND $osgroupmembership.GroupID = $osrole.GroupID)"
              ."         LEFT JOIN $osagent ON ($osagent.AgentID = $osgroupmembership.AgentID)"
              ." WHERE $osgroupmembership.AgentID = '$agentID'";
        
        $groupmembershipResults = mysqli_query($groupDBCon, $sql);
        if (!$groupmembershipResults) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        if( mysqli_num_rows($groupmembershipResults) == 0 )
        {
            return array('succeed' => 'false', 'error' => 'No Memberships', 'params' => var_export($params, TRUE), 'sql' => $sql);
            
        }
        
        $groupResults = array();
        while($groupMembershipInfo = mysqli_fetch_assoc($groupmembershipResults))
        {
            $groupID = $groupMembershipInfo['GroupID'];
            $sql = " SELECT BIT_OR($osrole.Powers) AS GroupPowers"
                  ." FROM $osgrouprolemembership JOIN $osrole ON ($osgrouprolemembership.GroupID = $osrole.GroupID AND $osgrouprolemembership.RoleID = $osrole.RoleID)"
                  ." WHERE $osgrouprolemembership.GroupID = '$groupID' AND $osgrouprolemembership.AgentID = '$agentID'";
            $groupPowersResult = mysqli_query($groupDBCon, $sql);
            if (!$groupPowersResult) 
            {
                return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
            }
            $groupPowersInfo = mysqli_fetch_assoc($groupPowersResult);
            $groupResults[$groupID] = array_merge($groupMembershipInfo, $groupPowersInfo);
        }
        
        return $groupResults;
    }
    
    function getGroupMembers($params)
    {
		if( is_array($error = secureRequest($params, FALSE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $groupID = $params['GroupID'];
        
        $sql = " SELECT $osgroupmembership.AgentID"
              ." , $osgroupmembership.Contribution, $osgroupmembership.ListInProfile, $osgroupmembership.AcceptNotices"
              ." , $osgroupmembership.SelectedRoleID, $osrole.Title"
              ." , CASE WHEN OwnerRoleMembership.AgentID IS NOT NULL THEN 1 ELSE 0 END AS IsOwner"
              ." FROM $osgroup JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID)"
              ."               JOIN $osrole ON ($osgroupmembership.SelectedRoleID = $osrole.RoleID AND $osgroupmembership.GroupID = $osrole.GroupID)"
              ."               JOIN $osrole AS OwnerRole ON ($osgroup.OwnerRoleID  = OwnerRole.RoleID AND $osgroup.GroupID  = OwnerRole.GroupID)"
              ."          LEFT JOIN $osgrouprolemembership AS OwnerRoleMembership ON ($osgroup.OwnerRoleID       = OwnerRoleMembership.RoleID 
                                                                               AND ($osgroup.GroupID           = OwnerRoleMembership.GroupID)
                                                                               AND ($osgroupmembership.AgentID = OwnerRoleMembership.AgentID))"
              ." WHERE $osgroup.GroupID = '$groupID'";
        
        $groupmemberResults = mysqli_query($groupDBCon, $sql);
        if (!$groupmemberResults) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        if (mysqli_num_rows($groupmemberResults) == 0) 
        {
            return array('succeed' => 'false', 'error' => 'No Group Members found', 'params' => var_export($params, TRUE), 'sql' => $sql);
        }
        
        $memberResults = array();
        while($memberInfo = mysqli_fetch_assoc($groupmemberResults))
        {
            $agentID = $memberInfo['AgentID'];
            $sql = " SELECT BIT_OR($osrole.Powers) AS AgentPowers"
                  ." FROM $osgrouprolemembership JOIN $osrole ON ($osgrouprolemembership.GroupID = $osrole.GroupID AND $osgrouprolemembership.RoleID = $osrole.RoleID)"
                  ." WHERE $osgrouprolemembership.GroupID = '$groupID' AND $osgrouprolemembership.AgentID = '$agentID'";
            $memberPowersResult = mysqli_query($groupDBCon, $sql);
            if (!$memberPowersResult) 
            {
                return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
            }
            
            if (mysqli_num_rows($groupmemberResults) == 0) 
            {
                $memberResults[$agentID] = array_merge($memberInfo, array('AgentPowers' => 0));
            } else {
                $memberPowersInfo = mysqli_fetch_assoc($memberPowersResult);
                $memberResults[$agentID] = array_merge($memberInfo, $memberPowersInfo);
            }
        }
        
        return $memberResults;
    }
    
    
    function getAgentActiveMembership($params)
    {
		if( is_array($error = secureRequest($params, FALSE)) )
		{
			return $error;
		}
		
		secureRequest($params, FALSE);
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $agentID = $params['AgentID'];
        
        $sql = " SELECT $osgroup.GroupID, $osgroup.Name as GroupName, $osgroup.Charter, $osgroup.InsigniaID, $osgroup.FounderID"
 			  ." , $osgroup.MembershipFee, $osgroup.OpenEnrollment, $osgroup.ShowInList, $osgroup.AllowPublish, $osgroup.MaturePublish"
              ." , $osgroupmembership.Contribution, $osgroupmembership.ListInProfile, $osgroupmembership.AcceptNotices"
              ." , $osgroupmembership.SelectedRoleID, $osrole.Title"
              ." , $osagent.ActiveGroupID "
              ." FROM $osagent JOIN $osgroup ON ($osgroup.GroupID = $osagent.ActiveGroupID)"
              ."               JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID AND $osagent.AgentID = $osgroupmembership.AgentID)"
              ."               JOIN $osrole ON ($osgroupmembership.SelectedRoleID = $osrole.RoleID AND $osgroupmembership.GroupID = $osrole.GroupID)"
              ." WHERE $osagent.AgentID = '$agentID'";
        
        $groupmembershipResult = mysqli_query($groupDBCon, $sql);
        if (!$groupmembershipResult) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        if (mysqli_num_rows($groupmembershipResult) == 0) 
        {
            return array('succeed' => 'false', 'error' => 'No Active Group Specified', 'params' => var_export($params, TRUE), 'sql' => $sql);
        }
        $groupMembershipInfo = mysqli_fetch_assoc($groupmembershipResult);
        
        $groupID = $groupMembershipInfo['GroupID'];
        $sql = " SELECT BIT_OR($osrole.Powers) AS GroupPowers"
              ." FROM $osgrouprolemembership JOIN $osrole ON ($osgrouprolemembership.GroupID = $osrole.GroupID AND $osgrouprolemembership.RoleID = $osrole.RoleID)"
              ." WHERE $osgrouprolemembership.GroupID = '$groupID' AND $osgrouprolemembership.AgentID = '$agentID'";
        $groupPowersResult = mysqli_query($groupDBCon, $sql);
        if (!$groupPowersResult) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        $groupPowersInfo = mysqli_fetch_assoc($groupPowersResult);
        
        return array_merge($groupMembershipInfo, $groupPowersInfo);
    }
    
    function getAgentRoles($params=null)
    {
		if( is_array($error = secureRequest($params, FALSE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $agentID = $params['AgentID'];
        
        $sql = " SELECT "
              ." $osrole.RoleID, $osrole.GroupID, $osrole.Title, $osrole.Name, $osrole.Description, $osrole.Powers"
              ." , CASE WHEN $osgroupmembership.SelectedRoleID = $osrole.RoleID THEN 1 ELSE 0 END AS Selected"
              ." FROM $osgroupmembership JOIN $osgrouprolemembership  ON ($osgroupmembership.GroupID = $osgrouprolemembership.GroupID"
              ." AND $osgroupmembership.AgentID = $osgrouprolemembership.AgentID)"
              ."                        JOIN $osrole  ON ( $osgrouprolemembership.RoleID = $osrole.RoleID AND $osgrouprolemembership.GroupID = $osrole.GroupID)"
              ."                   LEFT JOIN $osagent ON ($osagent.AgentID = $osgroupmembership.AgentID)"
              ." WHERE $osgroupmembership.AgentID = '$agentID'";
              
        if( isset($params['GroupID']) )
        {
            $groupID = $params['GroupID'];
            $sql .= " AND $osgroupmembership.GroupID = '$groupID'";
        }
        $roleResults = mysqli_query($groupDBCon, $sql);
        if (!$roleResults) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        if( mysqli_num_rows($roleResults) == 0 )
        {
            return array('succeed' => 'false', 'error' => 'None found', 'params' => var_export($params, TRUE), 'sql' => $sql);
        }
        
        $roles = array();
        while($role = mysqli_fetch_assoc($roleResults))
        {
            $ID = $role['GroupID'].$role['RoleID'];
            $roles[$ID] = $role;
        }
        
        return $roles;
    }
    
    function getGroupRoles($params)
    {
		if( is_array($error = secureRequest($params, FALSE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $groupID = $params['GroupID'];
        
        $sql = " SELECT "
              ." $osrole.RoleID, $osrole.Name, $osrole.Title, $osrole.Description, $osrole.Powers, count($osgrouprolemembership.AgentID) as Members"
              ." FROM $osrole LEFT JOIN $osgrouprolemembership ON ($osrole.GroupID = $osgrouprolemembership.GroupID AND $osrole.RoleID = $osgrouprolemembership.RoleID)"
              ." WHERE $osrole.GroupID = '$groupID'"
              ." GROUP BY $osrole.RoleID, $osrole.Name, $osrole.Title, $osrole.Description, $osrole.Powers";
              
        $roleResults = mysqli_query($groupDBCon, $sql);
        if (!$roleResults) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        if( mysqli_num_rows($roleResults) == 0 )
        {
            return array('succeed' => 'false', 'error' => 'No roles found for group', 'params' => var_export($params, TRUE), 'sql' => $sql);
        }
        
        $roles = array();
        while($role = mysqli_fetch_assoc($roleResults))
        {
            $RoleID = $role['RoleID'];
            $roles[$RoleID] = $role;
        }
        
        return $roles;
    }
    function getGroupRoleMembers($params)
    {
		if( is_array($error = secureRequest($params, FALSE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $groupID = $params['GroupID'];
        // $roleID = $params['RoleID'];
        
        $sql = " SELECT "
              ." $osrole.RoleID, $osgrouprolemembership.AgentID"
              ." FROM $osrole JOIN $osgrouprolemembership ON ($osrole.GroupID = $osgrouprolemembership.GroupID AND $osrole.RoleID = $osgrouprolemembership.RoleID)"
              ." WHERE $osrole.GroupID = '$groupID'";
//              ." AND $osrole.RoleID = '$roleID'";
              
        $memberResults = mysqli_query($groupDBCon, $sql);
        if (!$memberResults) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        $members = array();
        while($member = mysqli_fetch_assoc($memberResults))
        {
            $Key = $member['AgentID'] . $member['RoleID'];
            $members[$Key ] = $member;
        }
        
        return $members;
    }
    
    function setAgentGroupInfo($params)
    {
		if( is_array($error = secureRequest($params, TRUE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
		
        if (isset($params['AgentID'])) {
            $agentID = $params['AgentID'];
        } else {
            $agentID = "";
        }
        if (isset($params['GroupID'])) {
            $groupID = $params['GroupID'];
        } else {
            $groupID = "";
        }
        if (isset($params['SelectedRoleID'])) {
            $roleID  = $params['SelectedRoleID'];
        } else {
            $roleID = "";
        }
        if (isset($params['AcceptNotice'])) {
            $acceptNotices  = $params['AcceptNotices'];
        } else {
            $acceptNotices = "";
        }
        if (isset($params['ListInProfile'])) {
            $listInProfile  = $params['ListInProfile'];
        } else {
            $listInProfile = "";
        }
		if( isset($requestingAgent) && ($requestingAgent != $uuidZero) && ($requestingAgent != $agentID) )
		{
            return array('error' => "Agent can only change their own group info", 'params' => var_export($params, TRUE));
		}
        $sql = " UPDATE "
              ."     $osgroupmembership"
              ." SET "
              ."    AgentID = '$agentID'";
        if( isset($params['SelectedRoleID']) )
        {
            $sql .="    , SelectedRoleID = '$roleID'";
        }
        if( isset($params['AcceptNotices']) )
        {
            $sql .="    , AcceptNotices = '$acceptNotices'";
        }
        if( isset($params['ListInProfile']) )
        {
            $sql .="    , ListInProfile = '$listInProfile'";
        }
        $sql .=" WHERE $osgroupmembership.GroupID = '$groupID' AND $osgroupmembership.AgentID = '$agentID'";
        $memberResults = mysqli_query($groupDBCon, $sql);
        if (!$memberResults) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        return array('success'=> 'true');
    }
    
    function getGroupNotices($params)
    {
		if( is_array($error = secureRequest($params, FALSE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $groupID = $params['GroupID'];
        
        $sql = " SELECT "
              ." GroupID, NoticeID, Timestamp, FromName, Subject, Message, BinaryBucket"
              ." FROM $osgroupnotice"
              ." WHERE $osgroupnotice.GroupID = '$groupID'";
              
        $results = mysqli_query($groupDBCon, $sql);
        if (!$results) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        if( mysqli_num_rows($results) == 0 )
        {
            return array('succeed' => 'false', 'error' => 'No Notices', 'params' => var_export($params, TRUE), 'sql' => $sql);
        }
        
        $notices = array();
        while($notice = mysqli_fetch_assoc($results))
        {
            $NoticeID = $notice['NoticeID'];
            $notices[$NoticeID] = $notice;
        }
        
        return $notices;
    }
    function getGroupNotice($params)
    {
		if( is_array($error = secureRequest($params, FALSE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $noticeID = $params['NoticeID'];
        
        $sql = " SELECT "
              ." GroupID, NoticeID, Timestamp, FromName, Subject, Message, BinaryBucket"
              ." FROM $osgroupnotice"
              ." WHERE $osgroupnotice.NoticeID = '$noticeID'";
              
        $results = mysqli_query($groupDBCon, $sql);
        if (!$results) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        if( mysqli_num_rows($results) == 0 )
        {
            return array('succeed' => 'false', 'error' => 'Group Notice Not Found', 'params' => var_export($params, TRUE), 'sql' => $sql);
        }
        
        return mysqli_fetch_assoc($results);
    }
    
    function addGroupNotice($params)
    {
		if( is_array($error = secureRequest($params, TRUE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $groupID  = $params['GroupID'];
        $noticeID = $params['NoticeID'];
        $fromName = addslashes($params['FromName']);
        $subject  = addslashes($params['Subject']);
        $binaryBucket = $params['BinaryBucket'];
        $message      = addslashes($params['Message']);
        $timeStamp    = $params['TimeStamp'];
		if( is_array($error = checkGroupPermission($groupID, $groupPowers['SendNotices'])) )
		{
			return $error;
		}
        
        $sql = " INSERT INTO $osgroupnotice"
              ." (GroupID, NoticeID, Timestamp, FromName, Subject, Message, BinaryBucket)"
              ." VALUES "
              ." ('$groupID', '$noticeID', $timeStamp, '$fromName', '$subject', '$message', '$binaryBucket')";
              
        $results = mysqli_query($groupDBCon, $sql);
        if (!$results) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        return array('success' => 'true');
    }
    
    function addAgentToGroupInvite($params)
    {
		if( is_array($error = secureRequest($params, TRUE)) )
		{
			return $error;
		}
		
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $inviteID = $params['InviteID'];
        $groupID  = $params['GroupID'];
        $roleID   = $params['RoleID'];
        $agentID  = $params['AgentID'];
        //$tmStamp  = time();
        $tmStamp  = 0;
		if( is_array($error = checkGroupPermission($groupID, $groupPowers['AssignMember'])) )
		{
			return $error;
		}
		
        // Remove any existing invites for this agent to this group
        $sql = " DELETE FROM $osgroupinvite"
              ." WHERE $osgroupinvite.AgentID = '$agentID' AND $osgroupinvite.GroupID = '$groupID'";
              
        $results = mysqli_query($groupDBCon, $sql);
        if (!$results) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        // Add new invite for this agent to this group for the specifide role
        $sql = " INSERT INTO $osgroupinvite"
              ." (InviteID, GroupID, RoleID, AgentID, tmstamp) VALUES ('$inviteID', '$groupID', '$roleID', '$agentID', '$tmStamp')";
              
        $results = mysqli_query($groupDBCon, $sql);
        if (!$results) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        return array('success' => 'true');
    }
    function getAgentToGroupInvite($params)
    {
		if( is_array($error = secureRequest($params, FALSE)) )
		{
			return $error;
		}
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $inviteID = $params['InviteID'];
        
        $sql = " SELECT GroupID, RoleID, AgentID FROM $osgroupinvite"
              ." WHERE $osgroupinvite.InviteID = '$inviteID'";
              
        $results = mysqli_query($groupDBCon, $sql);
        if (!$results) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        if( mysqli_num_rows($results) == 1 )
        {
            $inviteInfo = mysqli_fetch_assoc($results);
            $groupID  = $inviteInfo['GroupID'];
            $roleID   = $inviteInfo['RoleID'];
            $agentID  = $inviteInfo['AgentID'];
        
            return array('success' => 'true', 'GroupID'=>$groupID, 'RoleID'=>$roleID, 'AgentID'=>$agentID);
        } else {
            return array('succeed' => 'false', 'error' => 'Invitation not found', 'params' => var_export($params, TRUE), 'sql' => $sql);
        }
    }
    
    function removeAgentToGroupInvite($params)
    {
		if( is_array($error = secureRequest($params, TRUE)) )
		{
			return $error;
		}
	
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
        $inviteID = $params['InviteID'];
        
        $sql = " DELETE FROM $osgroupinvite"
              ." WHERE $osgroupinvite.InviteID = '$inviteID'";
              
        $results = mysqli_query($groupDBCon, $sql);
        if (!$results) 
        {
            return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
        }
        
        return array('success' => 'true');
    }
    
	function secureRequest($params, $write = FALSE)
	{
		global 	$GroupWriteKey, $GroupReadKey, $VerifiedReadKey, $VerifiedWriteKey, $GroupRequireAgentAuthForWrite, $requestingAgent;
		
		if( isset($GroupReadKey) && ($GroupReadKey != '') && (!isset($VerifiedReadKey) || ($VerifiedReadKey !== TRUE)) )
		{
			if( !isset($params['ReadKey']) || ($params['ReadKey'] != $GroupReadKey ) )
			{
				return array('error' => "Invalid (or No) Read Key Specified", 'params' => var_export($params, TRUE));
			} else {
				$VerifiedReadKey = TRUE;
			}
		}
		
		if( ($write == TRUE) && isset($GroupWriteKey) && ($GroupWriteKey != '') && (!isset($VerifiedWriteKey) || ($VerifiedWriteKey !== TRUE)) )
		{
			if( !isset($params['WriteKey']) || ($params['WriteKey'] != $GroupWriteKey ) )
			{
				return array('error' => "Invalid (or No) Write Key Specified", 'params' => var_export($params, TRUE));
			} else {
				$VerifiedWriteKey = TRUE;
			}
		}
		
		if( ($write == TRUE) && isset($GroupRequireAgentAuthForWrite) && ($GroupRequireAgentAuthForWrite == TRUE) )
		{
			// Note: my brain can't do boolean logic this morning, so just putting this here instead of integrating with line above.
			// If the write key has already been verified for this request, don't check it again.  
			// This comes into play with methods that call other methods, such as CreateGroup() which calls Addrole()
			if( isset($VerifiedWriteKey) && ($VerifiedWriteKey !== TRUE))
			{
				return TRUE;
			}
		
			if( !isset($params['RequestingAgentID']) 
			 || !isset($params['RequestingAgentUserService'])
			 || !isset($params['RequestingSessionID']) 
			 )
			{
				return array('error' => "Requesting AgentID and SessionID must be specified", 'params' => var_export($params, TRUE));
			}
			$requestingAgent = $params['RequestingAgentID'];
			
			// NOTE: an AgentID and SessionID of $uuidZero will likely be a region making a request, that is not tied to a specific agent making the request.
			
			$client = new xmlrpc_client($params['RequestingAgentUserService']);
			$client->return_type = 'phpvals';
			
			$verifyParams = new xmlrpcval(array('avatar_uuid' => new xmlrpcval($params['RequestingAgentID'], 'string')
											   ,'session_id'  => new xmlrpcval($params['RequestingSessionID'], 'string')), 'struct');
			$message = new xmlrpcmsg("check_auth_session", array($verifyParams));
			$resp = $client->send($message, 5);
			if ($resp->faultCode()) 
			{
				return array('error' => "Error validating AgentID and SessionID"
				           , 'xmlrpcerror'=> $resp->faultString()
						   , 'params' => var_export($params, TRUE));
			} 
			
			$verifyReturn = $resp->value();
			
			if( !isset($verifyReturn['auth_session']) || ($verifyReturn['auth_session'] != 'TRUE') )
			{
				return array('error' => "UserService.check_auth_session() did not return TRUE"
						   , 'userservice' => var_export($verifyReturn, TRUE)
						   , 'params' => var_export($params, TRUE));
				
			}
		}
		
		return TRUE;
	}
	function checkGroupPermission($GroupID, $Permission)
	{
        global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
		
		// If it isn't set to true, then always return true, otherwise verify they have perms
		if( !isset($GroupEnforceGroupPerms) || ($GroupEnforceGroupPerms != TRUE) )
		{
			return true;
		}
		
		if( !isset($requestingAgent) || ($requestingAgent == $uuidZero) )
		{
            return array('error' => 'Requesting agent was either not specified or not validated.'
                       , 'params' => var_export($params, TRUE));
		}
		
		$params = array('AgentID' => $requestingAgent, 'GroupID' => $GroupID);
		$reqAgentMembership = getAgentGroupMembership($params);
		if( isset($reqAgentMembership['error'] ) )
		{
            return array('error' => 'Could not get agent membership for group'
                       , 'params' => var_export($params, TRUE)
					   , 'nestederror' => $reqAgentMembership['error']);
		}
		if( $reqAgentMembership['GroupPowers'] & $Permission != $Permission )
		{
            return array('error' => 'Agent does not have group power to $Permission'
                       , 'params' => var_export($params, TRUE));
		}
	}
    $s = new xmlrpc_server(array(
                            "test"                              => array("function" => "test")
                          , "groups.createGroup"                => array("function" => "createGroup", "signature" => $common_sig)
                          , "groups.updateGroup"                => array("function" => "updateGroup", "signature" => $common_sig)
                          , "groups.getGroup"                   => array("function" => "getGroup", "signature" => $common_sig)
                          , "groups.findGroups"                 => array("function" => "findGroups", "signature" => $common_sig)
                          , "groups.getGroupRoles"              => array("function" => "getGroupRoles", "signature" => $common_sig)
                          , "groups.addRoleToGroup"             => array("function" => "addRoleToGroup", "signature" => $common_sig)
                          , "groups.removeRoleFromGroup"        => array("function" => "removeRoleFromGroup", "signature" => $common_sig)
                          , "groups.updateGroupRole"            => array("function" => "updateGroupRole", "signature" => $common_sig)
                          , "groups.getGroupRoleMembers"        => array("function" => "getGroupRoleMembers", "signature" => $common_sig)
                          
                          , "groups.setAgentGroupSelectedRole"  => array("function" => "setAgentGroupSelectedRole", "signature" => $common_sig)
                          , "groups.addAgentToGroupRole"        => array("function" => "addAgentToGroupRole", "signature" => $common_sig)
                          , "groups.removeAgentFromGroupRole"   => array("function" => "removeAgentFromGroupRole", "signature" => $common_sig)
                          
                          , "groups.getGroupMembers"            => array("function" => "getGroupMembers", "signature" => $common_sig)
                          , "groups.addAgentToGroup"            => array("function" => "addAgentToGroup", "signature" => $common_sig)
                          , "groups.removeAgentFromGroup"       => array("function" => "removeAgentFromGroup", "signature" => $common_sig)
                          , "groups.setAgentGroupInfo"          => array("function" => "setAgentGroupInfo", "signature" => $common_sig)
                          , "groups.addAgentToGroupInvite"      => array("function" => "addAgentToGroupInvite", "signature" => $common_sig)
                          , "groups.getAgentToGroupInvite"      => array("function" => "getAgentToGroupInvite", "signature" => $common_sig)
                          , "groups.removeAgentToGroupInvite"   => array("function" => "removeAgentToGroupInvite", "signature" => $common_sig)
                          
                          , "groups.setAgentActiveGroup"        => array("function" => "setAgentActiveGroup", "signature" => $common_sig)
                          , "groups.getAgentGroupMembership"    => array("function" => "getAgentGroupMembership", "signature" => $common_sig)
                          , "groups.getAgentGroupMemberships"   => array("function" => "getAgentGroupMemberships", "signature" => $common_sig)
                          , "groups.getAgentActiveMembership"   => array("function" => "getAgentActiveMembership", "signature" => $common_sig)
                          , "groups.getAgentRoles"              => array("function" => "getAgentRoles", "signature" => $common_sig)
                          
                          , "groups.getGroupNotices"            => array("function" => "getGroupNotices", "signature" => $common_sig)
                          , "groups.getGroupNotice"             => array("function" => "getGroupNotice", "signature" => $common_sig)
                          , "groups.addGroupNotice"             => array("function" => "addGroupNotice", "signature" => $common_sig)
                          
                       ), false);
    $s->functions_parameters_type = 'phpvals';
    if (isset($debugXMLRPC) && $debugXMLRPC > 0 && isset($debugXMLRPCFile) && $debugXMLRPCFile != "") 
	{
		$s->setDebug($debugXMLRPC);
    }
    $s->service();
    if (isset($debugXMLRPC) && $debugXMLRPC > 0 && isset($debugXMLRPCFile) && $debugXMLRPCFile != "") 
	{
		$f = fopen($debugXMLRPCFile,"a");
		fwrite($f,"\n----- " . date("Y-m-d H:i:s") . " -----\n");
		$debugInfo = $s->serializeDebug();
		//$debugInfo = split("\n",$debugInfo);
		$debugInfo = explode("\n",$debugInfo);
		unset($debugInfo[0]);
		unset($debugInfo[count($debugInfo) -1]);
		$debugInfo = join("\n",$debugInfo);	
		fwrite($f,base64_decode($debugInfo));
		fclose($f);
    }
    
    mysqli_close($groupDBCon);