/// <summary>
        /// Create a new region.
        /// <summary>
        /// <param name="request">incoming XML RPC request</param>
        /// <remarks>
        /// XmlRpcCreateRegionMethod takes the following XMLRPC
        /// parameters
        /// <list type="table">
        /// <listheader><term>parameter name</term><description>description</description></listheader>
        /// <item><term>password</term>
        ///       <description>admin password as set in Aurora.ini</description></item>
        /// <item><term>region_name</term>
        ///       <description>desired region name</description></item>
        /// <item><term>region_id</term>
        ///       <description>(optional) desired region UUID</description></item>
        /// <item><term>region_x</term>
        ///       <description>desired region X coordinate (integer)</description></item>
        /// <item><term>region_y</term>
        ///       <description>desired region Y coordinate (integer)</description></item>
        /// <item><term>estate_owner_first</term>
        ///       <description>firstname of estate owner (formerly region master)
        ///       (required if new estate is being created, optional otherwise)</description></item>
        /// <item><term>estate_owner_last</term>
        ///       <description>lastname of estate owner (formerly region master)
        ///       (required if new estate is being created, optional otherwise)</description></item>
        /// <item><term>estate_owner_uuid</term>
        ///       <description>explicit UUID to use for estate owner (optional)</description></item>
        /// <item><term>listen_ip</term>
        ///       <description>internal IP address (dotted quad)</description></item>
        /// <item><term>listen_port</term>
        ///       <description>internal port (integer)</description></item>
        /// <item><term>external_address</term>
        ///       <description>external IP address</description></item>
        /// <item><term>persist</term>
        ///       <description>if true, persist the region info
        ///       ('true' or 'false')</description></item>
        /// <item><term>public</term>
        ///       <description>if true, the region is public
        ///       ('true' or 'false') (optional, default: true)</description></item>
        /// <item><term>enable_voice</term>
        ///       <description>if true, enable voice on all parcels,
        ///       ('true' or 'false') (optional, default: false)</description></item>
        /// <item><term>estate_name</term>
        ///       <description>the name of the estate to join (or to create if it doesn't
        ///       already exist)</description></item>
        /// <item><term>region_file</term>
        ///       <description>The name of the file to persist the region specifications to.
        /// If omitted, the region_file_template setting from Aurora.ini will be used. (optional)</description></item>
        /// </list>
        ///
        /// XmlRpcCreateRegionMethod returns
        /// <list type="table">
        /// <listheader><term>name</term><description>description</description></listheader>
        /// <item><term>success</term>
        ///       <description>true or false</description></item>
        /// <item><term>error</term>
        ///       <description>error message if success is false</description></item>
        /// <item><term>region_uuid</term>
        ///       <description>UUID of the newly created region</description></item>
        /// <item><term>region_name</term>
        ///       <description>name of the newly created region</description></item>
        /// </list>
        /// </remarks>
        public XmlRpcResponse XmlRpcCreateRegionMethod(XmlRpcRequest request, IPEndPoint remoteClient)
        {
            MainConsole.Instance.Info("[RADMIN]: CreateRegion: new request");

            FailIfRemoteAdminDisabled("CreateRegion");

            XmlRpcResponse response = new XmlRpcResponse();
            Hashtable responseData = new Hashtable();

            lock (m_requestLock)
            {
                int  m_regionLimit = m_config.GetInt("region_limit", 0);
                bool m_enableVoiceForNewRegions = m_config.GetBoolean("create_region_enable_voice", false);
                bool m_publicAccess = m_config.GetBoolean("create_region_public", true);

                try
                {
                    Hashtable requestData = (Hashtable)request.Params[0];

                    CheckStringParameters(request, new[]
                                                       {
                                                           "password",
                                                           "region_name",
                                                           "listen_ip", "external_address",
                                                           "estate_name"
                                                       });
                    CheckIntegerParams(request, new[] { "region_x", "region_y", "listen_port" });

                    // check password
                    if (!String.IsNullOrEmpty(m_requiredPassword) &&
                        (string)requestData["password"] != m_requiredPassword) throw new Exception("wrong password");

                    // check whether we still have space left (iff we are using limits)
                    if (m_regionLimit != 0 && manager.Scenes.Count >= m_regionLimit)
                        throw new Exception(String.Format("cannot instantiate new region, server capacity {0} already reached; delete regions first",
                                                          m_regionLimit));
                    // extract or generate region ID now
                    IScene scene = null;
                    UUID regionID = UUID.Zero;
                    if (requestData.ContainsKey("region_id") &&
                        !String.IsNullOrEmpty((string)requestData["region_id"]))
                    {
                        regionID = (UUID)(string)requestData["region_id"];
                        if (manager.TryGetScene(regionID, out scene))
                            throw new Exception(
                                String.Format("region UUID already in use by region {0}, UUID {1}, <{2},{3}>",
                                              scene.RegionInfo.RegionName, scene.RegionInfo.RegionID,
                                              scene.RegionInfo.RegionLocX / Constants.RegionSize, scene.RegionInfo.RegionLocY / Constants.RegionSize));
                    }
                    else
                    {
                        regionID = UUID.Random();
                        MainConsole.Instance.DebugFormat("[RADMIN] CreateRegion: new region UUID {0}", regionID);
                    }

                    // create volatile or persistent region info
                    RegionInfo region = new RegionInfo
                                            {
                                                RegionID = regionID,
                                                RegionName = (string) requestData["region_name"],
                                                RegionLocX =
                                                    Convert.ToInt32(requestData["region_x"])*Constants.RegionSize,
                                                RegionLocY =
                                                    Convert.ToInt32(requestData["region_y"])*Constants.RegionSize
                                            };


                    // check for collisions: region name, region UUID,
                    // region location
                    if (manager.TryGetScene(region.RegionName, out scene))
                        throw new Exception(
                            String.Format("region name already in use by region {0}",
                                          scene));

                    if (manager.TryGetScene(region.RegionLocX, region.RegionLocY, out scene))
                        throw new Exception(
                            String.Format("region location <{0},{1}> already in use by region {2}",
                                          region.RegionLocX / Constants.RegionSize, region.RegionLocY / Constants.RegionSize,
                                          scene));

                    region.InternalEndPoint =
                        new IPEndPoint(IPAddress.Parse((string) requestData["listen_ip"]), 0)
                            {Port = Convert.ToInt32(requestData["listen_port"])};

                    if (0 == region.InternalEndPoint.Port) throw new Exception("listen_port is 0");
                    
                    // default place for region configuration files is in the
                    // Regions directory of the config dir (aka /bin)
                    string regionConfigPath = Path.Combine(Util.configDir(), "Regions");
                    try
                    {
                        // Aurora.ini can specify a different regions dir
                        IConfig config = m_configSource.Configs["RegionStartup"];
                        if (config != null)
                        {
                            regionConfigPath = config.GetString("RegionsDirectory", regionConfigPath).Trim();
                        }
                    }
                    catch (Exception)
                    {
                        // No INI setting recorded.
                    }

                    string regionIniPath;

                    if (requestData.Contains("region_file"))
                    {
                        // Make sure that the file to be created is in a subdirectory of the region storage directory.
                        string requestedFilePath = Path.Combine(regionConfigPath, (string)requestData["region_file"]);
                        string requestedDirectory = Path.GetDirectoryName(Util.BasePathCombine(requestedFilePath));
                        if (requestedDirectory != null && requestedDirectory.StartsWith(Util.BasePathCombine(regionConfigPath)))
                            regionIniPath = requestedFilePath;
                        else
                            throw new Exception("Invalid location for region file.");
                    }
                    else
                    {
                        regionIniPath = Path.Combine(regionConfigPath,
                                                        String.Format(
                                                            m_config.GetString("region_file_template",
                                                                               "{0}x{1}-{2}.ini"),
                                                            (region.RegionLocX / Constants.RegionSize).ToString(),
                                                            (region.RegionLocY / Constants.RegionSize).ToString(),
                                                            regionID.ToString(),
                                                            region.InternalEndPoint.Port.ToString(),
                                                            region.RegionName.Replace(" ", "_").Replace(":", "_").
                                                                Replace("/", "_")));
                    }

                    MainConsole.Instance.DebugFormat("[RADMIN] CreateRegion: persisting region {0} to {1}",
                                      region.RegionID, regionIniPath);
                    region.SaveRegionToFile("dynamic region", regionIniPath);

                    // Set the estate

                    // Check for an existing estate
                    Aurora.Framework.IEstateConnector estateService = Aurora.DataManager.DataManager.RequestPlugin<Aurora.Framework.IEstateConnector>();
                    if (estateService == null)
                        throw new Exception("No estate service available.");
                    UUID userID = UUID.Zero;
                    if (requestData.ContainsKey("estate_owner_uuid"))
                    {
                        // ok, client wants us to use an explicit UUID
                        // regardless of what the avatar name provided
                        userID = new UUID((string)requestData["estate_owner_uuid"]);
                    }
                    else if (requestData.ContainsKey("estate_owner_first") & requestData.ContainsKey("estate_owner_last"))
                    {
                        // We need to look up the UUID for the avatar with the provided name.
                        string ownerFirst = (string)requestData["estate_owner_first"];
                        string ownerLast = (string)requestData["estate_owner_last"];

                        IScene currentOrFirst = manager.CurrentOrFirstScene;
                        IUserAccountService accountService = currentOrFirst.UserAccountService;
                        UserAccount user = accountService.GetUserAccount(currentOrFirst.RegionInfo.ScopeID,
                                                                           ownerFirst, ownerLast);
                        userID = user.PrincipalID;
                    }
                    else
                    {
                        throw new Exception("Estate owner details not provided.");
                    }
                    int estateID = estateService.GetEstate(userID, (string)requestData["estate_name"]);
                    if (estateID != 0)
                    {
                        // Create a new estate with the name provided
                        //region.EstateSettings = estateService.LoadEstateSettings(region.RegionID);

                        region.EstateSettings.EstateName = (string)requestData["estate_name"];
                        region.EstateSettings.EstateOwner = userID;
                        // Persistence does not seem to effect the need to save a new estate
                        region.EstateSettings.Save();
                    }

                    // Create the region and perform any initial initialization

                    IScene newScene = manager.StartNewRegion(region);

                    // If an access specification was provided, use it.
                    // Otherwise accept the default.
                    newScene.RegionInfo.EstateSettings.PublicAccess = GetBoolean(requestData, "public", m_publicAccess);
                    newScene.RegionInfo.EstateSettings.Save();

                    // enable voice on newly created region if
                    // requested by either the XmlRpc request or the
                    // configuration
                    if (GetBoolean(requestData, "enable_voice", m_enableVoiceForNewRegions))
                    {
                        IParcelManagementModule parcelManagement = newScene.RequestModuleInterface<IParcelManagementModule>();
                        if (parcelManagement != null)
                        {
                            List<ILandObject> parcels = parcelManagement.AllParcels();

                            foreach (ILandObject parcel in parcels)
                            {
                                parcel.LandData.Flags |= (uint)ParcelFlags.AllowVoiceChat;
                                parcel.LandData.Flags |= (uint)ParcelFlags.UseEstateVoiceChan;
                                parcelManagement.UpdateLandObject(parcel);
                            }
                        }
                    }

                    responseData["success"] = true;
                    responseData["region_name"] = region.RegionName;
                    responseData["region_uuid"] = region.RegionID.ToString();

                    response.Value = responseData;
                }
                catch (Exception e)
                {
                    MainConsole.Instance.ErrorFormat("[RADMIN] CreateRegion: failed {0}", e.Message);
                    MainConsole.Instance.DebugFormat("[RADMIN] CreateRegion: failed {0}", e);

                    responseData["success"] = false;
                    responseData["error"] = e.Message;

                    response.Value = responseData;
                }

                MainConsole.Instance.Info("[RADMIN]: CreateRegion: request complete");
                return response;
            }
        }