/// <summary>
        /// Constructor
        /// </summary>
        public RedisBrowserForm(MainForm parent)
        {
            InitializeComponent();

            // Initialize Variables
            clientList = new List <RedisClientInfo>();

            // Mdi
            this.MdiParent = parent;
            this.parent    = parent;

            // Add global settings handler
            GlobalSettings.Instance.SettingsChanged +=
                (Object o, GlobalSettings.SettingsChangedEventArgs e) => HandleSettingsChanges(e);

            // Initialize Form Updating
            serverPing     = new Ping();
            timer          = new Timer();
            timer.Interval = GlobalSettings.Instance.PingInterval;
            timer.Tick    += (Object o, EventArgs e) => UpdatePingDelay();

            // Initialize States
            stateManager = new WizardStateManager();
            stateManager.AddState(wsConnect);
            stateManager.AddState(wsConnected);
            stateManager.AddState(wsLoading);
            stateManager.SetCurrentState("wsConnect");

            // Keys List
            if (Environment.OSVersion.Platform == PlatformID.Win32NT &&
                (Environment.OSVersion.Version >= new Version(6, 1)))
            {
                olvKeys.SetNativeBackgroundWatermark(Properties.Resources.KeyListBG);
                olvKeys.GridLines = true;
            }
            olvcKey.ImageGetter = (Object row) =>
            {
                RedisTopLevelEntity en = (RedisTopLevelEntity)row;
                return((int)en.Type);
            };
            olvcTTL.AspectToStringConverter = delegate(Object o)
            {
                DateTime en = (DateTime)o;
                if (en == null || en < DateTime.Now)
                {
                    return("N/A");
                }
                else
                {
                    return(en.ToString());
                }
            };

            // CLient List
            AspectToStringConverterDelegate clientValConv = new AspectToStringConverterDelegate((Object o) =>
            {
                Int32 i = (Int32)o;
                if (i >= 0)
                {
                    return(i.ToString());
                }
                else
                {
                    return("N/A");
                }
            });

            olvcAge.AspectToStringConverter        = clientValConv;
            olvcDb.AspectToStringConverter         = clientValConv;
            olvcFileHandle.AspectToStringConverter = clientValConv;
            olvcIdle.AspectToStringConverter       = clientValConv;
            olvcMulti.AspectToStringConverter      = clientValConv;
            olvcObl.AspectToStringConverter        = clientValConv;
            olvcOll.AspectToStringConverter        = clientValConv;
            olvcOmem.AspectToStringConverter       = clientValConv;
            olvcPSub.AspectToStringConverter       = clientValConv;
            olvcQbuf.AspectToStringConverter       = clientValConv;
            olvcQbufF.AspectToStringConverter      = clientValConv;
            olvcSub.AspectToStringConverter        = clientValConv;

            // event handlers
            this.FormClosing += (Object o, FormClosingEventArgs e) => { if (timer.Enabled)
                                                                        {
                                                                            timer.Stop();
                                                                        }
                                                                        if (redisClient != null)
                                                                        {
                                                                            redisClient.Dispose();
                                                                        }
            };

            wsLoading.OnActivated   += (Object s, EventArgs e) => { loadingIndicator1.Enabled = true; };
            wsLoading.OnDeactivated += (Object s, EventArgs e) => { loadingIndicator1.Enabled = false; };
        }
        public void PullData()
        {
            // navigate to the loading state
            stateManager.SetCurrentState("wsLoading");

            // construct worker
            asyncLoader = new BackgroundWorker();
            asyncLoader.WorkerReportsProgress      = true;
            asyncLoader.WorkerSupportsCancellation = true;
            asyncLoader.DoWork += (Object o, DoWorkEventArgs e) =>
            {
                asyncLoader.ReportProgress(0, new Object[] { "RBF_ProgressDwnKeys", 0, 0 });

                // pass redis client to the worker thread
                RedisClient client = (RedisClient)e.Argument;

                // download all keys (may take a while)
                List <String> rawKeys = client.GetAllKeys();

                // get cache
                String             cacheFile = BuildCacheFilename(serverHost, serverPort);
                RedisDatabaseCache cache     = new RedisDatabaseCache();
                cache.LoadFile(cacheFile);

                // handle cancellation
                if (loaderCancelling)
                {
                    // { overallSuccess, result, message }
                    e.Result = new Object[] { false, null, "RBF_ErrUserCancel" };
                    return;
                }

                // start getting info
                List <RedisTopLevelEntity> entities = new List <RedisTopLevelEntity>();
                for (int i = 0; i < rawKeys.Count; i++)
                {
                    String key = rawKeys[i];

                    // handle cancellation
                    if (loaderCancelling)
                    {
                        // { overallSuccess, result, message }
                        e.Result = new Object[] { false, null, "RBF_ErrUserCancel" };
                        return;
                    }

                    RedisTopLevelEntity entity = new RedisTopLevelEntity();
                    entity.Key = key;

                    if (cache.IsCached(key))
                    {
                        RedisDatabaseCache.CachedEntry ce = cache.GetCachedInfo(key);
                        entity.Type      = ce.Type;
                        entity.ExpiresAt = ce.TTL;
                    }
                    else
                    {
                        // get key data
                        entity.Type      = RedisTopLevelEntity.ParseType(client.GetEntryType(key));
                        entity.ExpiresAt = DateTime.Now + client.GetTimeToLive(key);

                        // update cache
                        cache.UpdateCache(entity);
                    }

                    entities.Add(entity);

                    asyncLoader.ReportProgress(0, new Object[] { "RBF_ProgressGetInfo", i, rawKeys.Count });
                }

                // save cache
                cache.WriteFile(cacheFile);

                // pass results back
                e.Result = new Object[] { true, entities, null };
            };
            asyncLoader.ProgressChanged += (Object o, ProgressChangedEventArgs e) =>
            {
                Object[] args    = (Object[])e.UserState;
                String   message = (String)args[0];
                Int32    current = (Int32)args[1];
                Int32    total   = (Int32)args[2];

                message = String.Format(locale.GetString(message), current, total);
                lblLoadingProgressDetails.Text = message;

                if (total != 0)
                {
                    Int32 percentage = (int)((double)current / (double)total * 100);
                    if (percentage >= 25 && percentage < 50)
                    {
                        lblLoadingStatusTitle.Text = locale.GetString("RBF_LP25");
                    }
                    else if (percentage >= 50 && percentage < 75)
                    {
                        lblLoadingStatusTitle.Text = locale.GetString("RBF_LP50");
                    }
                    else if (percentage >= 75 && percentage < 90)
                    {
                        lblLoadingStatusTitle.Text = locale.GetString("RBF_LP75");
                    }
                    else if (percentage >= 90)
                    {
                        lblLoadingStatusTitle.Text = locale.GetString("RBF_LP90");
                    }
                    pbLoadingProgress.Value = percentage;
                }
            };
            asyncLoader.RunWorkerCompleted += (Object o, RunWorkerCompletedEventArgs e) =>
            {
                Object[] args    = (Object[])e.Result;
                Boolean  success = (Boolean)args[0];
                List <RedisTopLevelEntity> entities = (List <RedisTopLevelEntity>)args[1];
                String message = (String)args[2];

                if (success)
                {
                    keys = entities;

                    // todo: update listview stuff

                    stateManager.SetCurrentState("wsConnected");

                    //olvKeys.SetObjects(keys);
                    olvKeys.VirtualListDataSource = new RedisKeysDataSource(keys);

                    // check if client command is supported
                    if (redisClient.ServerVersion < Version.Parse("2.4.0"))
                    {
                        OnClientListError(locale.GetString("RBF_ClientNotSupported"));
                    }
                    else
                    {
                        clientCommandSupported = true;
                    }
                }
                else
                {
                    MessageBox.Show(locale.GetString(message));

                    this.Close();
                }
            };
            asyncLoader.RunWorkerAsync(redisClient);
        }