OSDN Git Service

RAD-7 RAD-172: Complete inventory search, recent and worn filters
[radegast/radegast.git] / Radegast / Core / RadegastInstance.cs
index ab5a2c3..70cbd78 100644 (file)
-// \r
-// Radegast Metaverse Client\r
-// Copyright (c) 2009, Radegast Development Team\r
-// All rights reserved.\r
-// \r
-// Redistribution and use in source and binary forms, with or without\r
-// modification, are permitted provided that the following conditions are met:\r
-// \r
-//     * Redistributions of source code must retain the above copyright notice,\r
-//       this list of conditions and the following disclaimer.\r
-//     * Redistributions in binary form must reproduce the above copyright\r
-//       notice, this list of conditions and the following disclaimer in the\r
-//       documentation and/or other materials provided with the distribution.\r
-//     * Neither the name of the application "Radegast", nor the names of its\r
-//       contributors may be used to endorse or promote products derived from\r
-//       this software without specific prior written permission.\r
-// \r
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
-// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
-//\r
-// $Id$\r
-//\r
-using System;\r
-using System.Collections.Generic;\r
-using System.IO;\r
-using System.Reflection;\r
-using System.Windows.Forms;\r
-using Radegast.Commands;\r
-using Radegast.Netcom;\r
-using Radegast.Media;\r
-using OpenMetaverse;\r
-\r
-namespace Radegast\r
-{\r
-    public class RadegastInstance\r
-    {\r
-        private GridClient client;\r
-        private RadegastNetcom netcom;\r
-\r
-        private StateManager state;\r
-\r
-        private frmMain mainForm;\r
-        private TabsConsole tabsConsole;\r
-\r
-        // Singleton, there can be only one instance\r
-        private static RadegastInstance globalInstance = null;\r
-        public static RadegastInstance GlobalInstance\r
-        {\r
-            get\r
-            {\r
-                if (globalInstance == null)\r
-                {\r
-                    globalInstance = new RadegastInstance(new GridClient());\r
-                }\r
-                return globalInstance;\r
-            }\r
-        }\r
-\r
-        private string userDir;\r
-        /// <summary>\r
-        /// System (not grid!) user's dir\r
-        /// </summary>\r
-        public string UserDir { get { return userDir; } }\r
-\r
-        /// <summary>\r
-        /// Grid client's user dir for settings and logs\r
-        /// </summary>\r
-        public string ClientDir\r
-        {\r
-            get\r
-            {\r
-                if (client != null && client.Self != null && !string.IsNullOrEmpty(client.Self.Name))\r
-                {\r
-                    return Path.Combine(userDir, client.Self.Name);\r
-                }\r
-                else\r
-                {\r
-                    return Environment.CurrentDirectory;\r
-                }\r
-            }\r
-        }\r
-\r
-        public string InventoryCacheFileName { get { return Path.Combine(ClientDir, "inventory.cache"); } }\r
-\r
-        private string animCacheDir;\r
-        public string AnimCacheDir { get { return animCacheDir; } }\r
-\r
-        private string globalLogFile;\r
-        public string GlobalLogFile { get { return globalLogFile; } }\r
-\r
-        private bool monoRuntime;\r
-        public bool MonoRuntime { get { return monoRuntime; } }\r
-\r
-        private Dictionary<UUID, Group> groups;\r
-        public Dictionary<UUID, Group> Groups { get { return groups; } }\r
-\r
-        private Settings globalSettings;\r
-        /// <summary>\r
-        /// Global settings for the entire application\r
-        /// </summary>\r
-        public Settings GlobalSettings { get { return globalSettings; } }\r
-\r
-        private Settings clientSettings;\r
-        /// <summary>\r
-        /// Per client settings\r
-        /// </summary>\r
-        public Settings ClientSettings { get { return clientSettings; } }\r
-\r
-        public Dictionary<UUID, string> nameCache = new Dictionary<UUID, string>();\r
-\r
-        public const string INCOMPLETE_NAME = "Loading...";\r
-\r
-        public readonly bool advancedDebugging = false;\r
-\r
-        public readonly List<IRadegastPlugin> PluginsLoaded = new List<IRadegastPlugin>();\r
-\r
-        private MediaManager mediaManager;\r
-        /// <summary>\r
-        /// Radegast media manager for playing streams and in world sounds\r
-        /// </summary>\r
-        public MediaManager MediaManager { get { return mediaManager; } }\r
-\r
-\r
-        private CommandsManager commandsManager;\r
-        /// <summary>\r
-        /// Radegast command manager for executing textual console commands\r
-        /// </summary>\r
-        public CommandsManager CommandsManager { get { return commandsManager; } }\r
-\r
-        public RadegastInstance(GridClient client0)\r
-        {\r
-            // incase something else calls GlobalInstance while we are loading\r
-            globalInstance = this; \r
-\r
-            client = client0;\r
-\r
-            // Are we running mono?\r
-            monoRuntime = Type.GetType("Mono.Runtime") != null;\r
-\r
-            netcom = new RadegastNetcom(client);\r
-            state = new StateManager(this);\r
-            mediaManager = new MediaManager(this);\r
-            commandsManager = new CommandsManager(this);\r
-\r
-            InitializeLoggingAndConfig();\r
-\r
-            client.Settings.MULTIPLE_SIMS = true;\r
-\r
-            client.Settings.USE_INTERPOLATION_TIMER = false;\r
-            client.Settings.ALWAYS_REQUEST_OBJECTS = true;\r
-            client.Settings.ALWAYS_DECODE_OBJECTS = true;\r
-            client.Settings.OBJECT_TRACKING = true;\r
-            client.Settings.ENABLE_SIMSTATS = true;\r
-            client.Settings.FETCH_MISSING_INVENTORY = true;\r
-            client.Settings.SEND_AGENT_THROTTLE = true;\r
-            client.Settings.SEND_AGENT_UPDATES = true;\r
-\r
-            client.Settings.USE_ASSET_CACHE = true;\r
-            client.Settings.ASSET_CACHE_DIR = Path.Combine(userDir, "cache");\r
-            client.Assets.Cache.AutoPruneEnabled = false;\r
-\r
-            client.Throttle.Texture = 2446000.0f;\r
-            client.Throttle.Asset = 2446000.0f;\r
-            client.Settings.THROTTLE_OUTGOING_PACKETS = true;\r
-            client.Settings.LOGIN_TIMEOUT = 120 * 1000;\r
-            client.Settings.SIMULATOR_TIMEOUT = 120 * 1000;\r
-            client.Settings.MAX_CONCURRENT_TEXTURE_DOWNLOADS = 20;\r
-\r
-            mainForm = new frmMain(this);\r
-            mainForm.InitializeControls();\r
-            tabsConsole = mainForm.TabConsole;\r
-\r
-            groups = new Dictionary<UUID, Group>();\r
-\r
-            client.Groups.OnCurrentGroups += new GroupManager.CurrentGroupsCallback(Groups_OnCurrentGroups);\r
-            client.Groups.OnGroupLeft += new GroupManager.GroupLeftCallback(Groups_OnGroupLeft);\r
-            client.Groups.OnGroupDropped += new GroupManager.GroupDroppedCallback(Groups_OnGroupDropped);\r
-            client.Groups.OnGroupJoined += new GroupManager.GroupJoinedCallback(Groups_OnGroupJoined);\r
-            client.Avatars.OnAvatarNames += new AvatarManager.AvatarNamesCallback(Avatars_OnAvatarNames);\r
-            client.Network.OnConnected += new NetworkManager.ConnectedCallback(Network_OnConnected);\r
-            ScanAndLoadPlugins();\r
-        }\r
-\r
-        public void CleanUp()\r
-        {\r
-            if (client != null)\r
-            {\r
-                client.Groups.OnCurrentGroups -= new GroupManager.CurrentGroupsCallback(Groups_OnCurrentGroups);\r
-                client.Groups.OnGroupLeft -= new GroupManager.GroupLeftCallback(Groups_OnGroupLeft);\r
-                client.Groups.OnGroupDropped -= new GroupManager.GroupDroppedCallback(Groups_OnGroupDropped);\r
-                client.Groups.OnGroupJoined -= new GroupManager.GroupJoinedCallback(Groups_OnGroupJoined);\r
-                client.Avatars.OnAvatarNames -= new AvatarManager.AvatarNamesCallback(Avatars_OnAvatarNames);\r
-                client.Network.OnConnected -= new NetworkManager.ConnectedCallback(Network_OnConnected);\r
-            }\r
-\r
-            lock (PluginsLoaded)\r
-            {\r
-                PluginsLoaded.ForEach(plug =>\r
-                {\r
-                    try\r
-                    {\r
-                        plug.StopPlugin(this);\r
-                    }\r
-                    catch (Exception) { }\r
-                });\r
-            }                        \r
-            commandsManager.Dispose();\r
-            commandsManager = null;\r
-            mediaManager.Dispose();\r
-            mediaManager = null;\r
-            state.Dispose();\r
-            state = null;\r
-            netcom.Dispose();\r
-            netcom = null;\r
-            Logger.Log("RadegastInstance finished cleaning up.", Helpers.LogLevel.Debug);\r
-        }\r
-\r
-        private void ScanAndLoadPlugins()\r
-        {\r
-            string dirName = Application.StartupPath;\r
-\r
-            if (!Directory.Exists(dirName)) return;\r
-\r
-            foreach (string loadfilename in Directory.GetFiles(dirName))\r
-            {\r
-                if (loadfilename.ToLower().EndsWith(".dll") || loadfilename.ToLower().EndsWith(".exe"))\r
-                {\r
-                    try\r
-                    {\r
-                        Assembly assembly = Assembly.LoadFile(loadfilename);\r
-                        LoadAssembly(loadfilename, assembly);\r
-                    }\r
-                    catch (BadImageFormatException)\r
-                    {\r
-                        // non .NET .dlls\r
-                    }\r
-                    catch (ReflectionTypeLoadException)\r
-                    {\r
-                        // Out of date or dlls missing sub dependencies\r
-                    }\r
-                    catch (Exception ex)\r
-                    {\r
-                        Logger.Log("ERROR in Radegast Plugin: " + loadfilename + " because " + ex.Message + " " + ex.StackTrace, Helpers.LogLevel.Debug);\r
-                    }\r
-                }\r
-            }\r
-        }\r
-\r
-        public void LoadAssembly(string loadfilename, Assembly assembly)\r
-        {\r
-            foreach (Type type in assembly.GetTypes())\r
-            {\r
-                if (typeof(IRadegastPlugin).IsAssignableFrom(type))\r
-                {\r
-                    foreach (var ci in type.GetConstructors())\r
-                    {\r
-                        if (ci.GetParameters().Length > 0) continue;\r
-                        try\r
-                        {\r
-                            IRadegastPlugin plug = (IRadegastPlugin)ci.Invoke(new object[0]);\r
-                            plug.StartPlugin(this);\r
-                            lock (PluginsLoaded) PluginsLoaded.Add(plug);\r
-                            break;\r
-                        }\r
-                        catch (Exception ex)\r
-                        {\r
-                            Logger.Log("ERROR Constructing Radegast Plugin: " + loadfilename + " because " + ex.Message, Helpers.LogLevel.Debug);\r
-                            throw ex;\r
-                        }\r
-                    }\r
-                }\r
-                else\r
-                {\r
-                    try\r
-                    {\r
-                        commandsManager.LoadType(type);\r
-                    }\r
-                    catch (Exception ex)\r
-                    {\r
-                        Logger.Log("ERROR in Radegast Plugin: " + loadfilename + " Command: " + type +\r
-                                   " because " + ex.Message + " " + ex.StackTrace, Helpers.LogLevel.Debug);\r
-                    }\r
-                }\r
-            }\r
-        }\r
-\r
-        void Network_OnConnected(object sender)\r
-        {\r
-            try\r
-            {\r
-                if (!Directory.Exists(ClientDir))\r
-                    Directory.CreateDirectory(ClientDir);\r
-            }\r
-            catch (Exception ex)\r
-            {\r
-                Logger.Log("Failed to create client directory", Helpers.LogLevel.Warning, ex);\r
-            }\r
-\r
-            clientSettings = new Settings(Path.Combine(ClientDir, "client_settings.xml"));\r
-        }\r
-\r
-        void Avatars_OnAvatarNames(Dictionary<UUID, string> names)\r
-        {\r
-            lock (nameCache)\r
-            {\r
-                foreach (KeyValuePair<UUID, string> av in names)\r
-                {\r
-                    if (!nameCache.ContainsKey(av.Key))\r
-                    {\r
-                        nameCache.Add(av.Key, av.Value);\r
-                    }\r
-                }\r
-            }\r
-        }\r
-\r
-        public string getAvatarName(UUID key)\r
-        {\r
-            lock (nameCache)\r
-            {\r
-                if (key == UUID.Zero)\r
-                {\r
-                    return "(???) (???)";\r
-                }\r
-                if (nameCache.ContainsKey(key))\r
-                {\r
-                    return nameCache[key];\r
-                }\r
-                else\r
-                {\r
-                    client.Avatars.RequestAvatarName(key);\r
-                    return INCOMPLETE_NAME;\r
-                }\r
-            }\r
-        }\r
-\r
-        public void getAvatarNames(List<UUID> keys)\r
-        {\r
-            lock (nameCache)\r
-            {\r
-                List<UUID> newNames = new List<UUID>();\r
-                foreach (UUID key in keys)\r
-                {\r
-                    if (!nameCache.ContainsKey(key))\r
-                    {\r
-                        newNames.Add(key);\r
-                    }\r
-                }\r
-                if (newNames.Count > 0)\r
-                {\r
-                    client.Avatars.RequestAvatarNames(newNames);\r
-                }\r
-            }\r
-        }\r
-\r
-        public bool haveAvatarName(UUID key)\r
-        {\r
-            lock (nameCache)\r
-            {\r
-                if (nameCache.ContainsKey(key))\r
-                    return true;\r
-                else\r
-                    return false;\r
-            }\r
-        }\r
-\r
-        void Groups_OnGroupJoined(UUID groupID, bool success)\r
-        {\r
-            client.Groups.RequestCurrentGroups();\r
-        }\r
-\r
-        void Groups_OnGroupLeft(UUID groupID, bool success)\r
-        {\r
-            client.Groups.RequestCurrentGroups();\r
-        }\r
-\r
-        void Groups_OnGroupDropped(UUID groupID)\r
-        {\r
-            client.Groups.RequestCurrentGroups();\r
-        }\r
-\r
-        public static string SafeFileName(string fileName)\r
-        {\r
-            foreach (char lDisallowed in Path.GetInvalidFileNameChars())\r
-            {\r
-                fileName = fileName.Replace(lDisallowed.ToString(), "_");\r
-            }\r
-\r
-            return fileName;\r
-        }\r
-\r
-        public void LogClientMessage(string fileName, string message)\r
-        {\r
-            lock (this)\r
-            {\r
-                try\r
-                {\r
-                    foreach (char lDisallowed in System.IO.Path.GetInvalidFileNameChars())\r
-                    {\r
-                        fileName = fileName.Replace(lDisallowed.ToString(), "_");\r
-                    }\r
-\r
-                    StreamWriter logfile = File.AppendText(Path.Combine(ClientDir, fileName));\r
-                    logfile.WriteLine(DateTime.Now.ToString("yyyy-MM-dd [HH:mm:ss] ") + message);\r
-                    logfile.Close();\r
-                    logfile.Dispose();\r
-                }\r
-                catch (Exception) { }\r
-            }\r
-        }\r
-\r
-        void Groups_OnCurrentGroups(Dictionary<UUID, Group> gr)\r
-        {\r
-            this.groups = gr;\r
-        }\r
-\r
-        private void InitializeLoggingAndConfig()\r
-        {\r
-            try\r
-            {\r
-                userDir = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), Properties.Resources.ProgramName);\r
-                if (!Directory.Exists(userDir))\r
-                {\r
-                    Directory.CreateDirectory(userDir);\r
-                }\r
-            }\r
-            catch (Exception)\r
-            {\r
-                userDir = System.Environment.CurrentDirectory;\r
-            };\r
-\r
-            animCacheDir = Path.Combine(userDir, @"anim_cache");\r
-            globalLogFile = Path.Combine(userDir, Properties.Resources.ProgramName + ".log");\r
-            globalSettings = new Settings(Path.Combine(userDir, "settings.xml"));\r
-        }\r
-\r
-        public GridClient Client\r
-        {\r
-            get { return client; }\r
-        }\r
-\r
-        public RadegastNetcom Netcom\r
-        {\r
-            get { return netcom; }\r
-        }\r
-\r
-        public StateManager State\r
-        {\r
-            get { return state; }\r
-        }\r
-\r
-        public frmMain MainForm\r
-        {\r
-            get { return mainForm; }\r
-        }\r
-\r
-        public TabsConsole TabConsole\r
-        {\r
-            get { return tabsConsole; }\r
-        }\r
-    }\r
-}\r
+// 
+// Radegast Metaverse Client
+// Copyright (c) 2009-2010, Radegast Development Team
+// All rights reserved.
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// 
+//     * Redistributions of source code must retain the above copyright notice,
+//       this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above copyright
+//       notice, this list of conditions and the following disclaimer in the
+//       documentation and/or other materials provided with the distribution.
+//     * Neither the name of the application "Radegast", nor the names of its
+//       contributors may be used to endorse or promote products derived from
+//       this software without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// $Id$
+//
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Threading;
+using System.Windows.Forms;
+using Radegast.Commands;
+using Radegast.Netcom;
+using Radegast.Media;
+using OpenMetaverse;
+
+namespace Radegast
+{
+    public class RadegastInstance
+    {
+        #region OnRadegastFormCreated
+        public event Action<RadegastForm> RadegastFormCreated;
+        /// <summary>
+        /// Triggers the RadegastFormCreated event.
+        /// </summary>
+        public virtual void OnRadegastFormCreated(RadegastForm radForm)
+        {
+            if (RadegastFormCreated != null) RadegastFormCreated(radForm);
+        }
+        #endregion
+
+        private GridClient client;
+        private RadegastNetcom netcom;
+
+        private StateManager state;
+
+        private frmMain mainForm;
+
+        // Singleton, there can be only one instance
+        private static RadegastInstance globalInstance = null;
+        public static RadegastInstance GlobalInstance
+        {
+            get
+            {
+                if (globalInstance == null)
+                {
+                    globalInstance = new RadegastInstance(new GridClient());
+                }
+                return globalInstance;
+            }
+        }
+
+        /// <summary>
+        /// When was Radegast started (UTC)
+        /// </summary>
+        public readonly DateTime StartupTimeUTC;
+
+        /// <summary>
+        /// Time zone of the current world (currently hard coded to US Pacific time)
+        /// </summary>
+        public TimeZoneInfo WordTimeZone;
+
+        private string userDir;
+        /// <summary>
+        /// System (not grid!) user's dir
+        /// </summary>
+        public string UserDir { get { return userDir; } }
+
+        /// <summary>
+        /// Grid client's user dir for settings and logs
+        /// </summary>
+        public string ClientDir
+        {
+            get
+            {
+                if (client != null && client.Self != null && !string.IsNullOrEmpty(client.Self.Name))
+                {
+                    return Path.Combine(userDir, client.Self.Name);
+                }
+                else
+                {
+                    return Environment.CurrentDirectory;
+                }
+            }
+        }
+
+        public string InventoryCacheFileName { get { return Path.Combine(ClientDir, "inventory.cache"); } }
+
+        private string globalLogFile;
+        public string GlobalLogFile { get { return globalLogFile; } }
+
+        private bool monoRuntime;
+        public bool MonoRuntime { get { return monoRuntime; } }
+
+        private Dictionary<UUID, Group> groups = new Dictionary<UUID, Group>();
+        public Dictionary<UUID, Group> Groups { get { return groups; } }
+
+        private Settings globalSettings;
+        /// <summary>
+        /// Global settings for the entire application
+        /// </summary>
+        public Settings GlobalSettings { get { return globalSettings; } }
+
+        private Settings clientSettings;
+        /// <summary>
+        /// Per client settings
+        /// </summary>
+        public Settings ClientSettings { get { return clientSettings; } }
+
+        public Dictionary<UUID, string> nameCache = new Dictionary<UUID, string>();
+
+        public const string INCOMPLETE_NAME = "Loading...";
+
+        public readonly bool advancedDebugging = false;
+
+        private PluginManager pluginManager;
+        /// <summary> Handles loading plugins and scripts</summary>
+        public PluginManager PluginManager { get { return pluginManager; } }
+
+        private MediaManager mediaManager;
+        /// <summary>
+        /// Radegast media manager for playing streams and in world sounds
+        /// </summary>
+        public MediaManager MediaManager { get { return mediaManager; } }
+
+
+        private CommandsManager commandsManager;
+        /// <summary>
+        /// Radegast command manager for executing textual console commands
+        /// </summary>
+        public CommandsManager CommandsManager { get { return commandsManager; } }
+
+        /// <summary>
+        /// Radegast ContextAction manager for context sensitive actions
+        /// </summary>
+        public ContextActionsManager ContextActionManager { get; private set; }
+
+        private RadegastMovement movement;
+        /// <summary>
+        /// Allows key emulation for moving avatar around
+        /// </summary>
+        public RadegastMovement Movement { get { return movement; } }
+
+        private InventoryClipboard inventoryClipboard;
+        /// <summary>
+        /// The last item that was cut or copied in the inventory, used for pasting
+        /// in a different place on the inventory, or other places like profile
+        /// that allow sending copied inventory items
+        /// </summary>
+        public InventoryClipboard InventoryClipboard
+        {
+            get { return inventoryClipboard; }
+            set
+            {
+                inventoryClipboard = value;
+                OnInventoryClipboardUpdated(EventArgs.Empty);
+            }
+        }
+
+        private RLVManager rlv;
+
+        /// <summary>
+        /// Manager for RLV functionality
+        /// </summary>
+        public RLVManager RLV { get { return rlv; } }
+
+        private GridManager gridManager;
+        /// <summary>Manages default params for different grids</summary>
+        public GridManager GridManger { get { return gridManager; } }
+
+        #region Events
+
+        #region ClientChanged event
+        /// <summary>The event subscribers, null of no subscribers</summary>
+        private EventHandler<ClientChangedEventArgs> m_ClientChanged;
+
+        ///<summary>Raises the ClientChanged Event</summary>
+        /// <param name="e">A ClientChangedEventArgs object containing
+        /// the old and the new client</param>
+        protected virtual void OnClientChanged(ClientChangedEventArgs e)
+        {
+            EventHandler<ClientChangedEventArgs> handler = m_ClientChanged;
+            if (handler != null)
+                handler(this, e);
+        }
+
+        /// <summary>Thread sync lock object</summary>
+        private readonly object m_ClientChangedLock = new object();
+
+        /// <summary>Raised when the GridClient object in the main Radegast instance is changed</summary>
+        public event EventHandler<ClientChangedEventArgs> ClientChanged
+        {
+            add { lock (m_ClientChangedLock) { m_ClientChanged += value; } }
+            remove { lock (m_ClientChangedLock) { m_ClientChanged -= value; } }
+        }
+        #endregion ClientChanged event
+
+        #region InventoryClipboardUpdated event
+        /// <summary>The event subscribers, null of no subscribers</summary>
+        private EventHandler<EventArgs> m_InventoryClipboardUpdated;
+
+        ///<summary>Raises the InventoryClipboardUpdated Event</summary>
+        /// <param name="e">A EventArgs object containing
+        /// the old and the new client</param>
+        protected virtual void OnInventoryClipboardUpdated(EventArgs e)
+        {
+            EventHandler<EventArgs> handler = m_InventoryClipboardUpdated;
+            if (handler != null)
+                handler(this, e);
+        }
+
+        /// <summary>Thread sync lock object</summary>
+        private readonly object m_InventoryClipboardUpdatedLock = new object();
+
+        /// <summary>Raised when the GridClient object in the main Radegast instance is changed</summary>
+        public event EventHandler<EventArgs> InventoryClipboardUpdated
+        {
+            add { lock (m_InventoryClipboardUpdatedLock) { m_InventoryClipboardUpdated += value; } }
+            remove { lock (m_InventoryClipboardUpdatedLock) { m_InventoryClipboardUpdated -= value; } }
+        }
+        #endregion InventoryClipboardUpdated event
+
+
+        #endregion Events
+
+        public RadegastInstance(GridClient client0)
+        {
+            // incase something else calls GlobalInstance while we are loading
+            globalInstance = this;
+
+#if !DEBUG
+            Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
+            Application.ThreadException += HandleThreadException;
+#endif
+
+            client = client0;
+
+            // Initialize current time zone, and mark when we started
+            GetWorldTimeZone();
+            StartupTimeUTC = DateTime.UtcNow;
+
+            // Are we running mono?
+            monoRuntime = Type.GetType("Mono.Runtime") != null;
+
+            netcom = new RadegastNetcom(this);
+            state = new StateManager(this);
+            mediaManager = new MediaManager(this);
+            commandsManager = new CommandsManager(this);
+            ContextActionManager = new ContextActionsManager(this);
+            movement = new RadegastMovement(this);
+
+            InitializeLoggingAndConfig();
+            InitializeClient(client);
+
+            rlv = new RLVManager(this);
+            gridManager = new GridManager(this);
+            gridManager.LoadGrids();
+
+            mainForm = new frmMain(this);
+            mainForm.InitializeControls();
+
+            mainForm.Load += new EventHandler(mainForm_Load);
+            pluginManager = new PluginManager(this);
+            pluginManager.ScanAndLoadPlugins();
+        }
+
+        private void InitializeClient(GridClient client)
+        {
+            client.Settings.MULTIPLE_SIMS = true;
+
+            client.Settings.USE_INTERPOLATION_TIMER = false;
+            client.Settings.ALWAYS_REQUEST_OBJECTS = true;
+            client.Settings.ALWAYS_DECODE_OBJECTS = true;
+            client.Settings.OBJECT_TRACKING = true;
+            client.Settings.ENABLE_SIMSTATS = true;
+            client.Settings.FETCH_MISSING_INVENTORY = true;
+            client.Settings.SEND_AGENT_THROTTLE = true;
+            client.Settings.SEND_AGENT_UPDATES = true;
+
+            client.Settings.USE_ASSET_CACHE = true;
+            client.Settings.ASSET_CACHE_DIR = Path.Combine(userDir, "cache");
+            client.Assets.Cache.AutoPruneEnabled = false;
+
+            client.Throttle.Total = 5000000f;
+            client.Settings.THROTTLE_OUTGOING_PACKETS = false;
+            client.Settings.LOGIN_TIMEOUT = 120 * 1000;
+            client.Settings.SIMULATOR_TIMEOUT = 120 * 1000;
+            client.Settings.MAX_CONCURRENT_TEXTURE_DOWNLOADS = 20;
+
+            RegisterClientEvents(client);
+        }
+
+        private void RegisterClientEvents(GridClient client)
+        {
+            client.Groups.CurrentGroups += new EventHandler<CurrentGroupsEventArgs>(Groups_CurrentGroups);
+            client.Groups.GroupLeaveReply += new EventHandler<GroupOperationEventArgs>(Groups_GroupsChanged);
+            client.Groups.GroupDropped += new EventHandler<GroupDroppedEventArgs>(Groups_GroupsChanged);
+            client.Groups.GroupJoinedReply += new EventHandler<GroupOperationEventArgs>(Groups_GroupsChanged);
+            client.Avatars.UUIDNameReply += new EventHandler<UUIDNameReplyEventArgs>(Avatars_UUIDNameReply);
+            if (netcom != null)
+                netcom.ClientConnected += new EventHandler<EventArgs>(netcom_ClientConnected);
+        }
+
+        private void UnregisterClientEvents(GridClient client)
+        {
+            client.Groups.CurrentGroups -= new EventHandler<CurrentGroupsEventArgs>(Groups_CurrentGroups);
+            client.Groups.GroupLeaveReply -= new EventHandler<GroupOperationEventArgs>(Groups_GroupsChanged);
+            client.Groups.GroupDropped -= new EventHandler<GroupDroppedEventArgs>(Groups_GroupsChanged);
+            client.Groups.GroupJoinedReply -= new EventHandler<GroupOperationEventArgs>(Groups_GroupsChanged);
+            client.Avatars.UUIDNameReply -= new EventHandler<UUIDNameReplyEventArgs>(Avatars_UUIDNameReply);
+            if (netcom != null)
+                netcom.ClientConnected -= new EventHandler<EventArgs>(netcom_ClientConnected);
+        }
+
+        private void GetWorldTimeZone()
+        {
+            try
+            {
+                foreach (TimeZoneInfo tz in TimeZoneInfo.GetSystemTimeZones())
+                {
+                    if (tz.Id == "Pacific Standard Time" || tz.Id == "America/Los_Angeles")
+                    {
+                        WordTimeZone = tz;
+                        break;
+                    }
+                }
+            }
+            catch (Exception) { }
+        }
+
+        public DateTime GetWorldTime()
+        {
+            DateTime now;
+            
+            try
+            {
+                if (WordTimeZone != null)
+                    now = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, WordTimeZone);
+                else
+                    now = DateTime.UtcNow.AddHours(-7);
+            }
+            catch (Exception)
+            {
+                now = DateTime.UtcNow.AddHours(-7);
+            }
+
+            return now;
+        }
+
+
+        public void Reconnect()
+        {
+            TabConsole.DisplayNotificationInChat("Attempting to reconnect...", ChatBufferTextStyle.StatusDarkBlue);
+            Logger.Log("Attemting to reconnect", Helpers.LogLevel.Info, client);
+            GridClient oldClient = client;
+            client = new GridClient();
+            UnregisterClientEvents(oldClient);
+            InitializeClient(client);
+            OnClientChanged(new ClientChangedEventArgs(oldClient, client));
+            netcom.Login();
+        }
+
+        public void CleanUp()
+        {
+            if (gridManager != null)
+            {
+                gridManager.Dispose();
+                gridManager = null;
+            }
+
+            if (rlv != null)
+            {
+                rlv.Dispose();
+                rlv = null;
+            }
+
+            if (client != null)
+            {
+                UnregisterClientEvents(client);
+            }
+
+            if (pluginManager != null)
+            {
+                pluginManager.Dispose();
+                pluginManager = null;
+            }
+
+            if (movement != null)
+            {
+                movement.Dispose();
+                movement = null;
+            }
+            if (commandsManager != null)
+            {
+                commandsManager.Dispose();
+                commandsManager = null;
+            }
+            if (ContextActionManager != null)
+            {
+                ContextActionManager.Dispose();
+                ContextActionManager = null;
+            }
+            if (mediaManager != null)
+            {
+                mediaManager.Dispose();
+                mediaManager = null;
+            }
+            if (state != null)
+            {
+                state.Dispose();
+                state = null;
+            }
+            if (netcom != null)
+            {
+                netcom.Dispose();
+                netcom = null;
+            }
+            if (mainForm != null)
+            {
+                mainForm.Load -= new EventHandler(mainForm_Load);
+            }
+            Logger.Log("RadegastInstance finished cleaning up.", Helpers.LogLevel.Debug);
+        }
+
+        void mainForm_Load(object sender, EventArgs e)
+        {
+            pluginManager.StartPlugins();
+        }
+
+        void netcom_ClientConnected(object sender, EventArgs e)
+        {
+            try
+            {
+                if (!Directory.Exists(ClientDir))
+                    Directory.CreateDirectory(ClientDir);
+            }
+            catch (Exception ex)
+            {
+                Logger.Log("Failed to create client directory", Helpers.LogLevel.Warning, ex);
+            }
+
+            clientSettings = new Settings(Path.Combine(ClientDir, "client_settings.xml"));
+        }
+
+
+        void Avatars_UUIDNameReply(object sender, UUIDNameReplyEventArgs e)
+        {
+            lock (nameCache)
+            {
+                foreach (KeyValuePair<UUID, string> av in e.Names)
+                {
+                    if (!nameCache.ContainsKey(av.Key))
+                    {
+                        nameCache.Add(av.Key, av.Value);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Fetches avatar name
+        /// </summary>
+        /// <param name="key">Avatar UUID</param>
+        /// <param name="blocking">Should we wait until the name is retrieved</param>
+        /// <returns>Avatar name</returns>
+        public string getAvatarName(UUID key, bool blocking)
+        {
+            if (!blocking)
+                return getAvatarName(key);
+
+            string name = null;
+
+            using (ManualResetEvent gotName = new ManualResetEvent(false))
+            {
+
+                EventHandler<UUIDNameReplyEventArgs> handler = (object sender, UUIDNameReplyEventArgs e) =>
+                    {
+                        if (e.Names.ContainsKey(key))
+                        {
+                            name = e.Names[key];
+                            gotName.Set();
+                        }
+                    };
+
+                client.Avatars.UUIDNameReply += handler;
+                name = getAvatarName(key);
+
+                if (name == INCOMPLETE_NAME)
+                {
+                    gotName.WaitOne(10 * 1000, false);
+                }
+
+                client.Avatars.UUIDNameReply -= handler;
+            }
+            return name;
+
+        }
+
+        /// <summary>
+        /// Fetches avatar name from cache, if not in cache will requst name from the server
+        /// </summary>
+        /// <param name="key">Avatar UUID</param>
+        /// <returns>Avatar name</returns>
+        public string getAvatarName(UUID key)
+        {
+            lock (nameCache)
+            {
+                if (key == UUID.Zero)
+                {
+                    return "(???) (???)";
+                }
+                if (nameCache.ContainsKey(key))
+                {
+                    return nameCache[key];
+                }
+                else
+                {
+                    client.Avatars.RequestAvatarName(key);
+                    return INCOMPLETE_NAME;
+                }
+            }
+        }
+
+        public void getAvatarNames(List<UUID> keys)
+        {
+            lock (nameCache)
+            {
+                List<UUID> newNames = new List<UUID>();
+                foreach (UUID key in keys)
+                {
+                    if (!nameCache.ContainsKey(key))
+                    {
+                        newNames.Add(key);
+                    }
+                }
+                if (newNames.Count > 0)
+                {
+                    client.Avatars.RequestAvatarNames(newNames);
+                }
+            }
+        }
+
+        public bool haveAvatarName(UUID key)
+        {
+            lock (nameCache)
+            {
+                if (nameCache.ContainsKey(key))
+                    return true;
+                else
+                    return false;
+            }
+        }
+
+        void Groups_GroupsChanged(object sender, EventArgs e)
+        {
+            client.Groups.RequestCurrentGroups();
+        }
+
+        public static string SafeFileName(string fileName)
+        {
+            foreach (char lDisallowed in Path.GetInvalidFileNameChars())
+            {
+                fileName = fileName.Replace(lDisallowed.ToString(), "_");
+            }
+
+            return fileName;
+        }
+
+        public void LogClientMessage(string fileName, string message)
+        {
+            lock (this)
+            {
+                try
+                {
+                    foreach (char lDisallowed in System.IO.Path.GetInvalidFileNameChars())
+                    {
+                        fileName = fileName.Replace(lDisallowed.ToString(), "_");
+                    }
+
+                    File.AppendAllText(Path.Combine(ClientDir, fileName),
+                        DateTime.Now.ToString("yyyy-MM-dd [HH:mm:ss] ") + message + Environment.NewLine);
+                }
+                catch (Exception) { }
+            }
+        }
+
+        void Groups_CurrentGroups(object sender, CurrentGroupsEventArgs e)
+        {
+            this.groups = e.Groups;
+        }
+
+        private void InitializeLoggingAndConfig()
+        {
+            try
+            {
+                userDir = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), Properties.Resources.ProgramName);
+                if (!Directory.Exists(userDir))
+                {
+                    Directory.CreateDirectory(userDir);
+                }
+            }
+            catch (Exception)
+            {
+                userDir = System.Environment.CurrentDirectory;
+            };
+
+            globalLogFile = Path.Combine(userDir, Properties.Resources.ProgramName + ".log");
+            globalSettings = new Settings(Path.Combine(userDir, "settings.xml"));
+        }
+
+        public GridClient Client
+        {
+            get { return client; }
+        }
+
+        public RadegastNetcom Netcom
+        {
+            get { return netcom; }
+        }
+
+        public StateManager State
+        {
+            get { return state; }
+        }
+
+        public frmMain MainForm
+        {
+            get { return mainForm; }
+        }
+
+        public TabsConsole TabConsole
+        {
+            get { return mainForm.TabConsole; }
+        }
+
+        public void HandleThreadException(object sender, ThreadExceptionEventArgs e)
+        {
+            Logger.Log("Unhandled Thread Exception: "
+                + e.Exception.Message + Environment.NewLine
+                + e.Exception.StackTrace + Environment.NewLine,
+                Helpers.LogLevel.Error,
+                client);
+#if DEBUG
+            Application.Exit();
+#endif
+        }
+    }
+
+    #region Event classes
+    public class ClientChangedEventArgs : EventArgs
+    {
+        private GridClient m_OldClient;
+        private GridClient m_Client;
+
+        public GridClient OldClient { get { return m_OldClient; } }
+        public GridClient Client { get { return m_Client; } }
+
+        public ClientChangedEventArgs(GridClient OldClient, GridClient Client)
+        {
+            m_OldClient = OldClient;
+            m_Client = Client;
+        }
+    }
+    #endregion Event classes
+}