//////////////////////////////////////////////////////////////////////
// Simple RLV-based group auto-changer.
// By Antony Fairport.
// Inspired by a question by Sally Lithanos in Builder's Brewery.
//
// Usage.
// ======
//
// This script needs RLV active in your viewer to work. You don't need
// a relay, but you do need RLV turned on. RLV support must me 2.5 or
// higher (so pretty much any modern viewer that has RLV or RLVa).
//
// Drop this script in a prim that you'll wear -- either make yourself
// a HUD or attach the prim to your avatar (perhaps even drop it
// inside somethign you wear). Then make a notecard and call it
// "Group Rules" and drop it in the object along with the string.
//
// Add lines to the notecard like this:
// 
// <region>=<group>
//
// Where <region> is a full region name and <group> is the group
// you want to auto-change to when you enter that region.
//
// There is also a special region called "*". Use this to set the
// default group to use. This group will be used when you enter
// a region you've not listed elsewhere in the notecard. If you
// don't use this your group will be set to none. An example
// might be:
//
// Shackles=Friends of Z&A
// Builders Resource=Builder's Brewery
// Fermi=Little Blue Island
// Little Blue Island=Little Blue Island
// *=Raven Park
// 
//
// Revision history.
// =================
//
// 2013-05-27
// Initial version.

//////////////////////////////////////////////////////////////////////
// Constants.
string CONFIG_FILE = "Group Rules";

//////////////////////////////////////////////////////////////////////
// Global configuration.
list g_lRegions;
list g_lGroups;
string g_sDefaultGroup;

//////////////////////////////////////////////////////////////////////
// Config reading globals.
key     g_kConfig;
integer g_iConfig;

//////////////////////////////////////////////////////////////////////
// Refresh the owner's group.
RefreshGroup()
{
    integer iRegion;
    string  sGroup;
    
    // If the region is in the region list...
    if ( ( iRegion = llListFindList( g_lRegions, [ llToLower( llGetRegionName() ) ] ) ) != -1 )
    {
        // ...pull out the group for that region.
        sGroup = llList2String( g_lGroups, iRegion );
    }
    else
    {
        // Otherwise, do we have a default?
        if ( g_sDefaultGroup )
        {
            // Yes. Use that.
            sGroup = g_sDefaultGroup;
        }
        else
        {
            // No default, so assume we'll go to "none".
            sGroup = "none";
        }
    }
    
    // Finally, force the group change.
    llOwnerSay( "Changing your group to '" + sGroup + "'" );
    llOwnerSay( "@setgroup:" + sGroup + "=force" );
}

//////////////////////////////////////////////////////////////////////
// Default state.
default
{
    //////////////////////////////////////////////////////////////////
    // State entry.
    state_entry()
    {
        // Read the configuration.
        state Configure;
    }
}

//////////////////////////////////////////////////////////////////////
// Configuration state.
state Configure
{
    //////////////////////////////////////////////////////////////////
    // State entry.
    state_entry()
    {
        // Let the user know what's happening.
        llOwnerSay( "Reading configutation..." );
        
        // Clear out the config.
        g_lRegions      = [];
        g_lGroups       = [];
        g_sDefaultGroup = "";
        
        // If it looks like we've got config...
        if ( llGetInventoryType( CONFIG_FILE ) == INVENTORY_NOTECARD )
        {
            // ...start reading it.
            g_kConfig = llGetNotecardLine( CONFIG_FILE, g_iConfig = 0 );
        }
        else
        {
            // Tell the user things aren't good.
            llOwnerSay( "No configuration found." );
        }
    }
    
    //////////////////////////////////////////////////////////////////
    // Handle data server responses.
    dataserver( key queryid, string data )
    {
        // If this is our query...
        if ( queryid == g_kConfig )
        {
            // If this isn't the end of the file...
            if ( data != EOF )
            {
                // If the line doesn't look like it's a comment, and it isn't empty...
                if ( ( llGetSubString( data, 0, 0 ) != "#" ) && ( llStringTrim( data, STRING_TRIM ) != "" ) )
                {
                    // Split the line into a list.
                    list sLineData = llParseString2List( data, [ "=" ], [] );
                    
                    // Pull out the region name
                    string sRegion = llToLower( llStringTrim( llList2String( sLineData, 0 ), STRING_TRIM ) );
                    
                    // Pull out the group name.
                    string sGroup = llStringTrim( llList2String( sLineData, 1 ), STRING_TRIM );

                    // If the region is the "wildcard" region...
                    if ( sRegion == "*" )
                    {
                        // ...then the group is the default group.
                        g_sDefaultGroup = sGroup;
                        
                        // Mention that.
                        llOwnerSay( "Default group: " + g_sDefaultGroup );
                    }
                    else
                    {
                        // ...otherwise add to the list of regions and groups.
                        g_lRegions += [ sRegion ];
                        g_lGroups  += [ sGroup ];
                        
                        // Mention what we've done.
                        llOwnerSay( sRegion + " -> " + sGroup );
                    }
                }
                
                // Read the next line.
                g_kConfig = llGetNotecardLine( CONFIG_FILE, ++g_iConfig );
            }
            else
            {
                // Config read. We're all set.
                state GroupChanger;
            }
        }
    }
}

//////////////////////////////////////////////////////////////////////
// Stage that handles group changing.
state GroupChanger
{
    //////////////////////////////////////////////////////////////////
    // State entry.
    state_entry()
    {
        // Say that we're reading.
        llOwnerSay( "Group changer active." );
        
        // Set the initial group.
        RefreshGroup();
    }
    
    //////////////////////////////////////////////////////////////////
    // Handle changes.
    changed( integer change )
    {
        // Did the region change?
        if ( change & CHANGED_REGION )
        {
            // It did. Refresh the group.
            RefreshGroup();
        }
        // Did the inventory change?
        else if ( change & CHANGED_INVENTORY )
        {
            // It did. Reload the config.
            llOwnerSay( "Rules change. Reloading..." );
            llResetScript();
        }
    }
}