// Chattr - Twitter client on .NET
//
// Copyright (c) 2007, 2008 Katsuhiko Ichinose <ichi@users.sourceforge.jp>
//
// Chattr is Free Software released under GNU General Public License.
//
// $Id: ChattrFormMain.cs 111 2008-06-13 16:10:58Z ichi $

using System;
using System.Collections.Generic;
using System.Text;

using System.ComponentModel;
using System.IO;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Net;
using System.Net.NetworkInformation;
using System.Xml;
using System.Web;
using System.Globalization;
using System.Collections;
using System.Runtime.InteropServices;
using System.Threading;
using System.Data.SQLite;
using System.Reflection;
using agsXMPP;

using System.Diagnostics;

namespace Chattr
{
    public partial class FormMain : Form
    {
        private static readonly string EXEC_PATH = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
        private static readonly string SQL_PATH = EXEC_PATH + @"\..\";

        private const string BG_FILL = "fill";
        private const string BG_LOAD = "load";
        private const string BG_LOADING = "loading";
        private const string BG_FOLLOWING = "following_timeline";
        private const string BG_USER = "user_timeline";
        private const string BG_REPLIES = "replies";
        private const string BG_DIRECT_MESSAGE = "direct_message";
        private const string BG_PROFILE_IMAGE = "profile_image";
        private const string BG_UPDATE = "update";
        private const string BG_TINYURL = "tinyurl";
        private const string BG_DELETE_ALL = "delete_all";
        private const string BG_FAVORITE = "favorite";
        private const string BG_SET_FLAG = "setflag";
        private const string BG_DUMMY = "";

        public const int NOTIFY_ALL = 0;
        public const int NOTIFY_INME = 1;
        public const int NOTIFY_KEYWORDS = 2;

        public const int PROXY_SYSTEM = 0;
        public const int PROXY_CHATTR = 1;

        public const int FLAG_INME = 0x01;
        public const int FLAG_KEYWORDS = 0x02;
        public const int FLAG_NEW = 0x04;
        public const int FLAG_DM = 0x10000000;
        private const int FLAG_FAVORITE = 0x100;

        private const int ICON_SIZE = 48;

        private const int MARGIN_LOAD = 100;

        private const float LINE_SPACE = 3.0F;

        private const int SINCE_POS = 0;

        public static readonly int RETRY_URL = 5;

        private enum ProgressOp
        {
            BG_FLAG = 0,
            STATUS_BAR,
            LABEL_STATUS,
            NUM_STATUS,
            LIST_ENABLE,
            LIST_BEGIN_UPDATE,
            LIST_END_UPDATE,
            LIST_ADD,
            LIST_INSERT,
            LIST_REPLACE,
            LIST_DELETE,
            LIST_REMOVE,
            LIST_REMOVES,
            LIST_SELECT,
            LIST_CLEAR,
            LIST_TOP_INDEX,
            LIST_SEARCH_BEGIN_UPDATE,
            LIST_SEARCH_END_UPDATE,
            LIST_SEARCH_ADD,
            LIST_SEARCH_INSERT,
            LIST_SEARCH_REPLACE,
            LIST_SEARCH_DELETE,
            LIST_SEARCH_REMOVE,
            LIST_SEARCH_REMOVES,
            LIST_SEARCH_SELECT,
            LIST_SEARCH_CLEAR,
            LIST_SEARCH_TOP_INDEX,
        }

        private enum LogLimit
        {
            NONE = 0,
            DAY1,
            DAY3,
            WEEK1,
            WEEK2,
            MONTH1,
            MONTH2,
            MONTH3,
            MONTH6,
            YEAR1,
        }

        public static Dictionary<string, int> DicUrl = new Dictionary<string, int>();

        private const int VALID_SPAN = 3;

        private const string LABEL_AVAILABLE = "Characters available: ";
        private const string REGEX_TINYURL = @"^((?:http|https)://(?:tinyurl\.com|urltea\.com|xrl\.us|z\.la)/[0-9a-zA-Z]+)";

        private LinkedList<IBackGround> m_BgWork = new LinkedList<IBackGround>();
        private bool m_fBgBusy = false;
        private bool m_fBgFlag;

        private FormPreferences m_Prefs;

        private bool m_fEnableFollowing = false;
        private DateTime m_TimeFollowing = DateTime.Now;
        private TimeSpan m_SpanFollowing = TimeSpan.Zero;
        private bool m_fEnableReplies = false;
        private DateTime m_TimeReplies = DateTime.Now;
        private TimeSpan m_SpanReplies = TimeSpan.Zero;
        private bool m_fEnableDM = false;
        private DateTime m_TimeDM = DateTime.Now;
        private TimeSpan m_SpanDM = TimeSpan.Zero;
        private DateTime m_TimeOfflineIn = DateTime.Now;
        private TimeSpan m_SpanOfflineFollowing = TimeSpan.Zero;
        private TimeSpan m_SpanOfflineReplies = TimeSpan.Zero;
        private TimeSpan m_SpanOfflineDM = TimeSpan.Zero;

        private DateTime m_SinceStatuses = DateTime.MaxValue;
        private DateTime m_SinceReplies = DateTime.MaxValue;
        private DateTime m_SinceDM = DateTime.MaxValue;

        private int m_Loading = 0;
        private int m_Load = 0;
        private long m_LastId = 0;

        private bool m_LoadDone = false;
        private DateTime m_LastDate;

        private XmppClientConnection m_Xmpp = null;

        private DataSetChattr.TableStatusDataTable m_TblSearch = null;
        private string m_Search;

        private int m_ListWidth;

        private FormBrowser m_Browser;
        private FormPopup m_Popup;
        //private FormLog m_Log;
        private FormPost m_Post;

        private ToolTip m_ToolTip = new ToolTip();

        private Mutex m_MutexStatus;
        private Mutex m_MutexSearch;
        private Mutex m_MutexProfile;
        private Mutex m_MutexTinyUrl;

        private Queue<bool> m_QueueProfile;
        private Queue<bool> m_QueueTnyUrl;

        private TableAdapterTransactor m_Tat;

        private int m_ContextMenuItems = 0;
        private int m_ContextMenuStatusesItems = 0;

        [DllImport("user32.dll")]
        static extern bool FlashWindow(IntPtr hwnd, bool bInvert);

        public void Navigate(string url)
        {
            try
            {
                if (Properties.Settings.Default.UseBuiltinBrowser)
                {
                    m_Browser.Navigate(url, m_Loading >= m_Load);
                }
                else
                {
                    System.Diagnostics.Process.Start(url);
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("Navigate() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
        }

        public void DeleteLog()
        {
            RequestDeleteAll();
        }

        static public WebProxy GetProxy()
        {
            WebProxy proxy = null;
            try
            {
                switch (Properties.Settings.Default.UseProxy)
                {
                    case PROXY_SYSTEM:
                        string twitter = "http://twitter.com/";
                        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(twitter);
                        System.Uri uri = req.Proxy.GetProxy(new System.Uri(twitter));
                        if (uri.AbsoluteUri != twitter)
                        {
                            proxy = new WebProxy(uri.Host, uri.Port);
                            if (req.Proxy.Credentials != null)
                            {
                                proxy.UseDefaultCredentials = false;
                                proxy.Credentials = req.Proxy.Credentials;
                            }
                        }
                        break;
                    default:
                        proxy = new WebProxy(Properties.Settings.Default.ProxyAddr, Properties.Settings.Default.ProxyPort);
                        if ((Properties.Settings.Default.ProxyUser != "") && (FormPreferences.GetProxyPass() != ""))
                        {
                            proxy.UseDefaultCredentials = false;
                            proxy.Credentials = new NetworkCredential(Properties.Settings.Default.ProxyUser, FormPreferences.GetProxyPass());
                        }
                        break;
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("GetProxy() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            return proxy;
        }

        private bool InitializeXmpp()
        {
            if (Properties.Settings.Default.UseXmpp && (Properties.Settings.Default.XmppID != "") && (m_Prefs.XmppPass != ""))
            {
                try
                {
                    m_Xmpp = new XmppClientConnection();
                    Jid jid = new Jid(Properties.Settings.Default.XmppID);
                    m_Xmpp.OnSocketError += new ErrorHandler(xmpp_OnSocketError);
                    m_Xmpp.OnError += new ErrorHandler(xmpp_OnError);
                    m_Xmpp.OnAuthError += new XmppElementHandler(xmpp_OnAuthError);
                    m_Xmpp.OnLogin += new ObjectHandler(xmpp_OnLogin);
                    m_Xmpp.OnIq += new agsXMPP.protocol.client.IqHandler(xmpp_OnIq);
                    m_Xmpp.OnMessage += new agsXMPP.protocol.client.MessageHandler(xmpp_OnMessage);
                    m_Xmpp.ConnectServer = Properties.Settings.Default.XmppServer;
                    m_Xmpp.Username = jid.User;
                    m_Xmpp.Server = jid.Server;
                    m_Xmpp.Password = m_Prefs.XmppPass;
                    m_Xmpp.Resource = "Chattr";
                    m_Xmpp.Port = Properties.Settings.Default.XmppPort;
                    //m_Xmpp.AutoResolveConnectServer = true;
                    //m_Xmpp.Priority = 10;
                    m_Xmpp.UseStartTLS = true;
                    //m_Xmpp.RegisterAccount = true;
                    m_Xmpp.UseSSL = Properties.Settings.Default.XmppUseSSL;
                    m_Xmpp.SocketConnectionType = agsXMPP.net.SocketConnectionType.Direct;
                    WebProxy proxy = GetProxy();
                    agsXMPP.net.ClientSocket socket = m_Xmpp.ClientSocket as agsXMPP.net.ClientSocket;
                    if (socket != null)
                    {
                        socket.Proxy = proxy;
                    }
                    return true;
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("InitializeXmpp() Error\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
            }
            return false;
        }

        private void XmppError(string msg, string caption)
        {
            MethodInvoker error = delegate
            {
                MessageBox.Show(this, msg, caption, MessageBoxButtons.OK, MessageBoxIcon.Error);
            };
            Invoke(error);
        }

        private void xmpp_OnSocketError(object sender, Exception ex)
        {
            XmppError("XMPPソケットエラー： " + ex.Message, "XMPP エラー");
            Debug.WriteLine("xmpp_OnSocketError: " + sender + ex);
        }

        private void xmpp_OnError(object sender, Exception ex)
        {
            XmppError("XMPPエラー： " + ex.Message, "XMPP エラー");
            Debug.WriteLine("xmpp_OnError: " + sender + ex);
        }

        private void xmpp_OnAuthError(object sender, agsXMPP.Xml.Dom.Element e)
        {
            XmppError("XMPP認証エラー", "XMPP エラー");
            Debug.WriteLine("xmpp_OnAuthError: " + sender + e);
        }

        private void xmpp_OnLogin(object sender)
        {
            Debug.WriteLine("xmpp_OnLogin: " + sender);
            m_Xmpp.SendMyPresence();
            m_Xmpp.Status = "OnLine";
            m_Xmpp.Show = agsXMPP.protocol.client.ShowType.chat;
        }

        private void xmpp_OnIq(object sender, agsXMPP.protocol.client.IQ iq)
        {
            Debug.WriteLine("xmpp_OnIq: " + sender + iq);
        }

        private void xmpp_OnMessage(object sender, agsXMPP.protocol.client.Message msg)
        {
            Debug.WriteLine("xmpp_OnMessage: " + sender + msg);
            RequestBackGround(msg);
        }

        private void OpenXmpp()
        {
            Debug.WriteLine("OpenXmpp()");
            try
            {
                if (NetworkInterface.GetIsNetworkAvailable())
                {
                    if (m_Xmpp == null)
                    {
                        if (InitializeXmpp())
                        {
                            m_Xmpp.Open();
                        }
                    }
                }
                else
                {
                    throw new WebException("Is not network available.", WebExceptionStatus.ConnectFailure);
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("OpenXmpp() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
        }

        private void CloseXmpp()
        {
            Debug.WriteLine("CloseXmpp()");
            try
            {
                if (m_Xmpp != null)
                {
                    //m_Xmpp.Status = "OffLine";
                    m_Xmpp.Show = agsXMPP.protocol.client.ShowType.NONE;
                    m_Xmpp.Close();
                    m_Xmpp = null;
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("CloseXmpp() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
        }

        private void InitializeTransactor()
        {
            m_Tat = new TableAdapterTransactor();
            m_Tat.AddTableAdapter(tableStatusTableAdapter);
        }

        private bool CommitTableStatus(DataSetChattr.TableStatusDataTable tableStatus)
        {
            bool result = false;
            try
            {
                m_Tat.BeginTransaction();
                tableStatusTableAdapter.Update(tableStatus);
                m_Tat.Commit();
                result = true;
            }
            catch (SystemException ex)
            {
                m_Tat.Rollback();
                Debug.WriteLine("CommitTableStatus() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            return result;
        }

        private void SetWindowTitle()
        {
            if (Properties.Settings.Default.UserName != "")
            {
                this.Text = Properties.Settings.Default.UserName + " - " + "Chattr";
            }
        }

        private void SetWindowSize()
        {
            if (Screen.AllScreens.Length > 1)
            {
                this.Location = Properties.Settings.Default.FormMainLocation2;
                this.Size = Properties.Settings.Default.FormMainSize2;
            }
            else
            {
                this.Location = Properties.Settings.Default.FormMainLocation;
                this.Size = Properties.Settings.Default.FormMainSize;
            }
        }

        private void SaveWindowSize()
        {
            if (this.Visible && (this.WindowState == FormWindowState.Normal))
            {
                if (Screen.AllScreens.Length > 1)
                {
                    Properties.Settings.Default.FormMainSize2 = this.Size;
                }
                else
                {
                    Properties.Settings.Default.FormMainSize = this.Size;
                }
            }
        }

        private void SaveWindowPosition()
        {
            if (this.Visible && (this.WindowState == FormWindowState.Normal))
            {
                if (Screen.AllScreens.Length > 1)
                {
                    Properties.Settings.Default.FormMainLocation2 = this.Location;
                }
                else
                {
                    Properties.Settings.Default.FormMainLocation = this.Location;
                }
            }
        }

        private void SetLocation()
        {
            foreach (string location in Regex.Split(Properties.Settings.Default.Locations, "\n"))
            {
                if ((location != "") && (location != "\r"))
                {
                    comboBoxLocation.Items.Add(location);
                }
            }
            if (Properties.Settings.Default.Location != "")
            {
                comboBoxLocation.ForeColor = Color.FromName(KnownColor.WindowText.ToString());
                comboBoxLocation.Text = Properties.Settings.Default.Location;
            }
        }

        private void UpdateLocation()
        {
            string locations = "";
            foreach (string location in comboBoxLocation.Items)
            {
                if (locations != "")
                {
                    locations += "\n";
                }
                locations += location;
            }
            Properties.Settings.Default.Locations = locations;
            if (comboBoxLocation.ForeColor != Color.FromName(KnownColor.GrayText.ToString()))
            {
                Properties.Settings.Default.Location = comboBoxLocation.Text;
            }
            else
            {
                Properties.Settings.Default.Location = "";
            }
        }

        static private SizeF MeasureString(Graphics graph, string s, Font font, float width)
        {
            SizeF size = new SizeF(0, 0);
            if (Properties.Settings.Default.LineSpace)
            {
                float height = font.GetHeight(graph);
                int length = s.Length;
                int pos = 0;
                if (Properties.Settings.Default.LineSpace)
                {
                    height += height / LINE_SPACE;
                }
                float mod = height % 1F;
                height = (float)((int)height);
                while (pos < length)
                {
                    string line = "";
                    while (pos < length)
                    {
                        if (s[pos] == '\n')
                        {
                            pos++;
                            break;
                        }
                        line += s[pos];
                        float w = graph.MeasureString(line, font).Width;
                        if ((width > 0) && (w > width))
                        {
                            int l = 1;
                            int p = line.Length - 2;
                            if ((p >= 0) && (line[p] < '\x2000') && (s[pos] < '\x2000') && (s[pos] != ' ') && (s[pos] != '　'))
                            {
                                while (p >= 0)
                                {
                                    if ((line[p] >= '\x2000') || (line[p] == ' ') || (line[p] == '　'))
                                    {
                                        break;
                                    }
                                    l++;
                                    p--;
                                }
                                if (p < 0)
                                {
                                    l = 1;
                                }
                                pos -= l - 1;
                            }
                            line = line.Substring(0, line.Length - l);
                            break;
                        }
                        pos++;
                        if (size.Width < w)
                        {
                            size.Width = w;
                        }
                    }
                    size.Height += height;
                }
                size.Height += mod;
            }
            else if (width > 0)
            {
                size = graph.MeasureString(s, font, (int)width);
            }
            else
            {
                size = graph.MeasureString(s, font);
            }
            return size;
        }

        static private void DrawString(Rectangle bounds, Graphics graph, string s, Font font, Brush brush, RectangleF rect, StringFormat format)
        {
            if (Properties.Settings.Default.LineSpace)
            {
                float height = font.GetHeight(graph);
                int length = s.Length;
                int pos = 0;
                if (Properties.Settings.Default.LineSpace)
                {
                    height += height / LINE_SPACE;
                }
                height = (float)((int)height);
                format.Trimming = StringTrimming.None;
                while ((pos < length) && ((int)rect.Height >= height) && (rect.Y + height <= bounds.Bottom))
                {
                    string line = "";
                    while (pos < length)
                    {
                        if (s[pos] == '\n')
                        {
                            pos++;
                            break;
                        }
                        line += s[pos];
                        if (graph.MeasureString(line, font).Width > rect.Width)
                        {
                            int l = 1;
                            int p = line.Length - 2;
                            if ((p >= 0) && (line[p] < '\x2000') && (s[pos] < '\x2000') && (s[pos] != ' ') && (s[pos] != '　'))
                            {
                                while (p >= 0)
                                {
                                    if ((line[p] >= '\x2000') || (line[p] == ' ') || (line[p] == '　'))
                                    {
                                        break;
                                    }
                                    l++;
                                    p--;
                                }
                                if (p < 0)
                                {
                                    l = 1;
                                }
                                pos -= l - 1;
                            }
                            line = line.Substring(0, line.Length - l);
                            if (!Properties.Settings.Default.NotEllipsis && (pos < length) && (rect.Y + height * 2 > bounds.Bottom))
                            {
                                line = line.Substring(0, line.Length - 1);
                                line += "…";
                                while (graph.MeasureString(line, font).Width > rect.Width)
                                {
                                    line = line.Substring(0, line.Length - 2);
                                    line += "…";
                                }
                            }
                            break;
                        }
                        pos++;
                    }
                    if (line != "")
                    {
                        graph.DrawString(line, font, brush, rect, format);
                    }
                    rect.Y += height;
                    rect.Height -= height;
                }
            }
            else
            {
                graph.DrawString(s, font, brush, rect, format);
            }
        }

        static private String MeasureDate(ListBox listBox, Rectangle bounds, Graphics graph, DataSetChattr.TableStatusRow row, ref SizeF sizeF, ref RectangleF rectF)
        {
            DateTime at = row.created_at.ToLocalTime();
            String str = at.ToString("HH:mm\nMM/dd");
            sizeF = MeasureString(graph, str, Properties.Settings.Default.FontTime, -1);
            rectF = (RectangleF)bounds;
            rectF.X = rectF.Right - sizeF.Width - 2;
            rectF.Width = sizeF.Width;
            rectF.Y += 3;
            if (Properties.Settings.Default.StatusSpace)
            {
                rectF.Y += 3;
            }
            rectF.Height = sizeF.Height;
            return str;
        }

        static private String MeasureText(ListBox listBox, Rectangle bounds, Graphics graph, DataSetChattr.TableStatusRow row, bool selected, int width, SizeF sizeAt, ref SizeF sizeF, ref RectangleF rectF)
        {
            String str = row.user_screen_name;
            rectF = (RectangleF)bounds;
            if (Properties.Settings.Default.SmallIcon)
            {
                str += "  " + Regex.Replace(row.text, "\n", Properties.Settings.Default.NotEllipsis ? "\n" : " ");
                if (Properties.Settings.Default.IndicateFrom && (row.source != ""))
                {
                    str += "  from " + row.source;
                }
                if (Properties.Settings.Default.NotEllipsis)
                {
                    SizeF z = MeasureString(graph, "　\n　", Properties.Settings.Default.FontStatuses, -1);
                    if (z.Height > width)
                    {
                        rectF.X = z.Height + 4;
                    }
                    else
                    {
                        rectF.X = width + 4;
                    }
                    z = new SizeF(rectF.Width - (sizeAt.Width + rectF.X + 2), 255);
                    sizeF = MeasureString(graph, str, Properties.Settings.Default.FontStatuses, z.Width);
                }
                else
                {
                    sizeF = MeasureString(graph, "　\n　", Properties.Settings.Default.FontStatuses, -1);
                    if (sizeF.Height > width)
                    {
                        rectF.X = sizeF.Height + 4;
                    }
                    else
                    {
                        rectF.X = width + 4;
                    }
                }
            }
            else
            {
                if ((row.user_name != "") && (row.user_name != row.user_screen_name))
                {
                    str += " / " + row.user_name;
                }
                str += "\n" + Regex.Replace(row.text, "\n", Properties.Settings.Default.NotEllipsis ? "\n" : " ");
                if (Properties.Settings.Default.IndicateFrom && (row.source != ""))
                {
                    str += "  from " + row.source;
                }
                if (Properties.Settings.Default.NotEllipsis)
                {
                    SizeF z = new SizeF(rectF.Width - (sizeAt.Width + ICON_SIZE + 6), 255);
                    sizeF = MeasureString(graph, str, Properties.Settings.Default.FontStatuses, z.Width);
                }
                else
                {
                    sizeF = MeasureString(graph, "　\n　\n　", Properties.Settings.Default.FontStatuses, -1);
                }
                if (sizeF.Height < ICON_SIZE)
                {
                    sizeF.Height = ICON_SIZE;
                }
                rectF.X = ICON_SIZE + 4;
            }
            rectF.Width -= sizeAt.Width + rectF.X + 2;
            rectF.Y += 3;
            if (Properties.Settings.Default.StatusSpace)
            {
                rectF.Y += 3;
            }
            rectF.Height = sizeF.Height;
            return str;
        }

        static public int listBox_MeasureItem(ListBox listBox, MeasureItemEventArgs e, DataSetChattr.TableStatusDataTable table, Mutex mutex, int listWidth)
        {
            int height = ICON_SIZE;
            if (table != null)
            {
                mutex.WaitOne();
                try
                {
                    Rectangle bounds = new Rectangle(0, 0, listWidth - 21, e.ItemHeight);
                    bool selected = (e.Index == listBox.SelectedIndex);
                    SizeF sizeAt = SizeF.Empty;
                    SizeF sizeF = SizeF.Empty;
                    RectangleF rectF = RectangleF.Empty;
                    int idx = e.Index;
                    if ((idx < 0) || (idx >= table.Rows.Count))
                    {
                        idx = 0;
                    }
                    IListItem item = listBox.Items[idx] as IListItem;
                    long id = item.Id;
                    int i = idx - 100;
                    if (i < 0)
                    {
                        i = 0;
                    }
                    int cnt = table.Rows.Count;
                    DataSetChattr.TableStatusRow row = table.Rows[i] as DataSetChattr.TableStatusRow;
                    while (i < cnt)
                    {
                        if ((row.RowState != DataRowState.Deleted) && (row.id == id))
                        {
                            break;
                        }
                        i++;
                        row = table.Rows[i] as DataSetChattr.TableStatusRow;
                    }
                    if (i >= cnt)
                    {
                        row = table.Rows[0] as DataSetChattr.TableStatusRow;
                        Debug.Assert(false, "listBox_MeasureItem: not found");
                    }
                    MeasureDate(listBox, bounds, e.Graphics, row, ref sizeAt, ref rectF);
                    int width = (int)(sizeAt.Height + 0.5);
                    if (width > ICON_SIZE)
                    {
                        width = ICON_SIZE;
                    }
                    MeasureText(listBox, bounds, e.Graphics, row, selected, width, sizeAt, ref sizeF, ref rectF);
                    height = (int)(sizeF.Height + 0.5);
                    if (height < width)
                    {
                        height = width;
                    }
                    height += 5;
                    if (Properties.Settings.Default.StatusSpace)
                    {
                        height += 6;
                    }
                    if (height > 255)
                    {
                        height = 255;
                    }
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("listBox_MeasureItem() Error\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
            return height;
        }

        static public void listBox_DrawItem(ListBox listBox, DrawItemEventArgs e, DataSetChattr.TableStatusDataTable table, Mutex mutex, DataSetChattr.TableProfileImageDataTable profileImage)
        {
            if (table != null)
            {
                mutex.WaitOne();
                try
                {
                    if ((e.Index >= 0) && (e.Index < listBox.Items.Count))
                    {
                        bool selected = (listBox.SelectionMode != SelectionMode.None) && ((e.State & DrawItemState.Selected) != 0);
                        int idx = e.Index;
                        DataSetChattr.TableStatusRow row = table.Rows[idx] as DataSetChattr.TableStatusRow;
                        // Brush
                        Brush brushText;
                        Brush brushTextAt;
                        Brush brushBg;
                        if (selected)
                        {
                            brushText = new SolidBrush(Properties.Settings.Default.ColorHighlight);
                            brushTextAt = new SolidBrush(Properties.Settings.Default.ColorHighlight);
                            brushBg = new SolidBrush(Properties.Settings.Default.BgColorHighlight);
                        }
                        else if ((row.flags & FLAG_DM) != 0)
                        {
                            brushText = new SolidBrush(Properties.Settings.Default.ColorDirectMessage);
                            brushTextAt = new SolidBrush(Properties.Settings.Default.ColorDirectMessage);
                            brushBg = new SolidBrush(Properties.Settings.Default.BgColorDirectMessage);
                        }
                        else if ((row.flags & FLAG_INME) != 0)
                        {
                            brushText = new SolidBrush(Properties.Settings.Default.ColorInMe);
                            brushTextAt = new SolidBrush(Properties.Settings.Default.ColorInMe);
                            brushBg = new SolidBrush(Properties.Settings.Default.BgColorInMe);
                        }
                        else if ((row.flags & FLAG_KEYWORDS) != 0)
                        {
                            brushText = new SolidBrush(Properties.Settings.Default.ColorKeywords);
                            brushTextAt = new SolidBrush(Properties.Settings.Default.ColorKeywords);
                            brushBg = new SolidBrush(Properties.Settings.Default.BgColorKeywords);
                        }
                        else if ((row.flags & FLAG_NEW) != 0)
                        {
                            brushText = new SolidBrush(Properties.Settings.Default.ColorNew);
                            brushTextAt = new SolidBrush(Properties.Settings.Default.ColorNew);
                            brushBg = new SolidBrush(Properties.Settings.Default.BgColorNew);
                        }
                        else
                        {
                            brushText = new SolidBrush(Properties.Settings.Default.ColorText);
                            brushTextAt = new SolidBrush(Properties.Settings.Default.ColorText);
                            brushBg = new SolidBrush(Properties.Settings.Default.BgColor);
                        }
                        // Date
                        SizeF sizeAt = SizeF.Empty;
                        RectangleF rectAt = RectangleF.Empty;
                        String strAt = MeasureDate(listBox, e.Bounds, e.Graphics, row, ref sizeAt, ref rectAt);
                        // Status
                        int height = (int)(sizeAt.Height + 0.5);
                        SizeF sizeF = SizeF.Empty;
                        RectangleF rectF = RectangleF.Empty;
                        String text = MeasureText(listBox, e.Bounds, e.Graphics, row, selected, height, sizeAt, ref sizeF, ref rectF);
                        StringFormat format = StringFormat.GenericDefault;
                        format.Alignment = StringAlignment.Near;
                        format.Trimming = StringTrimming.EllipsisCharacter;
                        // ICON
                        DataSetChattr.TableProfileImageRow pro = profileImage.Rows.Find(row.user_profile_image) as DataSetChattr.TableProfileImageRow;
                        Bitmap bmp = null;
                        int iconHeight = height;
                        if (pro != null)
                        {
                            if (iconHeight < (int)rectF.X - 4)
                            {
                                iconHeight = (int)rectF.X - 4;
                            }
                            if ((!Properties.Settings.Default.SmallIcon) || (iconHeight > ICON_SIZE))
                            {
                                iconHeight = ICON_SIZE;
                            }
                            bmp = new Bitmap(ByteArray2Bitmap(pro.image, pro.width, pro.height), iconHeight, iconHeight);
                        }
                        // Draw
                        e.Graphics.FillRectangle(brushBg, e.Bounds);
                        if (bmp != null)
                        {
                            float y = 0;
                            if (Properties.Settings.Default.StatusSpace)
                            {
                                y += 3;
                            }
                            e.Graphics.DrawImage(bmp, e.Bounds.X + 2, e.Bounds.Y + 2 + y);
                            if ((row.flags & FLAG_DM) != 0)
                            {
                                e.Graphics.DrawImage(Properties.Resources.mail, e.Bounds.X + 2 + 1, e.Bounds.Y + 2 + y + (bmp.Height - Properties.Resources.mail.Height) - 4);
                            }
                        }
                        DrawString(e.Bounds, e.Graphics, text, Properties.Settings.Default.FontStatuses, brushText, rectF, format);
                        format = StringFormat.GenericDefault;
                        format.Alignment = StringAlignment.Center;
                        DrawString(e.Bounds, e.Graphics, strAt, Properties.Settings.Default.FontTime, brushTextAt, rectAt, format);
                        e.Graphics.DrawLine(new Pen(Color.FromName(KnownColor.ControlDark.ToString())), e.Bounds.X, e.Bounds.Bottom - 1, e.Bounds.Right - 1, e.Bounds.Bottom - 1);
                        if (selected)
                        {
                            e.DrawFocusRectangle();
                        }
                    }
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("listBox_DrawItem() Error\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
        }

        private void listBox_KeyDown(ListBox listBox, KeyEventArgs e, DataSetChattr.TableStatusDataTable table, Mutex mutex)
        {
            switch (e.KeyData)
            {
                case Keys.Enter:
                    listBox_DoubleClick(listBox, e, table, mutex);
                    e.Handled = true;
                    break;
                case Keys.Control | Keys.Down:
                    mutex.WaitOne();
                    try
                    {
                        int cnt = listBox.Items.Count;
                        int idx = listBox.SelectedIndex;
                        while (idx < cnt)
                        {
                            DataSetChattr.TableStatusRow row = table.Rows[idx] as DataSetChattr.TableStatusRow;
                            if ((row.flags & FLAG_NEW) != 0)
                            {
                                listBox.SelectedIndex = idx;
                                break;
                            }
                            idx++;
                        }
                    }
                    finally
                    {
                        mutex.ReleaseMutex();
                    }
                    e.Handled = true;
                    break;
                case Keys.Control | Keys.Up:
                    mutex.WaitOne();
                    try
                    {
                        int idx = listBox.SelectedIndex;
                        while (idx >= 0)
                        {
                            DataSetChattr.TableStatusRow row = table.Rows[idx] as DataSetChattr.TableStatusRow;
                            if ((row.flags & FLAG_NEW) != 0)
                            {
                                listBox.SelectedIndex = idx;
                                break;
                            }
                            idx--;
                        }
                    }
                    finally
                    {
                        mutex.ReleaseMutex();
                    }
                    e.Handled = true;
                    break;
            }
        }

        private void listBox_DoubleClick(ListBox listBox, EventArgs e, DataSetChattr.TableStatusDataTable table, Mutex mutex)
        {
            if (table != null)
            {
                mutex.WaitOne();
                try
                {
                    int i = listBox.SelectedIndex;
                    if (i >= 0)
                    {
                        DataSetChattr.TableStatusRow row = table.Rows[i] as DataSetChattr.TableStatusRow;
                        if (row != null)
                        {
                            if ((row.flags & FLAG_DM) == 0)
                            {
                                EntryReply(listBox, e, table, mutex);
                            }
                            else
                            {
                                EntryDirectMessage(listBox, e, table, mutex);
                            }
                        }
                    }
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("listBox_DoubleClick() Error\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
        }

        private bool listBox_SelectedIndexChanged(ListBox listBox, EventArgs e, DataSetChattr.TableStatusDataTable table, Mutex mutex, ref int idx)
        {
            bool change = false;
            idx = ListBox.NoMatches;
            if (table != null)
            {
                idx = listBox.SelectedIndex;
                if ((idx >= 0) && (idx < table.Rows.Count))
                {
                    mutex.WaitOne();
                    try
                    {
                        DataSetChattr.TableStatusRow row = table.Rows[idx] as DataSetChattr.TableStatusRow;
                        if (row.RowState != DataRowState.Deleted)
                        {
                            StatusParser parser = new StatusParser(row.text);
                            contextMenuStripStatusesMake(contextMenuStripStatuses, row, parser, true);
                            int flags = row.flags;
                            flags &= (~FLAG_NEW);
                            LinkedList<string> urls = parser.URLs;
                            if (urls.Count > 0)
                            {
                                LinkedListNode<string> node = urls.First;
                                while (node != null)
                                {
                                    RequestTinyUrl(node.Value);
                                    node = node.Next;
                                }
                            }
                            //if (!ParseKeyword(parser, row))
                            //{
                            //    flags &= (~FLAG_KEYWORDS);
                            //}
                            if (row.flags != flags)
                            {
                                row.flags = flags;
                                change = true;
                            }
                            RequestProfileImage(row.user_profile_image);
                        }
                    }
                    catch (SystemException ex)
                    {
                        Debug.WriteLine("listBox_SelectedIndexChanged() Error\n" +
                            ex.Message + "\n" + "Source: " + ex.Source);
                    }
                    finally
                    {
                        mutex.ReleaseMutex();
                    }
                }
            }
            return change;
        }

        private void listBox_MouseDown(ListBox listBox, MouseEventArgs e, DataSetChattr.TableStatusDataTable table, Mutex mutex)
        {
            if ((table != null) && (e.Button == MouseButtons.Right))
            {
                int idx = listBox.IndexFromPoint(e.Location);
                if (idx != ListBox.NoMatches)
                {
                    listBox.SelectedIndex = idx;
                }
            }
        }

        private void contextMenuStripStatusesMake(ContextMenuStrip menuStrip, DataSetChattr.TableStatusRow row, StatusParser parser, bool shortcut)
        {
            while (menuStrip.Items.Count > m_ContextMenuStatusesItems)
            {
                menuStrip.Items.RemoveAt(m_ContextMenuStatusesItems);
            }
            while (contextMenuStrip.Items.Count > m_ContextMenuItems)
            {
                contextMenuStrip.Items.RemoveAt(m_ContextMenuItems);
            }
            if ((row.flags & FLAG_DM) == 0)
            {
                menuStrip.Items[3].Enabled = true;
            }
            else
            {
                menuStrip.Items[3].Enabled = false;
            }
            // User
            menuStrip.Items.Add(new ToolStripSeparator());
            contextMenuStrip.Items.Add(new ToolStripSeparator());
            string owner = row.user_screen_name;
            if ((row.user_name != "") && (row.user_name != row.user_screen_name))
            {
                owner += " / " + row.user_name;
            }
            ToolStripMenuItem item = new ToolStripMenuItem(owner);
            item.ShortcutKeys = Keys.Control | Keys.U;
            item.ShowShortcutKeys = shortcut;
            item.Click += new EventHandler(contextMenuStripStatusesUser_Click);
            menuStrip.Items.Add(item);
            contextMenuStrip.Items.Add(new ToolStripMenuItem(item.Text, null, new EventHandler(contextMenuStripStatusesUser_Click), item.ShortcutKeys));
            if (row.id >= 0)
            {
                item = new ToolStripMenuItem("http://twitter.com/" + row.user_screen_name + "/statuses/" + row.id);
                item.ShortcutKeys = Keys.Control | Keys.S;
                item.ShowShortcutKeys = shortcut;
                item.Click += new EventHandler(contextMenuStripStatusesLink_Click);
                menuStrip.Items.Add(item);
                contextMenuStrip.Items.Add(new ToolStripMenuItem(item.Text, null, new EventHandler(contextMenuStripStatusesLink_Click), item.ShortcutKeys));
            }
            LinkedList<string> users = parser.Users;
            if (users.Count > 0)
            {
                int n = 0;
                menuStrip.Items.Add(new ToolStripSeparator());
                contextMenuStrip.Items.Add(new ToolStripSeparator());
                LinkedListNode<string> node = users.First;
                while (node != null)
                {
                    item = new ToolStripMenuItem(node.Value);
                    item.ShowShortcutKeys = shortcut;
                    switch (n)
                    {
                        case 0: item.ShortcutKeys = Keys.Control | Keys.Shift | Keys.D1; break;
                        case 1: item.ShortcutKeys = Keys.Control | Keys.Shift | Keys.D2; break;
                        case 2: item.ShortcutKeys = Keys.Control | Keys.Shift | Keys.D3; break;
                        case 3: item.ShortcutKeys = Keys.Control | Keys.Shift | Keys.D4; break;
                        case 4: item.ShortcutKeys = Keys.Control | Keys.Shift | Keys.D5; break;
                        case 5: item.ShortcutKeys = Keys.Control | Keys.Shift | Keys.D6; break;
                        case 6: item.ShortcutKeys = Keys.Control | Keys.Shift | Keys.D7; break;
                        case 7: item.ShortcutKeys = Keys.Control | Keys.Shift | Keys.D8; break;
                        case 8: item.ShortcutKeys = Keys.Control | Keys.Shift | Keys.D9; break;
                        case 9: item.ShortcutKeys = Keys.Control | Keys.Shift | Keys.D0; break;
                        default: item.ShowShortcutKeys = false; break;
                    }
                    item.Click += new EventHandler(contextMenuStripStatusesUser_Click);
                    menuStrip.Items.Add(item);
                    contextMenuStrip.Items.Add(new ToolStripMenuItem(item.Text, null, new EventHandler(contextMenuStripStatusesUser_Click), item.ShortcutKeys));
                    n++;
                    node = node.Next;
                }
            }
            // Link
            LinkedList<string> urls = parser.URLs;
            if (urls.Count > 0)
            {
                int n = 0;
                menuStrip.Items.Add(new ToolStripSeparator());
                contextMenuStrip.Items.Add(new ToolStripSeparator());
                LinkedListNode<string> node = urls.First;
                while (node != null)
                {
                    string u = node.Value;
                    Image img = null;
                    Regex r = new Regex(REGEX_TINYURL);
                    Match m = r.Match(u);
                    if (m.Success)
                    {
                        DataSetChattr.TableTinyUrlRow tiny = (DataSetChattr.TableTinyUrlRow)dataSetChattr.TableTinyUrl.Rows.Find(m.Groups[0].Value);
                        if (tiny != null)
                        {
                            u = Regex.Replace(u, REGEX_TINYURL, tiny.url);
                        }
                    }
                    u = Regex.Replace(u, "&", "&&");
                    if (img != null)
                    {
                        item = new ToolStripMenuItem(u, img);
                    }
                    else
                    {
                        item = new ToolStripMenuItem(u);
                    }
                    item.ShowShortcutKeys = shortcut;
                    switch (n)
                    {
                        case 0: item.ShortcutKeys = Keys.Control | Keys.D1; break;
                        case 1: item.ShortcutKeys = Keys.Control | Keys.D2; break;
                        case 2: item.ShortcutKeys = Keys.Control | Keys.D3; break;
                        case 3: item.ShortcutKeys = Keys.Control | Keys.D4; break;
                        case 4: item.ShortcutKeys = Keys.Control | Keys.D5; break;
                        case 5: item.ShortcutKeys = Keys.Control | Keys.D6; break;
                        case 6: item.ShortcutKeys = Keys.Control | Keys.D7; break;
                        case 7: item.ShortcutKeys = Keys.Control | Keys.D8; break;
                        case 8: item.ShortcutKeys = Keys.Control | Keys.D9; break;
                        case 9: item.ShortcutKeys = Keys.Control | Keys.D0; break;
                        default: item.ShowShortcutKeys = false; break;
                    }
                    item.Click += new EventHandler(contextMenuStripStatusesLink_Click);
                    menuStrip.Items.Add(item);
                    contextMenuStrip.Items.Add(new ToolStripMenuItem(item.Text, null, new EventHandler(contextMenuStripStatusesLink_Click), item.ShortcutKeys));
                    n++;
                    node = node.Next;
                }
            }
            // Location
            LinkedList<string> locations = parser.Locations;
            if (locations.Count > 0)
            {
                int n = 0;
                menuStrip.Items.Add(new ToolStripSeparator());
                contextMenuStrip.Items.Add(new ToolStripSeparator());
                LinkedListNode<string> node = locations.First;
                while (node != null)
                {
                    Match m;
                    if ((m = (new Regex(@"^(.*?)[\[\*_]")).Match(node.Value)).Success)
                    {
                        item = new ToolStripMenuItem("L:" + m.Groups[1].Value);
                    }
                    else
                    {
                        item = new ToolStripMenuItem("L:" + node.Value);
                    }
                    if (n == 0)
                    {
                        item.ShortcutKeys = Keys.Control | Keys.L;
                        item.ShowShortcutKeys = shortcut;
                    }
                    item.Click += new EventHandler(contextMenuStripStatusesLocation_Click);
                    menuStrip.Items.Add(item);
                    contextMenuStrip.Items.Add(new ToolStripMenuItem(item.Text, null, new EventHandler(contextMenuStripStatusesLocation_Click), item.ShortcutKeys));
                    n++;
                    node = node.Next;
                }
            }
            // 未読クリア
            menuStrip.Items.Add(new ToolStripSeparator());
            contextMenuStrip.Items.Add(new ToolStripSeparator());
            item = new ToolStripMenuItem("全ての未読をクリア(&C)");
            item.ShortcutKeys = Keys.Control | Keys.Shift | Keys.C;
            item.ShowShortcutKeys = shortcut;
            item.Click += new EventHandler(contextMenuStripStatusesClear_Click);
            menuStrip.Items.Add(item);
            contextMenuStrip.Items.Add(new ToolStripMenuItem(item.Text, null, new EventHandler(contextMenuStripStatusesClear_Click), item.ShortcutKeys));
        }

        private void contextMenuStripStatusesUser_Click(object sender, EventArgs e)
        {
            if (sender.GetType() == typeof(ToolStripMenuItem))
            {
                ToolStripMenuItem item = (ToolStripMenuItem)sender;
                Debug.WriteLine("contextMenuStripStatusesUser_Click: " + item.Text);
                string user = item.Text;
                Match m;
                if ((m = (new Regex(@"^(.*?) / ")).Match(user)).Success)
                {
                    user = m.Groups[1].Value;
                }
                Navigate("http://twitter.com/" + user + "/");
            }
        }

        private void contextMenuStripStatusesLink_Click(object sender, EventArgs e)
        {
            if (sender.GetType() == typeof(ToolStripMenuItem))
            {
                ToolStripMenuItem item = (ToolStripMenuItem)sender;
                Debug.WriteLine("contextMenuStripStatusesLink_Click: " + item.Text);
                Regex r = new Regex(@"^http");
                Match m = r.Match(item.Text);
                if (m.Success)
                {
                    string url = item.Text;
                    r = new Regex(@"^(.*://)(tinyurl\.com.*)$");
                    m = r.Match(item.Text);
                    if (m.Success)
                    {
                        url = m.Groups[1].Value + "preview." + m.Groups[2].Value;
                    }
                    Navigate(url);
                }
            }
        }

        private void contextMenuStripStatusesLocation_Click(object sender, EventArgs e)
        {
            if (sender.GetType() == typeof(ToolStripMenuItem))
            {
                ToolStripMenuItem item = (ToolStripMenuItem)sender;
                Debug.WriteLine("contextMenuStripStatusesLocation_Click: " + item.Text);
                string location = item.Text;
                Match m;
                if ((m = new Regex(@"^L:(.*)$").Match(location)).Success)
                {
                    location = m.Groups[1].Value;
                }
                Navigate("http://maps.google.co.jp/maps?oe=UTF-8&hl=ja&tab=wl&q=" + System.Uri.EscapeDataString(location) + "&ie=UTF8&z=14");
            }
        }

        void contextMenuStripStatusesClear_Click(object sender, EventArgs e)
        {
            if (sender.GetType() == typeof(ToolStripMenuItem))
            {
                ListBox listBox = listBoxStatuses;
                DataSetChattr.TableStatusDataTable table = dataSetChattr.TableStatus;
                Mutex mutex = m_MutexStatus;
                if (m_TblSearch != null)
                {
                    listBox = listBoxSearch;
                    table = m_TblSearch;
                    mutex = m_MutexSearch;
                }
                ClearNew(listBox, e, table, mutex);
            }
        }

        private void EnterTextBox(string text)
        {
            textBoxStatus.Text = text;
            textBoxStatus.SelectionStart = textBoxStatus.Text.Length;
            textBoxStatus.SelectionLength = 0;
        }

        private void EntryReply(ListBox listBox, EventArgs e, DataSetChattr.TableStatusDataTable table, Mutex mutex)
        {
            if (table != null)
            {
                mutex.WaitOne();
                try
                {
                    if (textBoxStatus.Enabled)
                    {
                        int i = listBox.SelectedIndex;
                        if (i >= 0)
                        {
                            DataSetChattr.TableStatusRow row = table.Rows[i] as DataSetChattr.TableStatusRow;
                            textBoxStatus.Focus();
                            EnterTextBox("@" + row.user_screen_name + " " + textBoxStatus.Text);
                        }
                    }
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("ReplyTextBox() Error\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
        }

        private void EntryDirectMessage(ListBox listBox, EventArgs e, DataSetChattr.TableStatusDataTable table, Mutex mutex)
        {
            if (table != null)
            {
                mutex.WaitOne();
                try
                {
                    if (textBoxStatus.Enabled)
                    {
                        int i = listBox.SelectedIndex;
                        if (i >= 0)
                        {
                            DataSetChattr.TableStatusRow row = table.Rows[i] as DataSetChattr.TableStatusRow;
                            textBoxStatus.Focus();
                            EnterTextBox("d " + row.user_screen_name + " " + textBoxStatus.Text);
                        }
                    }
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("DirectMessageTextBox() Error\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
        }

        private void Favorite(ListBox listBox, EventArgs e, DataSetChattr.TableStatusDataTable table, Mutex mutex)
        {
            if (table != null)
            {
                mutex.WaitOne();
                try
                {
                    int idx = listBox.SelectedIndex;
                    if ((idx >= 0) && (idx < table.Rows.Count))
                    {
                        DataSetChattr.TableStatusRow row = table.Rows[idx] as DataSetChattr.TableStatusRow;
                        long id = row.id;
                        if (id >= 0)
                        {
                            RequestFavorite(id);
                        }
                        else
                        {
                            row.flags |= FLAG_FAVORITE;
                            SetToolStripStatusLabelText("お気に入り登録を予約しました");
                        }
                    }
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("Favorite() Error\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
        }

        private void Reblog(ListBox listBox, EventArgs e, DataSetChattr.TableStatusDataTable table, Mutex mutex)
        {
            if ((table != null) && (textBoxStatus.Enabled))
            {
                mutex.WaitOne();
                try
                {
                    int idx = listBox.SelectedIndex;
                    if ((idx >= 0) && (idx < table.Rows.Count))
                    {
                        textBoxStatus.Focus();
                        DataSetChattr.TableStatusRow row = table.Rows[idx] as DataSetChattr.TableStatusRow;
                        EnterTextBox("@reblog " + row.text);
                    }
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("Reblog() Error\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
        }

        private void ClearNew(ListBox listBox, EventArgs e, DataSetChattr.TableStatusDataTable table, Mutex mutex)
        {
            if ((table != null) && (textBoxStatus.Enabled))
            {
                mutex.WaitOne();
                try
                {
                    int n = 0;
                    int cnt = table.Rows.Count;
                    for (int i = 0 ; i < cnt ; i++)
                    {
                        DataSetChattr.TableStatusRow row = table.Rows[i] as DataSetChattr.TableStatusRow;
                        if ((row.flags & FLAG_NEW) != 0)
                        {
                            row.flags &= ~FLAG_NEW;
                            n++;
                        }
                    }
                    if (n > 0)
                    {
                        listBox.BeginUpdate();
                        listBox.EndUpdate();
                    }
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("ClearNew() Error\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
        }

        public void PostContextMenuStripMake(ContextMenuStrip menuStrip, long id)
        {
            m_MutexStatus.WaitOne();
            try
            {
                if (id < 0)
                {
                    DataSetChattr.TableIdRow r = dataSetChattr.TableId.FindByid(id);
                    if (r != null)
                    {
                        id = r.replace;
                    }
                }
                DataSetChattr.TableStatusRow row = dataSetChattr.TableStatus.FindByid(id) as DataSetChattr.TableStatusRow;
                if (row != null)
                {
                    StatusParser parser = new StatusParser(row.text);
                    contextMenuStripStatusesMake(menuStrip, row, parser, false);
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("ContextMenuStripMake() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            finally
            {
                m_MutexStatus.ReleaseMutex();
            }
        }

        public void PostReply(long id)
        {
            m_MutexStatus.WaitOne();
            try
            {
                if (id < 0)
                {
                    DataSetChattr.TableIdRow r = dataSetChattr.TableId.FindByid(id);
                    if (r != null)
                    {
                        id = r.replace;
                    }
                }
                DataSetChattr.TableStatusRow row = dataSetChattr.TableStatus.FindByid(id) as DataSetChattr.TableStatusRow;
                if (row != null)
                {
                    m_Post.InsertText("@" + row.user_screen_name + " ");
                    m_Post.Show();
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("PostReply() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            finally
            {
                m_MutexStatus.ReleaseMutex();
            }
        }

        public void PostDirectMessage(long id)
        {
            m_MutexStatus.WaitOne();
            try
            {
                if (id < 0)
                {
                    DataSetChattr.TableIdRow r = dataSetChattr.TableId.FindByid(id);
                    if (r != null)
                    {
                        id = r.replace;
                    }
                }
                DataSetChattr.TableStatusRow row = dataSetChattr.TableStatus.FindByid(id) as DataSetChattr.TableStatusRow;
                if (row != null)
                {
                    m_Post.InsertText("d " + row.user_screen_name + " ");
                    m_Post.Show();
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("PostDirectMessage() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            finally
            {
                m_MutexStatus.ReleaseMutex();
            }
        }

        public void PostFavorite(long id)
        {
            m_MutexStatus.WaitOne();
            try
            {
                if (id < 0)
                {
                    DataSetChattr.TableIdRow r = dataSetChattr.TableId.FindByid(id);
                    if (r != null)
                    {
                        id = r.replace;
                    }
                }
                DataSetChattr.TableStatusRow row = dataSetChattr.TableStatus.FindByid(id) as DataSetChattr.TableStatusRow;
                if (row != null)
                {
                    if (id >= 0)
                    {
                        RequestFavorite(id);
                    }
                    else
                    {
                        row.flags |= FLAG_FAVORITE;
                        SetToolStripStatusLabelText("お気に入り登録を予約しました");
                    }
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("PostFavorite() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            finally
            {
                m_MutexStatus.ReleaseMutex();
            }
        }

        public void PostReblog(long id)
        {
            m_MutexStatus.WaitOne();
            try
            {
                if (id < 0)
                {
                    DataSetChattr.TableIdRow r = dataSetChattr.TableId.FindByid(id);
                    if (r != null)
                    {
                        id = r.replace;
                    }
                }
                DataSetChattr.TableStatusRow row = dataSetChattr.TableStatus.FindByid(id) as DataSetChattr.TableStatusRow;
                if (row != null)
                {
                    m_Post.SetText("@reblog " + row.text);
                    m_Post.Show();
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("PostDirectMessage() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            finally
            {
                m_MutexStatus.ReleaseMutex();
            }
        }

        private static Bitmap ByteArray2Bitmap(byte[] img, int width, int height)
        {
            Bitmap bmp = new Bitmap(width, height);
            BitmapData bmpData = bmp.LockBits(
                new Rectangle(0, 0, bmp.Width, bmp.Height),
                ImageLockMode.WriteOnly,
                PixelFormat.Format32bppArgb);
            Marshal.Copy(img, 0, bmpData.Scan0, img.Length);
            bmp.UnlockBits(bmpData);
            bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
            return bmp;
        }

        private static byte[] Bitmap2ByteArray(Bitmap bmp)
        {
            bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
            BitmapData bmpData = bmp.LockBits(
                new Rectangle(0, 0, bmp.Width, bmp.Height),
                ImageLockMode.ReadOnly,
                PixelFormat.Format32bppArgb);
            byte[] img = new byte[bmp.Width * bmp.Height * 4];
            Marshal.Copy(bmpData.Scan0, img, 0, img.Length);
            bmp.UnlockBits(bmpData);
            return img;
        }

        private bool ExistRequest(string arg)
        {
            int cnt = m_BgWork.Count;
            LinkedListNode<IBackGround> node = m_BgWork.First;
            for (int i = 0; i < cnt; i++)
            {
                if ((!m_fBgBusy) || (i > 0))
                {
                    IBackGround bg = node.Value;
                    IBackGroundString bgs = bg as IBackGroundString;
                    if ((bg.GetType() == typeof(IBackGroundString)) && (bgs.Arg == arg))
                    {
                        return true;
                    }
                }
                node = node.Next;
            }
            return false;
        }

        private void RequestDummy()
        {
            if (!ExistRequest(BG_DUMMY))
            {
                RequestBackGround(BG_DUMMY);
            }
        }

        private void RequestBackGround(string arg)
        {
            RunBackGround(delegate
            {
                if (arg != null)
                {
                    m_BgWork.AddLast(new IBackGroundString(arg));
                }
            });
        }

        private void RequestBackGround(agsXMPP.protocol.client.Message msg)
        {
            RunBackGround(delegate
            {
                if (msg != null)
                {
                    m_BgWork.AddLast(new IBackGroundXmppMessage(msg));
                }
            });
        }

        private void RunBackGround(MethodInvoker method)
        {
            method();
            if (m_BgWork.Count > 0)
            {
                if (!backgroundWorker.IsBusy && !m_fBgBusy)
                {
                    m_fBgBusy = true;
                    backgroundWorker.RunWorkerAsync(m_BgWork.First.Value);
                }
            }
        }

        private void RequestSetFlag(long id, int flags)
        {
            string req = BG_SET_FLAG + " " + id + " " + flags;
            if (!ExistRequest(req))
            {
                RequestBackGround(req);
                Debug.WriteLine(DateTime.Now + " RequestSetFlag: " + id + " / " + flags);
            }
        }

        private void RequestLoad()
        {
            if (!ExistRequest(BG_LOAD))
            {
                RequestBackGround(BG_LOAD);
            }
        }

        private void RequestLoading()
        {
            if ((!m_LoadDone) && (!ExistRequest(BG_LOADING)))
            {
                RequestBackGround(BG_LOADING);
            }
        }

        private void RequestDeleteAll()
        {
            if (!ExistRequest(BG_DELETE_ALL))
            {
                RequestBackGround(BG_DELETE_ALL);
            }
        }

        private void RequestFavorite(long id)
        {
            string req = BG_FAVORITE + " " + id;
            if (!ExistRequest(req))
            {
                RequestBackGround(req);
                Debug.WriteLine("RequestFavorite: " + id);
            }
        }

        private void RequestProfileImage(String profile_image)
        {
            if (dataSetChattr.TableProfileImage.Rows.Find(profile_image) == null)
            {
                string req = BG_PROFILE_IMAGE + " " + profile_image;
                if (!ExistRequest(req))
                {
                    RequestBackGround(req);
                    Debug.WriteLine("RequestProfileImage: " + profile_image);
                }
            }
        }

        private void RequestTinyUrl(String url)
        {
            Regex r = new Regex(REGEX_TINYURL);
            Match m = r.Match(url);
            if (m.Success && (dataSetChattr.TableTinyUrl.Rows.Find(m.Groups[1].Value) == null))
            {
                string req = BG_TINYURL + " " + m.Groups[1].Value;
                if (!ExistRequest(req))
                {
                    RequestBackGround(req);
                    Debug.WriteLine("RequestTinyUrl: " + m.Groups[1].Value);
                }
            }
        }

        public string MakeStatusText(string text)
        {
            if (Properties.Settings.Default.UseSignature && (Properties.Settings.Default.Signature != ""))
            {
                text += " " + Properties.Settings.Default.Signature;
            }
            if ((comboBoxLocation.ForeColor != Color.FromKnownColor(KnownColor.GrayText)) && (comboBoxLocation.Text != ""))
            {
                text += " L:" + comboBoxLocation.Text;
            }
            return text;
        }

        public void UpdateStatus(String status)
        {
            RequestBackGround(BG_UPDATE + " " + status);
        }

        private void GetFollowingTimeline()
        {
            String req = BG_FOLLOWING;
            if (!ExistRequest(req))
            {
                Debug.WriteLine("GetFollowingTimeline(" + DateTime.Now + ")");
                m_fEnableFollowing = false;
                RequestBackGround(req);
            }
        }

        public void GetFollowingTimelineViaPage(int page)
        {
            String req = BG_FOLLOWING + " ?page=" + page;
            if (!ExistRequest(req))
            {
                Debug.WriteLine("GetFollowingTimelineViaPage(" + DateTime.Now + ")");
                m_fEnableFollowing = false;
                RequestBackGround(req);
            }
        }

        private void GetUserTimeline()
        {
            String req = BG_USER;
            if (!ExistRequest(req))
            {
                Debug.WriteLine("GetUserTimeline(" + DateTime.Now + ")");
                RequestBackGround(req);
            }
        }

        private void GetReplies()
        {
            String req = BG_REPLIES;
            if (!ExistRequest(req))
            {
                Debug.WriteLine("GetReplies(" + DateTime.Now + ")");
                m_fEnableReplies = false;
                RequestBackGround(req);
            }
        }

        private void GetDirectMessage()
        {
            String req = BG_DIRECT_MESSAGE;
            if (!ExistRequest(req))
            {
                Debug.WriteLine("GetDirectMessage(" + DateTime.Now + ")");
                m_fEnableDM = false;
                RequestBackGround(req);
            }
        }

        private void StartTimer()
        {
            timer.Enabled = true;
        }

        private void StartTimelineTimer()
        {
            DateTime now = DateTime.Now;
            StartFollowingTimer(now);
            StartRepliesTimer(now);
            StartDirectMessageTimer(now);
            StartTimer();
        }

        private void StartFollowingTimer(DateTime now)
        {
            if (!toolStripButtonOffline.Checked && (Properties.Settings.Default.IntervalFriends != 0))
            {
                m_SpanFollowing = new TimeSpan(Properties.Settings.Default.IntervalFriends * 10000000 * 60);
                m_TimeFollowing = now;
                m_SpanOfflineFollowing = TimeSpan.Zero;
                m_fEnableFollowing = true;
                Debug.WriteLine("StartFollowingTimer(" + now + ")");
            }
            else
            {
                m_fEnableFollowing = false;
            }
        }

        private void StartRepliesTimer(DateTime now)
        {
            if (!toolStripButtonOffline.Checked && (Properties.Settings.Default.IntervalReplies != 0))
            {
                m_SpanReplies = new TimeSpan(Properties.Settings.Default.IntervalReplies * 10000000 * 60);
                m_TimeReplies = now;
                m_SpanOfflineReplies = TimeSpan.Zero;
                m_fEnableReplies = true;
                Debug.WriteLine("StartRepliesTimer(" + now + ")");
            }
            else
            {
                m_fEnableReplies = false;
            }
        }

        private void StartDirectMessageTimer(DateTime now)
        {
            if (!toolStripButtonOffline.Checked && (Properties.Settings.Default.IntervalDM != 0))
            {
                m_SpanDM = new TimeSpan(Properties.Settings.Default.IntervalDM * 10000000 * 60);
                m_TimeDM = now;
                m_SpanOfflineDM = TimeSpan.Zero;
                m_fEnableDM = true;
                Debug.WriteLine("StartDmTimer(" + now + ")");
            }
            else
            {
                m_fEnableDM = false;
            }
        }

        private object DoBackGround_String(IBackGroundString bg, BackgroundWorker worker)
        {
            object result = null;
            Regex r = new Regex(@"^(.*?) (.*)", RegexOptions.Singleline);
            Match m = r.Match(bg.Arg);
            String a = new String(bg.Arg.ToCharArray());
            String v = "";
            if (m.Success)
            {
                a = m.Groups[1].Value;
                v = m.Groups[2].Value;
            }
            switch (a)
            {
                case BG_FILL:
                    result = DoBackGround_Fill(v, worker);
                    break;
                case BG_LOAD:
                    result = DoBackGround_Load(v, worker);
                    break;
                case BG_LOADING:
                    result = DoBackGround_Loading(v, worker);
                    break;
                case BG_FOLLOWING:
                    result = DoBackGround_GetFollowingTimeline(v, worker);
                    break;
                case BG_USER:
                    result = DoBackGround_GetUserTimeline(v, worker);
                    break;
                case BG_REPLIES:
                    result = DoBackGround_GetReplies(v, worker);
                    break;
                case BG_DIRECT_MESSAGE:
                    result = DoBackGround_GetDirectMessage(v, worker);
                    break;
                case BG_PROFILE_IMAGE:
                    result = DoBackGround_GetProfileImage(v, worker);
                    break;
                case BG_UPDATE:
                    result = DoBackGround_Update(v, worker);
                    break;
                case BG_TINYURL:
                    result = DoBackGround_GetTinyUrl(v, worker);
                    break;
                case BG_DELETE_ALL:
                    result = DoBackGround_DeleteAll(v, worker);
                    break;
                case BG_FAVORITE:
                    result = DoBackGround_Favorite(v, worker);
                    break;
                case BG_SET_FLAG:
                    result = DoBackGround_SetFlag(v, worker);
                    break;
            }
            return result;
        }

        private static void ThreadFillProfileImage(object param)
        {
            if (param.GetType() == typeof(IFillTableProfileImage))
            {
                IFillTableProfileImage ift = param as IFillTableProfileImage;
                ift.Adapter.Fill(ift.Table);
            }
        }

        private static void ThreadFillTinyUrl(object param)
        {
            if (param.GetType() == typeof(IFillTableTinyUrl))
            {
                IFillTableTinyUrl ift = param as IFillTableTinyUrl;
                ift.Adapter.Fill(ift.Table);
            }
        }

        private static void ThreadFillId(object param)
        {
            if (param.GetType() == typeof(IFillTableId))
            {
                IFillTableId ift = param as IFillTableId;
                ift.Adapter.Fill(ift.Table);
            }
        }

        private static bool RunThread(Thread thread, BackgroundWorker worker, object param)
        {
            thread.Start(param);
            while (thread.IsAlive)
            {
                if (worker.CancellationPending)
                {
                    thread.Abort();
                    return false;
                }
                Thread.Sleep(100);
            }
            return true;
        }

        private static bool RunThreadQueue(Thread thread, Queue<bool> queue, object param)
        {
            thread.Start(param);
            while (thread.IsAlive)
            {
                if (queue.Count > 0)
                {
                    thread.Abort();
                    return false;
                }
                Thread.Sleep(100);
            }
            return true;
        }

        private long GetTableStatusCount()
        {
            long cnt = 0;
            string cmd = @"SELECT count(*) FROM TableStatus";
            object scalar = null;
            SQLiteConnection cnn = SQLite.ExecuteScalar(SQL_PATH, cmd, ref scalar);
            if (cnn != null)
            {
                using (cnn)
                {
                    cnt = long.Parse(scalar.ToString());
                    cnn.Close();
                }
            }
            return cnt;
        }

        private static SQLiteConnection ExecuteReader(ref SQLiteDataReader reader, long limit, long offset)
        {
            string cmd = @"SELECT * FROM TableStatus LIMIT " + limit + @" OFFSET " + offset;
            SQLiteConnection cnn = SQLite.ExecuteReader(SQL_PATH, cmd, ref reader);
            return cnn;
        }

        private static SQLiteConnection ExecuteReader(ref SQLiteDataReader reader, DateTime min, DateTime max, int limit, bool order)
        {
            string cmd = @"SELECT * FROM TableStatus WHERE " +
                @"created_at > '" + min.ToString("yyyy-MM-dd HH:mm:ss.ffffff") + @"' AND " +
                @"created_at <= '" + max.ToString("yyyy-MM-dd HH:mm:ss.ffffff") + @"'";
            if (order)
            {
                cmd += @" ORDER BY created_at DESC, id DESC";
            }
            if (limit > 0)
            {
                cmd += " LIMIT " + limit;
            }
            SQLiteConnection cnn = SQLite.ExecuteReader(SQL_PATH, cmd, ref reader);
            return cnn;
        }

        private DataSetChattr.TableStatusRow TableStatusReadRow(SQLiteDataReader reader)
        {
            DataSetChattr.TableStatusRow row = dataSetChattr.TableStatus.NewTableStatusRow();
            row.ItemArray = new Object[] {
                reader.GetInt64(dataSetChattr.TableStatus.idColumn.Ordinal),
                reader.GetDateTime(dataSetChattr.TableStatus.created_atColumn.Ordinal),
                reader.GetString(dataSetChattr.TableStatus.textColumn.Ordinal),
                reader.GetString(dataSetChattr.TableStatus.sourceColumn.Ordinal),
                reader.GetString(dataSetChattr.TableStatus.source_urlColumn.Ordinal),
                reader.GetInt64(dataSetChattr.TableStatus.user_idColumn.Ordinal),
                reader.GetString(dataSetChattr.TableStatus.user_nameColumn.Ordinal),
                reader.GetString(dataSetChattr.TableStatus.user_screen_nameColumn.Ordinal),
                reader.GetString(dataSetChattr.TableStatus.user_locationColumn.Ordinal),
                reader.GetString(dataSetChattr.TableStatus.user_profile_imageColumn.Ordinal),
                reader.GetInt32(dataSetChattr.TableStatus.flagsColumn.Ordinal)
            };
            return row;
        }

        private bool TableStatusAdd(DataSetChattr.TableStatusRow row)
        {
            if (dataSetChattr.TableStatus.Rows.Find(row.id) == null)
            {
                int i = dataSetChattr.TableStatus.Rows.Count - 1;
                while (i >= 0)
                {
                    DataSetChattr.TableStatusRow r = dataSetChattr.TableStatus.Rows[i] as DataSetChattr.TableStatusRow;
                    if (row.id == r.id)
                    {
                        break;
                    }
                    else if (r.created_at > row.created_at)
                    {
                        i = 0;
                    }
                    i--;
                }
                if (i >= 0)
                {
                    return false;
                }
                dataSetChattr.TableStatus.Rows.Add(row);
                return true;
            }
            return false;
        }

        private bool TableStatusInsert(DataSetChattr.TableStatusRow row)
        {
            if (dataSetChattr.TableStatus.Rows.Find(row.id) == null)
            {
                int i = 0;
                while (i < dataSetChattr.TableStatus.Rows.Count)
                {
                    DataSetChattr.TableStatusRow r = dataSetChattr.TableStatus.Rows[i] as DataSetChattr.TableStatusRow;
                    if (row.id == r.id)
                    {
                        return false;
                    }
                    else if (r.created_at < row.created_at)
                    {
                        break;
                    }
                    i++;
                }
                if (i < dataSetChattr.TableStatus.Rows.Count)
                {
                    dataSetChattr.TableStatus.Rows.InsertAt(row, i);
                }
                else
                {
                    dataSetChattr.TableStatus.Rows.Add(row);
                }
                return true;
            }
            return false;
        }

        delegate bool TableStatusAddDelegate(DataSetChattr.TableStatusRow row);

        private int TableStatusLoad(SQLiteConnection cnn, SQLiteDataReader reader, TableStatusAddDelegate addDelegate)
        {
            int rows = 0;
            if (cnn != null)
            {
                using (cnn)
                {
                    if (reader != null)
                    {
                        using (reader)
                        {
                            LinkedList<long> list = new LinkedList<long>();
                            try
                            {
                                while (reader.Read())
                                {
                                    DataSetChattr.TableStatusRow row = TableStatusReadRow(reader);
                                    if (addDelegate(row))
                                    {
                                        list.AddLast(row.id);
                                        rows++;
                                        m_Load++;
                                        if (m_LastDate > row.created_at)
                                        {
                                            m_LastDate = row.created_at;
                                        }
                                    }
                                }
                            }
                            catch (SystemException ex)
                            {
                                Debug.WriteLine("reader.Get() Error\n" +
                                    ex.Message + "\n" + "Source: " + ex.Source);
                            }
                            finally
                            {
                                reader.Close();
                            }
                            DataSetChattr.TableStatusDataTable changes = null;
                            m_MutexStatus.WaitOne();
                            try
                            {
                                changes = dataSetChattr.TableStatus.GetChanges() as DataSetChattr.TableStatusDataTable;
                                dataSetChattr.TableStatus.AcceptChanges();
                            }
                            finally
                            {
                                m_MutexStatus.ReleaseMutex();
                            }
                            if ((changes != null) && (changes.Rows.Count > 0))
                            {
                                using (changes)
                                {
                                    foreach (DataSetChattr.TableStatusRow row in changes.Rows)
                                    {
                                        LinkedListNode<long> node = list.First;
                                        while (node != null)
                                        {
                                            if (row.id == node.Value)
                                            {
                                                list.Remove(node);
                                                row.AcceptChanges();
                                                break;
                                            }
                                            node = node.Next;
                                        }
                                    }
                                    DataSetChattr.TableStatusDataTable update = changes.GetChanges() as DataSetChattr.TableStatusDataTable;
                                    if ((update != null) && (update.Rows.Count > 0))
                                    {
                                        using (update)
                                        {
                                            CommitTableStatus(update);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    cnn.Close();
                }
            }
            return rows;
        }

        private void TableStatusFill()
        {
            TableStatusAddDelegate addDelegate = delegate(DataSetChattr.TableStatusRow row)
            {
                return TableStatusInsert(row);
            };
            DateTime now = DateTime.UtcNow;
            m_LastDate = now.AddDays(-1);
            SQLiteDataReader reader = null;
            SQLiteConnection cnn = ExecuteReader(ref reader, m_LastDate, now.AddYears(1), -1, false);
            if (TableStatusLoad(cnn, reader, addDelegate) == 0)
            {
                m_LastDate = now.AddDays(0);
                TableStatusLoading();
            }
            Debug.WriteLine("TableStatusLoad(): " + m_LastDate);
        }

        private int TableStatusLoad(DateTime min, DateTime max, int limit)
        {
            TableStatusAddDelegate addDelegate = delegate(DataSetChattr.TableStatusRow row)
            {
                return TableStatusAdd(row);
            };
            SQLiteDataReader reader = null;
            SQLiteConnection cnn = ExecuteReader(ref reader, min, max, limit, true);
            return TableStatusLoad(cnn, reader, addDelegate);
        }

        private void TableStatusLoading()
        {
            if (!m_LoadDone)
            {
                if (TableStatusLoad(m_LastDate.AddDays(-1), m_LastDate, -1) > 0)
                {
                }
                else if (TableStatusLoad(m_LastDate.AddDays(-3), m_LastDate, -1) > 0)
                {
                }
                else if (TableStatusLoad(m_LastDate.AddDays(-7), m_LastDate, -1) > 0)
                {
                }
                else if (TableStatusLoad(m_LastDate.AddDays(-14), m_LastDate, -1) > 0)
                {
                }
                else if (TableStatusLoad(m_LastDate.AddMonths(-1), m_LastDate, -1) > 0)
                {
                }
                else if (TableStatusLoad(m_LastDate.AddMonths(-2), m_LastDate, -1) > 0)
                {
                }
                else if (TableStatusLoad(m_LastDate.AddMonths(-3), m_LastDate, -1) > 0)
                {
                }
                else if (TableStatusLoad(m_LastDate.AddMonths(-6), m_LastDate, -1) > 0)
                {
                }
                else if (TableStatusLoad(m_LastDate.AddYears(-1), m_LastDate, -1) > 0)
                {
                }
                else if (TableStatusLoad(DateTime.MinValue, m_LastDate, -1) > 0)
                {
                }
                else
                {
                    m_LoadDone = true;
                }
            }
        }

        private object DoBackGround_Fill(String arg, BackgroundWorker worker)
        {
            Debug.WriteLine("DoBackGround_Fill(" + arg + ")");
            if (worker.CancellationPending)
            {
                return null;
            }
            worker.ReportProgress((int)ProgressOp.STATUS_BAR, "ロード中...");

            SQLite.CreateDB(SQL_PATH);
            //DateTime today = DateTime.Today;
            //if ((today > Properties.Settings.Default.VacuumDay) || Properties.Settings.Default.VacuumReq)
            //{
            //    Properties.Settings.Default.VacuumDay = today;
            //    Properties.Settings.Default.VacuumReq = false;
            //    SQLite.Vacuum(SQL_PATH);
            //}
            DateTime now = DateTime.UtcNow;
            m_LoadDone = false;
            m_Load = 0;
            TableStatusFill();
            Directory.SetCurrentDirectory(EXEC_PATH + @"\..");
            Thread t = new Thread(ThreadFillProfileImage);
            if (!RunThread(t, worker, new IFillTableProfileImage(tableProfileImageTableAdapter, dataSetChattr.TableProfileImage)))
            {
                return null;
            }
            //m_Log.ProfileImage = dataSetChattr.TableProfileImage;
            t = new Thread(ThreadFillTinyUrl);
            if (!RunThread(t, worker, new IFillTableTinyUrl(tableTinyUrlTableAdapter, dataSetChattr.TableTinyUrl)))
            {
                return null;
            }
            t = new Thread(ThreadFillId);
            if (!RunThread(t, worker, new IFillTableId(tableIdTableAdapter, dataSetChattr.TableId)))
            {
                return null;
            }
            Debug.WriteLine("Load: " + (DateTime.UtcNow - now));
            Debug.WriteLine("DoBackGround_Fill: Loading...");
            m_Loading = 0;
            worker.ReportProgress((int)ProgressOp.LIST_BEGIN_UPDATE);
            foreach (DataSetChattr.TableStatusRow row in dataSetChattr.TableStatus.Rows)
            {
                if (worker.CancellationPending)
                {
                    return null;
                }
                else if (m_Loading < 600)
                {
                    m_Loading++;
                    worker.ReportProgress((int)ProgressOp.LIST_ADD, new IListItem(row.id, 0));
                    m_LastId = row.id;
                }
                else
                {
                    break;
                }
            }
            Debug.WriteLine("DoBackGround_Fill: Loading done.");
            worker.ReportProgress((int)ProgressOp.STATUS_BAR, "ロード終了");
            if (dataSetChattr.TableStatus.Rows.Count > 0)
            {
                SetSelectedID(Properties.Settings.Default.SelectedID, worker);
            }
            TopIndex(0, 0, worker);
            worker.ReportProgress((int)ProgressOp.LIST_END_UPDATE);
            worker.ReportProgress((int)ProgressOp.NUM_STATUS);
            worker.ReportProgress((int)ProgressOp.STATUS_BAR, "");
            return new IResultInit();
        }

        private object DoBackGround_Load(String arg, BackgroundWorker worker)
        {
            if (m_Loading < m_Load)
            {
                int cnt = dataSetChattr.TableStatus.Rows.Count;
                int idx = m_Loading - 200;
                if (idx < 0)
                {
                    idx = 0;
                }
                DataSetChattr.TableStatusRow row = dataSetChattr.TableStatus.Rows[idx] as DataSetChattr.TableStatusRow;
                while (row.id != m_LastId)
                {
                    idx++;
                    if (idx >= cnt)
                    {
                        if (worker.CancellationPending)
                        {
                            return null;
                        }
                        idx = 0;
                        Debug.Assert(false, "DoBackGround_Load() Error: overfllow");
                    }
                    row = dataSetChattr.TableStatus.Rows[idx] as DataSetChattr.TableStatusRow;
                }
                idx++;
                int i = 0;
                while (m_Loading < m_Load)
                {
                    m_Loading++;
                    row = dataSetChattr.TableStatus.Rows[idx] as DataSetChattr.TableStatusRow;
                    worker.ReportProgress((int)ProgressOp.LIST_ADD, new IListItem(row.id, idx));
                    m_LastId = row.id;
                    idx++;
                    i++;
                    if (m_BgWork.Count >= 2)
                    {
                        break;
                    }
                    else if (i >= 300)
                    {
                        i = 0;
                        if (!Loading(worker))
                        {
                            return null;
                        }
                    }
                }
                if (i > 0)
                {
                    if (!Loading(worker))
                    {
                        return null;
                    }
                }
                worker.ReportProgress((int)ProgressOp.NUM_STATUS);
            }
            if (m_BgWork.Count < 2)
            {
                worker.ReportProgress((int)ProgressOp.STATUS_BAR, "");
                Debug.WriteLine("DoBackGround_Load: done.");
            }
            return null;
        }

        private bool Loading(BackgroundWorker worker)
        {
            worker.ReportProgress((int)ProgressOp.NUM_STATUS);
            m_fBgFlag = true;
            worker.ReportProgress((int)ProgressOp.BG_FLAG, false);
            do
            {
                if (worker.CancellationPending)
                {
                    return false;
                }
                Thread.Sleep(100);
            }
            while (m_fBgFlag);
            if (m_LoadDone)
            {
                worker.ReportProgress((int)ProgressOp.STATUS_BAR, "");
                Debug.WriteLine("Loading: done.");
            }
            return true;
        }

        private object DoBackGround_Loading(String arg, BackgroundWorker worker)
        {
            if (!m_LoadDone)
            {
                TableStatusLoading();
            }
            return null;
        }

        private static string Option(string arg, DateTime since)
        {
            if (arg != "")
            {
                return arg;
            }
            else if (since == DateTime.MaxValue)
            {
                return "";
            }
            return "?since=" + since.ToString(@"ddd\%2C+dd+MMM+yyyy+HH\%3Amm\%3Ass", new CultureInfo("en-US")) + "+GMT";
        }

        private static void ThreadGetFollowingTimeline(object param)
        {
            if (param.GetType() == typeof(IGetTimeline))
            {
                IGetTimeline arg = param as IGetTimeline;
                HttpWebResponse res = TwitterAPI.GetFollowingTimeline(arg.User, arg.Pass, arg.Option);
                arg.Response = res;
            }
        }

        private object DoBackGround_GetFollowingTimeline(String arg, BackgroundWorker worker)
        {
            DateTime now = DateTime.Now;
            IResultGetFollowing result = new IResultGetFollowing();
            worker.ReportProgress((int)ProgressOp.STATUS_BAR, "Following タイムライン取得中...");
            IGetTimeline igt = new IGetTimeline(Properties.Settings.Default.UserName, m_Prefs.Password, Option(arg, m_SinceStatuses));
            HttpWebResponse res = null;
            Thread t = new Thread(ThreadGetFollowingTimeline);
            if (!RunThread(t, worker, igt))
            {
                return null;
            }
            res = igt.Response;
            if ((res != null) && (res.StatusCode == HttpStatusCode.OK))
            {
                XmlDocument doc = new XmlDocument();
                try
                {
                    doc.Load(res.GetResponseStream());
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("doc.Load(res.GetResponseStream) Error\n" +
                        "in DoBackGround_GetFollowingTimeline()" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                finally
                {
                    res.Close();
                }
                //m_Log.ClearTmpStatuses();
                IResultGetFollowing ret = RetrieveStatuses(doc.DocumentElement, worker, "ステータス", true);
                //m_Log.UpdateStatuses();
                if (ret != null)
                {
                    result.Flags = ret.Flags;
                    result.List = ret.List;
                    ret.Date.Sort();
                    if (ret.Date.Count > 0)
                    {
                        m_SinceStatuses = (DateTime)ret.Date[SINCE_POS];
                    }
                    //foreach (DateTime at_ret in ret.Date)
                    //{
                    //    Debug.WriteLine("DoBackGround_GetFollowingTimeline: " + at_ret);
                    //}
                }
                if (Properties.Settings.Default.NotCommitFromIM)
                {
                    m_MutexProfile.WaitOne();
                    try
                    {
                        DataSetChattr.TableProfileImageDataTable changes = dataSetChattr.TableProfileImage.GetChanges() as DataSetChattr.TableProfileImageDataTable;
                        if ((changes != null) && (changes.Rows.Count > 0))
                        {
                            tableProfileImageTableAdapter.Update(changes);
                            dataSetChattr.TableProfileImage.AcceptChanges();
                        }
                    }
                    catch (SystemException ex)
                    {
                        dataSetChattr.TableProfileImage.RejectChanges();
                        Debug.WriteLine("tableProfileImageTableAdapter.Update() Error\n" +
                            "in DoBackGround_GetFollowingTimeline()" +
                            ex.Message + "\n" + "Source: " + ex.Source);
                    }
                    finally
                    {
                        m_MutexProfile.ReleaseMutex();
                    }
                    m_MutexTinyUrl.WaitOne();
                    try
                    {
                        DataSetChattr.TableTinyUrlDataTable changes = dataSetChattr.TableTinyUrl.GetChanges() as DataSetChattr.TableTinyUrlDataTable;
                        if ((changes != null) && (changes.Rows.Count > 0))
                        {
                            tableTinyUrlTableAdapter.Update(changes);
                            dataSetChattr.TableTinyUrl.AcceptChanges();
                            Debug.WriteLine("DoBackGround_GetFollowingTimeline: tableTinyUrlTableAdapter.Update()");
                        }
                    }
                    catch (SystemException ex)
                    {
                        dataSetChattr.TableTinyUrl.RejectChanges();
                        Debug.WriteLine("tableTinyUrlTableAdapter.Update() Error\n" +
                            "in DoBackGround_GetFollowingTimeline()" +
                            ex.Message + "\n" + "Source: " + ex.Source);
                    }
                    finally
                    {
                        m_MutexTinyUrl.ReleaseMutex();
                    }
                }
            }
            else
            {
                string error = GetError(res);
                if (error != null)
                {
                    worker.ReportProgress((int)ProgressOp.STATUS_BAR, "Following タイムライン取得エラー" + error);
                }
                if (res != null)
                {
                    res.Close();
                    Debug.WriteLine("following timeline: " + res.StatusCode + " - " + res.StatusDescription);
                }
            }
            Debug.WriteLine("DoBackGround_GetFollowingTimeline: " + (DateTime.Now - now));
            return (object)result;
        }

        private static void ThreadGetUserTimeline(object param)
        {
            if (param.GetType() == typeof(IGetTimeline))
            {
                IGetTimeline arg = param as IGetTimeline;
                HttpWebResponse res = TwitterAPI.GetUserTimeline(arg.User, arg.Pass, arg.Option);
                arg.Response = res;
            }
        }

        private object DoBackGround_GetUserTimeline(String arg, BackgroundWorker worker)
        {
            DateTime now = DateTime.Now;
            IResultGetUser result = new IResultGetUser();
            worker.ReportProgress((int)ProgressOp.STATUS_BAR, "User タイムライン取得中...");
            IGetTimeline igt = new IGetTimeline(Properties.Settings.Default.UserName, m_Prefs.Password, Option(arg, DateTime.MaxValue));
            HttpWebResponse res = null;
            Thread t = new Thread(ThreadGetUserTimeline);
            if (!RunThread(t, worker, igt))
            {
                return null;
            }
            res = igt.Response;
            if ((res != null) && (res.StatusCode == HttpStatusCode.OK))
            {
                XmlDocument doc = new XmlDocument();
                try
                {
                    doc.Load(res.GetResponseStream());
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("doc.Load(res.GetResponseStream) Error\n" +
                        "in DoBackGround_GetUserTimeline()" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                finally
                {
                    res.Close();
                }
                IResultGetFollowing ret = RetrieveStatuses(doc.DocumentElement, worker, "ステータス", false);
                if (ret != null)
                {
                    result.Flags = ret.Flags;
                    result.List = ret.List;
                }
            }
            else
            {
                string error = GetError(res);
                if (error != null)
                {
                    worker.ReportProgress((int)ProgressOp.STATUS_BAR, "User タイムライン取得エラー" + error);
                }
                if (res != null)
                {
                    res.Close();
                    Debug.WriteLine("user timeline: " + res.StatusCode + " - " + res.StatusDescription);
                }
            }
            Debug.WriteLine("DoBackGround_GetUserTimeline: " + (DateTime.Now - now));
            return (object)result;
        }

        private static void ThreadGetReplies(object param)
        {
            if (param.GetType() == typeof(IGetTimeline))
            {
                IGetTimeline arg = param as IGetTimeline;
                HttpWebResponse res = TwitterAPI.GetReplies(arg.User, arg.Pass, arg.Option);
                arg.Response = res;
            }
        }

        private object DoBackGround_GetReplies(String arg, BackgroundWorker worker)
        {
            DateTime now = DateTime.Now;
            IResultGetReplies result = new IResultGetReplies();
            worker.ReportProgress((int)ProgressOp.STATUS_BAR, "Replies 取得中...");
            string option = arg;
            IGetTimeline igt = new IGetTimeline(Properties.Settings.Default.UserName, m_Prefs.Password, Option(arg, m_SinceReplies));
            HttpWebResponse res = null;
            Thread t = new Thread(ThreadGetReplies);
            if (!RunThread(t, worker, igt))
            {
                return null;
            }
            res = igt.Response;
            if ((res != null) && (res.StatusCode == HttpStatusCode.OK))
            {
                XmlDocument doc = new XmlDocument();
                try
                {
                    doc.Load(res.GetResponseStream());
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("doc.Load(res.GetResponseStream) Error\n" +
                        "in DoBackGround_GetRepliessTimeline()" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                finally
                {
                    res.Close();
                }
                IResultGetFollowing ret = RetrieveStatuses(doc.DocumentElement, worker, "リプライ", false);
                if (ret != null)
                {
                    result.Flags = ret.Flags;
                    result.List = ret.List;
                }
            }
            else
            {
                string error = GetError(res);
                if (error != null)
                {
                    worker.ReportProgress((int)ProgressOp.STATUS_BAR, "Reples 取得エラー" + error);
                }
                if (res != null)
                {
                    res.Close();
                    Debug.WriteLine("replies: " + res.StatusCode + " - " + res.StatusDescription);
                }
            }
            Debug.WriteLine("DoBackGround_GetReplies: " + (DateTime.Now - now));
            return (object)result;
        }

        private static void ThreadGetDirectMessage(object param)
        {
            if (param.GetType() == typeof(IGetTimeline))
            {
                IGetTimeline arg = param as IGetTimeline;
                HttpWebResponse res = TwitterAPI.GetDirectMessage(arg.User, arg.Pass, arg.Option);
                arg.Response = res;
            }
        }

        private object DoBackGround_GetDirectMessage(String arg, BackgroundWorker worker)
        {
            DateTime now = DateTime.Now;
            IResuleGetDirectMessage result = new IResuleGetDirectMessage();
            worker.ReportProgress((int)ProgressOp.STATUS_BAR, "ダイレクトメッセージ取得中...");
            string option = arg;
            IGetTimeline igt = new IGetTimeline(Properties.Settings.Default.UserName, m_Prefs.Password, Option(arg, m_SinceReplies));
            HttpWebResponse res = null;
            Thread t = new Thread(ThreadGetDirectMessage);
            if (!RunThread(t, worker, igt))
            {
                return null;
            }
            res = igt.Response;
            if ((res != null) && (res.StatusCode == HttpStatusCode.OK))
            {
                XmlDocument doc = new XmlDocument();
                try
                {
                    doc.Load(res.GetResponseStream());
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("doc.Load(res.GetResponseStream) Error\n" +
                        "in DoBackGround_GetDirectMessage()" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                finally
                {
                    res.Close();
                }
                IResuleGetDirectMessage ret = RetrieveDirectMessage(doc.DocumentElement, worker, "メッセージ", false);
                if (ret != null)
                {
                    result.Flags = ret.Flags;
                    result.List = ret.List;
                }
            }
            else
            {
                string error = GetError(res);
                if (error != null)
                {
                    worker.ReportProgress((int)ProgressOp.STATUS_BAR, "ダイレクトメッセージ取得エラー" + error);
                }
                if (res != null)
                {
                    res.Close();
                    Debug.WriteLine("replies: " + res.StatusCode + " - " + res.StatusDescription);
                }
            }
            Debug.WriteLine("DoBackGround_GetDirectMessage: " + (DateTime.Now - now));
            return (object)result;
        }

        private object DoBackGround_XmppMessage(IBackGroundXmppMessage bg, BackgroundWorker worker)
        {
            DateTime now = DateTime.Now;
            IResultXmppMessage result = new IResultXmppMessage();
            DataSetChattr.TableStatusRow row_new = ParseXmpp(bg.Msg);
            if (row_new != null)
            {
                bool valid = false;
                try
                {
                    int topIdx = 0;
                    int topIdxSearch = 0;
                    long topId = 0;
                    long topIdSearch = 0;
                    long selected = 0;
                    long selectedSearch = 0;
                    StatusParser parser = new StatusParser(row_new.text);
                    ParseUserName(parser, row_new);
                    ParseTinyUrl(parser);
                    ParseKeyword(parser, row_new);
                    if (row_new.id >= 0)
                    {
                        if (dataSetChattr.TableStatus.FindByid(row_new.id) == null)
                        {
                            valid = true;
                        }
                        if (valid && !m_LoadDone)
                        {
                            DataSetChattr.TableStatusDataTable table = tableStatusTableAdapter.GetDataByID(row_new.id);
                            if ((table != null) && (table.Rows.Count > 0))
                            {
                                valid = false;
                            }
                        }
                    }
                    else
                    {
                        int cnt = dataSetChattr.TableStatus.Rows.Count;
                        for (int i = 0; i < cnt; i++)
                        {
                            DataSetChattr.TableStatusRow row = dataSetChattr.TableStatus.Rows[i] as DataSetChattr.TableStatusRow;
                            if (row.RowState != DataRowState.Deleted)
                            {
                                TimeSpan span = row_new.created_at - row.created_at;
                                if ((((row_new.flags & FLAG_DM) == 0) && ((row.id >= 0) &&
                                    (row.user_screen_name == row_new.user_screen_name) && (row.text == row_new.text))) ||
                                    (((row_new.flags & FLAG_DM) != 0) && (((row.flags & FLAG_DM) != 0) && (row.user_id != -1) &&
                                    (row.user_screen_name == row_new.user_screen_name) && (row.text == row_new.text))))
                                {
                                    if (Math.Abs(span.TotalHours) > VALID_SPAN)
                                    {
                                        valid = true;
                                    }
                                    break;
                                }
                                else if (span.TotalHours > VALID_SPAN)
                                {
                                    valid = true;
                                    break;
                                }
                            }
                        }
                    }
                    if (worker.CancellationPending)
                    {
                        return null;
                    }
                    else if (valid)
                    {
                        LinkedList<IListItem> list = new LinkedList<IListItem>();
                        topIdx = GetTopIndex();
                        topIdxSearch = GetTopIndexSearch();
                        selected = GetSelectedID();
                        selectedSearch = GetSelectedSearchID();
                        DataSetChattr.TableStatusDataTable changes = null;
                        m_MutexStatus.WaitOne();
                        try
                        {
                            if (dataSetChattr.TableStatus.Rows.Count > 0)
                            {
                                if (topIdx >= 0)
                                {
                                    topId = ((DataSetChattr.TableStatusRow)(dataSetChattr.TableStatus.Rows[topIdx])).id;
                                }
                                if ((m_TblSearch != null) && (topIdxSearch >= 0))
                                {
                                    topIdSearch = ((DataSetChattr.TableStatusRow)(m_TblSearch.Rows[topIdxSearch])).id;
                                }
                            }
                            InsertStatus(row_new, list);
                            RequestProfileImage(row_new.user_profile_image);
                            if (worker.CancellationPending)
                            {
                                return null;
                            }
                            if (!Properties.Settings.Default.NotCommitFromIM)
                            {
                                DateTime now_ = DateTime.Now;
                                changes = dataSetChattr.TableStatus.GetChanges() as DataSetChattr.TableStatusDataTable;
                                dataSetChattr.TableStatus.AcceptChanges();
                                DateTime end_ = DateTime.Now;
                                TimeSpan span_ = end_ - now_;
                                Debug.WriteLine(end_ + " GetChanges: " + span_);
                            }
                        }
                        catch (SystemException ex)
                        {
                            Debug.WriteLine("m_MutexStatus.WaitOne() Error\n" +
                                "in DoBackGround_XmppMessage()" +
                                ex.Message + "\n" + "Source: " + ex.Source);
                        }
                        finally
                        {
                            m_MutexStatus.ReleaseMutex();
                            if (valid)
                            {
                                worker.ReportProgress((int)ProgressOp.LIST_BEGIN_UPDATE);
                                worker.ReportProgress((int)ProgressOp.LIST_INSERT, new IListItem(list.First.Value as IListItem));
                                SetSelectedID(selected, worker);
                                TopIndex(topIdx, topId, worker);
                                worker.ReportProgress((int)ProgressOp.LIST_END_UPDATE);
                                worker.ReportProgress((int)ProgressOp.NUM_STATUS);
                                result.Flags = row_new.flags;
                                result.List.Add(MakePopup(row_new));
                            }
                            if (!Properties.Settings.Default.NotCommitFromIM && (changes != null))
                            {
                                DateTime now_ = DateTime.Now;
                                CommitTableStatus(changes);
                                DateTime end_ = DateTime.Now;
                                TimeSpan span_ = end_ - now_;
                                Thread.Sleep(0);
                                Debug.WriteLine(end_ + " Update: " + changes.Rows.Count + " / " + span_);
                            }
                            if (valid)
                            {
                                UpdateSearchTable(worker, 0, selectedSearch, topIdxSearch, topIdSearch);
                            }
                        }
                    }
                    else
                    {
                        Debug.WriteLine("Cancel");
                    }
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("DoBackGround_XmppMessage() Error\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
            }
            Debug.WriteLine("DoBackGround_XmppMessage: " + (DateTime.Now - now));
            return result;
        }

        private string GetError(HttpWebResponse res)
        {
            if (res != null)
            {
                return " ［" + res.StatusDescription + "］";
            }
            SystemException ex = TwitterAPI.GetLastError();
            if (ex != null)
            {
                string error = ex.Message;
                Match m;
                if ((m = new Regex(@"^.*?\: (.*)$").Match(error)).Success)
                {
                    error = m.Groups[1].Value;
                    if ((m = new Regex(@"^\(304\)").Match(error)).Success)
                    {
                        Debug.WriteLine("GetError: " + error);
                        return null;
                    }
                }
                return " ［" + error + "］";
            }
            return "";
        }

        private bool IsBadGateway(HttpWebResponse res)
        {
            if (res != null)
            {
                return (res.StatusCode == HttpStatusCode.BadGateway);
            }
            string error = GetError(res);
            Match m;
            if ((error != null) && (m = new Regex(@"^ ［\(502\)").Match(error)).Success)
            {
                return true;
            }
            return false;
        }

        private IResultGetFollowing RetrieveStatuses(XmlElement root, BackgroundWorker worker, string unit, bool add)
        {
            IResultGetFollowing result = new IResultGetFollowing();
            try
            {
                if ((root.Name == "statuses") && (root.Attributes["type"].Value == "array"))
                {
                    DataSetChattr.TableStatusDataTable changes = null;
                    int retrieve = 0;
                    int replace = 0;
                    string timeline = "following timeline";
                    if (unit != "ステータス")
                    {
                        timeline = "replies";
                    }
                    Debug.WriteLine(timeline + ": " + root.ChildNodes.Count + " retrieve");
                    int topIdx = GetTopIndex();
                    int topIdxSearch = GetTopIndexSearch();
                    long topId = 0;
                    long topIdSearch = 0;
                    long selected = GetSelectedID();
                    long selectedSearch = GetSelectedSearchID();
                    LinkedList<IListItem> list = new LinkedList<IListItem>();
                    m_MutexStatus.WaitOne();
                    try
                    {
                        if (dataSetChattr.TableStatus.Rows.Count > 0)
                        {
                            if (topIdx >= 0)
                            {
                                topId = ((DataSetChattr.TableStatusRow)(dataSetChattr.TableStatus.Rows[topIdx])).id;
                            }
                            if ((m_TblSearch != null) && (topIdxSearch >= 0))
                            {
                                topIdSearch = ((DataSetChattr.TableStatusRow)(m_TblSearch.Rows[topIdxSearch])).id;
                            }
                        }
                        for (int i = root.ChildNodes.Count - 1; i >= 0; i--)
                        {
                            XmlNode node = root.ChildNodes[i];
                            if (worker.CancellationPending)
                            {
                                return null;
                            }
                            DateTime at = DateTime.MaxValue;
                            DataSetChattr.TableStatusRow row_new = dataSetChattr.TableStatus.NewTableStatusRow();
                            int? exist = ParseStatus(node, ref at, ref row_new);
                            result.Date.Add(at);
                            if (exist != null)
                            {
                                StatusParser parser = new StatusParser(row_new.text);
                                ParseUserName(parser, row_new);
                                ParseTinyUrl(parser);
                                ParseKeyword(parser, row_new);
                                if (exist > 0)
                                {
                                    int x = (int)exist - 1;
                                    DataSetChattr.TableStatusRow row = (DataSetChattr.TableStatusRow)dataSetChattr.TableStatus.Rows[x];
                                    if (topId == row.id)
                                    {
                                        topId = row_new.id;
                                    }
                                    if (topIdSearch == row.id)
                                    {
                                        topIdSearch = row_new.id;
                                    }
                                    if (selectedSearch == row.id)
                                    {
                                        selectedSearch = row_new.id;
                                    }
                                    selected = ReplaceStatus(row_new, x, selected, list);
                                    replace++;
                                    retrieve++;
                                }
                                else if (exist < 0)
                                {
                                    int cnt = dataSetChattr.TableStatus.Rows.Count;
                                    if (cnt == 0)
                                    {
                                        AddStatus(row_new, list);
                                    }
                                    else
                                    {
                                        int x = cnt;
                                        if (row_new.id >= 0)
                                        {
                                            for (x = 0; x < cnt; x++)
                                            {
                                                DataSetChattr.TableStatusRow row = (DataSetChattr.TableStatusRow)dataSetChattr.TableStatus.Rows[x];
                                                if ((row.RowState != DataRowState.Deleted) && ((row.flags & FLAG_DM) == 0))
                                                {
                                                    if ((row.id < 0) &&
                                                        (row.user_screen_name == row_new.user_screen_name) &&
                                                        (row.text == row_new.text))
                                                    {
                                                        if (worker.CancellationPending)
                                                        {
                                                            return null;
                                                        }
                                                        if ((row.flags & FLAG_FAVORITE) != 0)
                                                        {
                                                            RequestFavorite(row_new.id);
                                                        }
                                                        try
                                                        {
                                                            if (dataSetChattr.TableId.FindByid(row.id) == null)
                                                            {
                                                                dataSetChattr.TableId.Rows.Add(row.id, row_new.id);
                                                            }
                                                        }
                                                        catch (SystemException ex)
                                                        {
                                                            Debug.WriteLine("tableIdTableAdapter.Update() Error\n" +
                                                                "in RetrieveStatuses()" +
                                                                ex.Message + "\n" + "Source: " + ex.Source);
                                                        }
                                                        if (topId == row.id)
                                                        {
                                                            topId = row_new.id;
                                                        }
                                                        if (topIdSearch == row.id)
                                                        {
                                                            topIdSearch = row_new.id;
                                                        }
                                                        if (selectedSearch == row.id)
                                                        {
                                                            selectedSearch = row_new.id;
                                                        }
                                                        selected = ReplaceStatus(row_new, x, selected, list);
                                                        replace++;
                                                        break;
                                                    }
                                                    else if ((row_new.created_at - row.created_at).TotalHours >= VALID_SPAN)
                                                    {
                                                        x = cnt;
                                                    }
                                                }
                                            }
                                        }
                                        if (worker.CancellationPending)
                                        {
                                            return null;
                                        }
                                        else if (x >= cnt)
                                        {
                                            result.List.Add(MakePopup(row_new));
                                            result.Flags |= row_new.flags;
                                            InsertStatus(row_new, list);
                                            RequestProfileImage(row_new.user_profile_image);
                                        }
                                    }
                                    retrieve++;
                                }
                                //if (add)
                                //{
                                //    m_Log.AddRow(row_new);
                                //}
                            }
                        }
                        Debug.WriteLine(timeline + ": " + retrieve + " / " + replace);
                        if (retrieve > 0)
                        {
                            if (worker.CancellationPending)
                            {
                                return null;
                            }
                            DateTime now = DateTime.Now;
                            try
                            {
                                changes = dataSetChattr.TableStatus.GetChanges() as DataSetChattr.TableStatusDataTable;
                                dataSetChattr.TableStatus.AcceptChanges();
                            }
                            catch (SystemException ex)
                            {
                                Debug.WriteLine("dataSetChattr.TableStatus.GetChanges() Error\n" +
                                    "in RetrieveStatuses()" +
                                    ex.Message + "\n" + "Source: " + ex.Source);
                            }
                            DateTime end = DateTime.Now;
                            TimeSpan span = end - now;
                            Debug.WriteLine(end + " GetChanges: " + span);
                        }
                    }
                    catch (SystemException ex)
                    {
                        Debug.WriteLine("m_MutexStatus.WaitOne() Error\n" +
                            "in RetrieveStatuses()" +
                            ex.Message + "\n" + "Source: " + ex.Source);
                    }
                    finally
                    {
                        m_MutexStatus.ReleaseMutex();
                    }
                    try
                    {
                        string statusBar = "";
                        if ((retrieve - replace) > 0)
                        {
                            statusBar = (retrieve - replace) + " " + unit + "取得しました";
                        }
                        worker.ReportProgress((int)ProgressOp.STATUS_BAR, statusBar);
                        //if (add)
                        //{
                        //    m_Log.SetStatusBar(statusBar);
                        //}
                        if (list.Count > 0)
                        {
                            worker.ReportProgress((int)ProgressOp.LIST_BEGIN_UPDATE);
                            int delete = 0;
                            LinkedListNode<IListItem> node = list.First;
                            while (node != null)
                            {
                                if (node.Value.GetType() == typeof(IListItemAdd))
                                {
                                    worker.ReportProgress((int)ProgressOp.LIST_ADD, new IListItem(node.Value as IListItem));
                                }
                                else if (node.Value.GetType() == typeof(IListItemInsert))
                                {
                                    worker.ReportProgress((int)ProgressOp.LIST_INSERT, new IListItem(node.Value as IListItem));
                                }
                                else if (node.Value.GetType() == typeof(IListItemDelete))
                                {
                                    worker.ReportProgress((int)ProgressOp.LIST_DELETE, node.Value.Index);
                                    delete++;
                                }
                                else if (node.Value.GetType() == typeof(IListItemRemove))
                                {
                                    worker.ReportProgress((int)ProgressOp.LIST_REMOVE, node.Value.Index);
                                }
                                node = node.Next;
                            }
                            if (delete > 0)
                            {
                                worker.ReportProgress((int)ProgressOp.LIST_REMOVES, delete);
                            }
                            SetSelectedID(selected, worker);
                            TopIndex(topIdx, topId, worker);
                            worker.ReportProgress((int)ProgressOp.LIST_END_UPDATE);
                        }
                        worker.ReportProgress((int)ProgressOp.NUM_STATUS);
                        if (worker.CancellationPending)
                        {
                            return null;
                        }
                        if ((changes != null) && (changes.Rows.Count > 0))
                        {
                            DateTime now = DateTime.Now;
                            CommitTableStatus(changes);
                            DateTime end = DateTime.Now;
                            TimeSpan span = end - now;
                            Debug.WriteLine(end + " Update: " + changes.Rows.Count + " / " + span);
                        }
                        DataTable chg = dataSetChattr.TableId.GetChanges();
                        if ((chg != null) && (chg.Rows.Count > 0))
                        {
                            tableIdTableAdapter.Update(dataSetChattr.TableId);
                            dataSetChattr.TableId.AcceptChanges();
                        }
                        if (worker.CancellationPending)
                        {
                            return null;
                        }
                        if (retrieve > 0)
                        {
                            if (!UpdateSearchTable(worker, replace, selectedSearch, topIdxSearch, topIdSearch))
                            {
                                return null;
                            }
                        }
                    }
                    catch (SystemException ex)
                    {
                        Debug.WriteLine("RetrieveStatuses() Error\n" +
                            ex.Message + "\n" + "Source: " + ex.Source);
                    }
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("RetrieveStatuses() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            return result;
        }

        private IResuleGetDirectMessage RetrieveDirectMessage(XmlElement root, BackgroundWorker worker, string unit, bool add)
        {
            IResuleGetDirectMessage result = new IResuleGetDirectMessage();
            try
            {
                if ((root.Name == "direct-messages") && (root.Attributes["type"].Value == "array"))
                {
                    DataSetChattr.TableStatusDataTable changes = null;
                    int retrieve = 0;
                    int replace = 0;
                    string timeline = "direct message";
                    Debug.WriteLine(timeline + ": " + root.ChildNodes.Count + " retrieve");
                    int topIdx = GetTopIndex();
                    int topIdxSearch = GetTopIndexSearch();
                    long topId = 0;
                    long topIdSearch = 0;
                    long selected = GetSelectedID();
                    long selectedSearch = GetSelectedSearchID();
                    LinkedList<IListItem> list = new LinkedList<IListItem>();
                    m_MutexStatus.WaitOne();
                    try
                    {
                        if (dataSetChattr.TableStatus.Rows.Count > 0)
                        {
                            if (topIdx >= 0)
                            {
                                topId = ((DataSetChattr.TableStatusRow)(dataSetChattr.TableStatus.Rows[topIdx])).id;
                            }
                            if ((m_TblSearch != null) && (topIdxSearch >= 0))
                            {
                                topIdSearch = ((DataSetChattr.TableStatusRow)(m_TblSearch.Rows[topIdxSearch])).id;
                            }
                        }
                        for (int i = root.ChildNodes.Count - 1; i >= 0; i--)
                        {
                            XmlNode node = root.ChildNodes[i];
                            if (worker.CancellationPending)
                            {
                                return null;
                            }
                            DateTime at = DateTime.MaxValue;
                            DataSetChattr.TableStatusRow row_new = dataSetChattr.TableStatus.NewTableStatusRow();
                            int? exist = ParseDirectMessage(node, ref at, ref row_new);
                            result.Date.Add(at);
                            if (exist != null)
                            {
                                StatusParser parser = new StatusParser(row_new.text);
                                ParseUserName(parser, row_new);
                                ParseTinyUrl(parser);
                                ParseKeyword(parser, row_new);
                                if (exist > 0)
                                {
                                    int x = (int)exist - 1;
                                    DataSetChattr.TableStatusRow row = (DataSetChattr.TableStatusRow)dataSetChattr.TableStatus.Rows[x];
                                    if (topId == row.id)
                                    {
                                        topId = row_new.id;
                                    }
                                    if (topIdSearch == row.id)
                                    {
                                        topIdSearch = row_new.id;
                                    }
                                    if (selectedSearch == row.id)
                                    {
                                        selectedSearch = row_new.id;
                                    }
                                    selected = ReplaceStatus(row_new, x, selected, list);
                                    replace++;
                                    retrieve++;
                                }
                                else if (exist < 0)
                                {
                                    int cnt = dataSetChattr.TableStatus.Rows.Count;
                                    if (cnt == 0)
                                    {
                                        AddStatus(row_new, list);
                                    }
                                    else
                                    {
                                        int x = cnt;
                                        if (row_new.id < 0)
                                        {
                                            for (x = 0; x < cnt; x++)
                                            {
                                                DataSetChattr.TableStatusRow row = (DataSetChattr.TableStatusRow)dataSetChattr.TableStatus.Rows[x];
                                                if ((row.RowState != DataRowState.Deleted) && ((row.flags & FLAG_DM) != 0))
                                                {
                                                    if ((row.id < 0) && (row.id != row_new.id) &&
                                                        (row.user_screen_name == row_new.user_screen_name) &&
                                                        (row.text == row_new.text))
                                                    {
                                                        if (worker.CancellationPending)
                                                        {
                                                            return null;
                                                        }
                                                        try
                                                        {
                                                            if (dataSetChattr.TableId.FindByid(row.id) == null)
                                                            {
                                                                dataSetChattr.TableId.Rows.Add(row.id, row_new.id);
                                                            }
                                                        }
                                                        catch (SystemException ex)
                                                        {
                                                            Debug.WriteLine("tableIdTableAdapter.Update() Error\n" +
                                                                "in RetrieveDirectMessage()" +
                                                                ex.Message + "\n" + "Source: " + ex.Source);
                                                        }
                                                        if (topId == row.id)
                                                        {
                                                            topId = row_new.id;
                                                        }
                                                        if (topIdSearch == row.id)
                                                        {
                                                            topIdSearch = row_new.id;
                                                        }
                                                        if (selectedSearch == row.id)
                                                        {
                                                            selectedSearch = row_new.id;
                                                        }
                                                        selected = ReplaceStatus(row_new, x, selected, list);
                                                        replace++;
                                                        break;
                                                    }
                                                    else if ((row_new.created_at - row.created_at).TotalHours >= VALID_SPAN)
                                                    {
                                                        x = cnt;
                                                    }
                                                }
                                            }
                                        }
                                        if (worker.CancellationPending)
                                        {
                                            return null;
                                        }
                                        else if (x >= cnt)
                                        {
                                            result.List.Add(MakePopup(row_new));
                                            result.Flags |= row_new.flags;
                                            InsertStatus(row_new, list);
                                            RequestProfileImage(row_new.user_profile_image);
                                        }
                                    }
                                    retrieve++;
                                }
                                //if (add)
                                //{
                                //    m_Log.AddRow(row_new);
                                //}
                            }
                        }
                        Debug.WriteLine(timeline + ": " + retrieve + " / " + replace);
                        if (retrieve > 0)
                        {
                            if (worker.CancellationPending)
                            {
                                return null;
                            }
                            DateTime now = DateTime.Now;
                            try
                            {
                                changes = dataSetChattr.TableStatus.GetChanges() as DataSetChattr.TableStatusDataTable;
                                dataSetChattr.TableStatus.AcceptChanges();
                            }
                            catch (SystemException ex)
                            {
                                Debug.WriteLine("dataSetChattr.TableStatus.GetChanges() Error\n" +
                                    "in RetrieveDirectMessage()" +
                                    ex.Message + "\n" + "Source: " + ex.Source);
                            }
                            DateTime end = DateTime.Now;
                            TimeSpan span = end - now;
                            Debug.WriteLine(end + " GetChanges: " + span);
                        }
                    }
                    catch (SystemException ex)
                    {
                        Debug.WriteLine("m_MutexStatus.WaitOne() Error\n" +
                            "in RetrieveDirectMessage()" +
                            ex.Message + "\n" + "Source: " + ex.Source);
                    }
                    finally
                    {
                        m_MutexStatus.ReleaseMutex();
                    }
                    try
                    {
                        string statusBar = "";
                        if ((retrieve - replace) > 0)
                        {
                            statusBar = (retrieve - replace) + " " + unit + "取得しました";
                        }
                        worker.ReportProgress((int)ProgressOp.STATUS_BAR, statusBar);
                        //if (add)
                        //{
                        //    m_Log.SetStatusBar(statusBar);
                        //}
                        if (list.Count > 0)
                        {
                            worker.ReportProgress((int)ProgressOp.LIST_BEGIN_UPDATE);
                            int delete = 0;
                            LinkedListNode<IListItem> node = list.First;
                            while (node != null)
                            {
                                if (node.Value.GetType() == typeof(IListItemAdd))
                                {
                                    worker.ReportProgress((int)ProgressOp.LIST_ADD, new IListItem(node.Value as IListItem));
                                }
                                else if (node.Value.GetType() == typeof(IListItemInsert))
                                {
                                    worker.ReportProgress((int)ProgressOp.LIST_INSERT, new IListItem(node.Value as IListItem));
                                }
                                else if (node.Value.GetType() == typeof(IListItemDelete))
                                {
                                    worker.ReportProgress((int)ProgressOp.LIST_DELETE, node.Value.Index);
                                    delete++;
                                }
                                else if (node.Value.GetType() == typeof(IListItemRemove))
                                {
                                    worker.ReportProgress((int)ProgressOp.LIST_REMOVE, node.Value.Index);
                                }
                                node = node.Next;
                            }
                            if (delete > 0)
                            {
                                worker.ReportProgress((int)ProgressOp.LIST_REMOVES, delete);
                            }
                            SetSelectedID(selected, worker);
                            TopIndex(topIdx, topId, worker);
                            worker.ReportProgress((int)ProgressOp.LIST_END_UPDATE);
                        }
                        worker.ReportProgress((int)ProgressOp.NUM_STATUS);
                        if (worker.CancellationPending)
                        {
                            return null;
                        }
                        if ((changes != null) && (changes.Rows.Count > 0))
                        {
                            DateTime now = DateTime.Now;
                            CommitTableStatus(changes);
                            DateTime end = DateTime.Now;
                            TimeSpan span = end - now;
                            Debug.WriteLine(end + " Update: " + changes.Rows.Count + " / " + span);
                        }
                        DataTable chg = dataSetChattr.TableId.GetChanges();
                        if ((chg != null) && (chg.Rows.Count > 0))
                        {
                            tableIdTableAdapter.Update(dataSetChattr.TableId);
                            dataSetChattr.TableId.AcceptChanges();
                        }
                        if (worker.CancellationPending)
                        {
                            return null;
                        }
                        if (retrieve > 0)
                        {
                            if (!UpdateSearchTable(worker, replace, selectedSearch, topIdxSearch, topIdSearch))
                            {
                                return null;
                            }
                        }
                    }
                    catch (SystemException ex)
                    {
                        Debug.WriteLine("RetrieveDirectMessage() Error\n" +
                            ex.Message + "\n" + "Source: " + ex.Source);
                    }
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("RetrieveDirectMessage() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            return result;
        }

        private IPopup MakePopup(DataSetChattr.TableStatusRow row)
        {
            return new IPopup(row.id, row.flags, row.user_screen_name, row.text);
        }

        private bool UpdateSearchTable(BackgroundWorker worker, int replace, long selected, int top, long id)
        {
            if (m_TblSearch != null)
            {
                m_TblSearch = SearchStatus(m_Search);
                if (m_TblSearch == null)
                {
                    listBoxSearch.Items.Clear();
                }
                else
                {
                    if (listBoxSearch.Items.Count != m_TblSearch.Rows.Count)
                    {
                        worker.ReportProgress((int)ProgressOp.LIST_SEARCH_BEGIN_UPDATE);
                        int i = listBoxSearch.Items.Count - m_TblSearch.Rows.Count;
                        while (i > 0)
                        {
                            if (worker.CancellationPending)
                            {
                                return false;
                            }
                            worker.ReportProgress((int)ProgressOp.LIST_SEARCH_REMOVE, 0);
                            i--;
                        }
                        i = replace;
                        while (i > 0)
                        {
                            if (worker.CancellationPending)
                            {
                                return false;
                            }
                            worker.ReportProgress((int)ProgressOp.LIST_SEARCH_REMOVE, 0);
                            i--;
                        }
                        i = m_TblSearch.Rows.Count - listBoxSearch.Items.Count - 1;
                        while (i >= 0)
                        {
                            if (worker.CancellationPending)
                            {
                                return false;
                            }
                            DataSetChattr.TableStatusRow row = m_TblSearch.Rows[i] as DataSetChattr.TableStatusRow;
                            worker.ReportProgress((int)ProgressOp.LIST_SEARCH_INSERT, new IListItem(row.id, 0));
                            i--;
                        }
                        if (worker.CancellationPending)
                        {
                            return false;
                        }
                        SetSelectedSearchID(selected, worker);
                        TopIndexSearch(top, id, worker);
                        worker.ReportProgress((int)ProgressOp.LIST_SEARCH_END_UPDATE, 0);
                    }
                    if (m_TblSearch.Rows.Count == 0)
                    {
                        m_TblSearch = null;
                    }
                }
            }
            return true;
        }

        private DataSetChattr.TableStatusDataTable SearchStatus(string pattern)
        {
            if (toolStripMenuItemUser.Checked)
            {
                return tableStatusTableAdapter.GetDataBySearchUser(m_Search);
            }
            else if (toolStripMenuItemStatus.Checked)
            {
                return tableStatusTableAdapter.GetDataBySearchStatus(m_Search);
            }
            else if (toolStripMenuItemLocation.Checked)
            {
                return tableStatusTableAdapter.GetDataBySearchStatus(m_Search);
            }
            else if (toolStripMenuItemSource.Checked)
            {
                return tableStatusTableAdapter.GetDataBySearchSource(m_Search);
            }
            return tableStatusTableAdapter.GetDataBySearchAll(m_Search);
        }

        private int? ParseStatus(XmlNode node, ref DateTime at, ref DataSetChattr.TableStatusRow row_new)
        {
            String str = node["id"].InnerText;
            if ((str == null) || (str == ""))
            {
                return null;
            }
            Int64 id = Int64.Parse(str);
            String created_at = node["created_at"].InnerText;
            Regex r = new Regex(@"^(.*) (\+0000) (.*)$");
            Match m = r.Match(created_at);
            if (m.Success)
            {
                created_at = m.Groups[1].Value + " " + m.Groups[3].Value + " +0";
            }
            at = DateTime.ParseExact(created_at, "ddd MMM dd HH:mm:ss yyyy z", new CultureInfo("en-US")).ToUniversalTime();
            String text = HttpUtility.HtmlDecode(Regex.Replace(node["text"].InnerText, "\r", ""));
            r = new Regex(@"^(.*)\n$", RegexOptions.Singleline);
            m = r.Match(text);
            while (m.Success)
            {
                text = m.Groups[1].Value;
                m = r.Match(text);
            }
            String source_url = "";
            String source = node["source"].InnerText;
            r = new Regex(@"<.*?=""(.*?)"">(.*)<");
            m = r.Match(source);
            if (m.Success)
            {
                source_url = m.Groups[1].Value;
                source = m.Groups[2].Value;
            }
            Int64 user_id = Int64.Parse(node["user"]["id"].InnerText);
            String user_name = node["user"]["name"].InnerText;
            String screen_name = node["user"]["screen_name"].InnerText;
            String location = node["user"]["location"].InnerText;
            String profile_image = node["user"]["profile_image_url"].InnerText;
            r = new Regex(@"^(.*)\?");
            m = r.Match(profile_image);
            if (m.Success)
            {
                profile_image = m.Groups[1].Value;
            }
            row_new.ItemArray = new Object[] {
                    id,
                    at,
                    text,
                    source,
                    source_url,
                    user_id,
                    user_name,
                    screen_name,
                    location,
                    profile_image,
                    FLAG_NEW
                };
            int result = -1;
            if (dataSetChattr.TableStatus.FindByid(id) != null)
            {
                result = 0;
            }
            if ((result == -1) && (!m_LoadDone))
            {
                DataSetChattr.TableStatusDataTable table = tableStatusTableAdapter.GetDataByID(id);
                if ((table != null) && (table.Rows.Count > 0))
                {
                    result =  0;
                }
            }
            if (result == 0)
            {
                foreach (DataSetChattr.TableStatusRow row in dataSetChattr.TableStatus.Rows)
                {
                    result++;
                    if (row.RowState != DataRowState.Deleted)
                    {
                        if (row.id == id)
                        {
                            if (row.source == "Jabber/XMPP")
                            {
                                return result;
                            }
                            break;
                        }
                    }
                }
                result = 0;
            }
            return result;
        }

        private int? ParseDirectMessage(XmlNode node, ref DateTime at, ref DataSetChattr.TableStatusRow row_new)
        {
            String str = node["id"].InnerText;
            if ((str == null) || (str == ""))
            {
                return null;
            }
            Int64 id = -Int64.Parse(str);
            String created_at = node["created_at"].InnerText;
            Regex r = new Regex(@"^(.*) (\+0000) (.*)$");
            Match m = r.Match(created_at);
            if (m.Success)
            {
                created_at = m.Groups[1].Value + " " + m.Groups[3].Value + " +0";
            }
            at = DateTime.ParseExact(created_at, "ddd MMM dd HH:mm:ss yyyy z", new CultureInfo("en-US")).ToUniversalTime();
            String text = HttpUtility.HtmlDecode(Regex.Replace(node["text"].InnerText, "\r", ""));
            r = new Regex(@"^(.*)\n$", RegexOptions.Singleline);
            m = r.Match(text);
            while (m.Success)
            {
                text = m.Groups[1].Value;
                m = r.Match(text);
            }
            String source_url = "";
            String source = "";
            Int64 user_id = Int64.Parse(node["sender"]["id"].InnerText);
            String user_name = node["sender"]["name"].InnerText;
            String screen_name = node["sender"]["screen_name"].InnerText;
            String location = node["sender"]["location"].InnerText;
            String profile_image = node["sender"]["profile_image_url"].InnerText;
            r = new Regex(@"^(.*)\?");
            m = r.Match(profile_image);
            if (m.Success)
            {
                profile_image = m.Groups[1].Value;
            }
            row_new.ItemArray = new Object[] {
                    id,
                    at,
                    text,
                    source,
                    source_url,
                    user_id,
                    user_name,
                    screen_name,
                    location,
                    profile_image,
                    FLAG_NEW | FLAG_DM
                };
            int result = -1;
            if (dataSetChattr.TableStatus.FindByid(id) != null)
            {
                result = 0;
            }
            if ((result == -1) && (!m_LoadDone))
            {
                DataSetChattr.TableStatusDataTable table = tableStatusTableAdapter.GetDataByID(id);
                if ((table != null) && (table.Rows.Count > 0))
                {
                    result = 0;
                }
            }
            if (result == 0)
            {
                foreach (DataSetChattr.TableStatusRow row in dataSetChattr.TableStatus.Rows)
                {
                    result++;
                    if (row.RowState != DataRowState.Deleted)
                    {
                        if (row.id == id)
                        {
                            if (row.source == "Jabber/XMPP")
                            {
                                return result;
                            }
                            break;
                        }
                    }
                }
                result = 0;
            }
            return result;
        }

        private DataSetChattr.TableStatusRow ParseXmpp(agsXMPP.protocol.client.Message msg)
        {
            if ((msg.From.Server != "twitter.com") || (msg.From.User != "twitter"))
            {
                return null;
            }
            DateTime at = DateTime.Now.ToUniversalTime();
            Int64 id = Int64.Parse(at.ToString("-yyyyMMddHHmmssfff"));
            String text = "";
            String source_url = "";
            String source = "Jabber/XMPP";
            Int64 user_id = -1;
            String user_name = "";
            String screen_name = "";
            String location = "";
            String profile_image = "";
            int flags = FLAG_NEW;
            Regex r;
            Match m;
            if (msg.ChildNodes.Item(0).GetType() == typeof(agsXMPP.Xml.Dom.Text))
            {
                Debug.WriteLine("ParseXmpp: " + msg.ChildNodes.Item(0).GetType());
            }
            for (int i = 1; i < msg.ChildNodes.Count; i++)
            {
                object item = msg.ChildNodes.Item(i);
                if (item.GetType() == typeof(agsXMPP.Xml.Dom.Element))
                {
                    agsXMPP.Xml.Dom.Element node = item as agsXMPP.Xml.Dom.Element;
                    Debug.WriteLine(node.TagName + " :\'" + node.Value + "'");
                    switch (node.TagName)
                    {
                        case "body":
                            text = HttpUtility.HtmlDecode(Regex.Replace(node.Value, "\r", ""));
                            r = new Regex(@"^(.*)\n$", RegexOptions.Singleline);
                            m = r.Match(text);
                            while (m.Success)
                            {
                                text = m.Groups[1].Value;
                                m = r.Match(text);
                            }
                            break;
                        case "screen_name":
                            screen_name = node.Value;
                            break;
                        case "profile_image":
                            profile_image = node.Value;
                            r = new Regex(@"^(.*)\?");
                            m = r.Match(profile_image);
                            if (m.Success)
                            {
                                profile_image = m.Groups[1].Value;
                            }
                            break;
                        case "x":
                            string stamp = node.Attribute("stamp");
                            if ((stamp != null) && (stamp != ""))
                            {
                                if (!Properties.Settings.Default.OfflineIM)
                                {
                                    return null;
                                }
                                try
                                {
                                    at = DateTime.ParseExact(stamp, @"yyyyMMdd\THH:mm:ss z", new CultureInfo("en-US")).ToUniversalTime();
                                    Debug.WriteLine("stamp: " + at + " (" + at.ToLocalTime() + ")");
                                }
                                catch (SystemException ex)
                                {
                                    Debug.WriteLine("DateTime.ParseExact() Error\n" +
                                        "in ParseXmpp()\n" +
                                        ex.Message + "\n" + "Source: " + ex.Source);
                                }
                            }
                            break;
                        case "entry":
                            for (int n = 1; n < node.ChildNodes.Count; n++)
                            {
                                object entry_item = node.ChildNodes.Item(n);
                                if (entry_item.GetType() == typeof(agsXMPP.Xml.Dom.Element))
                                {
                                    agsXMPP.Xml.Dom.Element entry_node = entry_item as agsXMPP.Xml.Dom.Element;
                                    switch (entry_node.TagName)
                                    {
                                        case "source":
                                            for (int sn = 1; sn < entry_node.ChildNodes.Count; sn++)
                                            {
                                                object source_item = entry_node.ChildNodes.Item(sn);
                                                if (source_item.GetType() == typeof(agsXMPP.Xml.Dom.Element))
                                                {
                                                    agsXMPP.Xml.Dom.Element source_node = source_item as agsXMPP.Xml.Dom.Element;
                                                    switch (source_node.TagName)
                                                    {
                                                        case "title":
                                                            r = new Regex(@"^Twitter \/ (.*)$");
                                                            m = r.Match(source_node.Value);
                                                            if (m.Success)
                                                            {
                                                                screen_name = m.Groups[1].Value;
                                                            }
                                                            break;
                                                        case "author":
                                                            for (int an = 1; an < source_node.ChildNodes.Count; an++)
                                                            {
                                                                object author_item = source_node.ChildNodes.Item(an);
                                                                if (author_item.GetType() == typeof(agsXMPP.Xml.Dom.Element))
                                                                {
                                                                    agsXMPP.Xml.Dom.Element author_node = author_item as agsXMPP.Xml.Dom.Element;
                                                                    switch (author_node.TagName)
                                                                    {
                                                                        case "name":
                                                                            user_name = author_node.Value;
                                                                            break;
                                                                        case "screen_name":
                                                                            screen_name = author_node.Value;
                                                                            break;
                                                                        case "location":
                                                                            location = author_node.Value;
                                                                            break;
                                                                    }
                                                                    Debug.WriteLine("ParseXmpp: <author> " + author_node.TagName + " [" + author_node.Value + "]");
                                                                }
                                                            }
                                                            break;
                                                        case "from_source":
                                                            String from_source = HttpUtility.HtmlDecode(source_node.Value);
                                                            source_url = "";
                                                            source = from_source;
                                                            r = new Regex(@"<.*?=""(.*?)"">(.*)<");
                                                            m = r.Match(source);
                                                            if (m.Success)
                                                            {
                                                                source_url = m.Groups[1].Value;
                                                                source = m.Groups[2].Value;
                                                            }
                                                            break;
                                                        case "icon":
                                                            profile_image = source_node.Value;
                                                            break;
                                                    }
                                                    Debug.WriteLine("ParseXmpp: <source> " + source_node.TagName + " [" + source_node.Value + "]");
                                                }
                                            }
                                            break;
                                        case "id":
                                            r = new Regex(@"^.*?\,(.*\+0)0\:00\:\/statuses\/(.*)$");
                                            m = r.Match(entry_node.Value);
                                            if (m.Success)
                                            {
                                                Debug.WriteLine(DateTime.ParseExact("2007-12-25T00:28:21+0", @"yyyy-MM-dd\THH:mm:ssz", new CultureInfo("en-US")));
                                                at = DateTime.ParseExact(m.Groups[1].Value, @"yyyy-MM-dd\THH:mm:ssz", new CultureInfo("en-US")).ToUniversalTime();
                                                id = long.Parse(m.Groups[2].Value);
                                            }
                                            break;
                                        default:
                                            Debug.WriteLine("ParseXmpp: <entry> " + entry_node.TagName + " [" + entry_node.Value + "]");
                                            break;
                                    }
                                }
                            }
                            break;
                        default:
                            Debug.WriteLine("ParseXmpp: " + node.TagName + " [" + node.Value + "]");
                            break;
                    }
                }
                else if (item.GetType() == typeof(agsXMPP.Xml.Dom.Text))
                {
                    agsXMPP.Xml.Dom.Text item_text = item as agsXMPP.Xml.Dom.Text;
                    Debug.WriteLine("ParseXmpp: (agsXMPP.Xml.Dom.Text) " + item_text);
                }
            }
            if ((screen_name == "") || (profile_image == ""))
            {
                return null;
            }
            r = new Regex(@"^Direct from " + screen_name + @":\n(.*)\n\nReply with 'd " + screen_name + @" hi\.'$", RegexOptions.Singleline);
            m = r.Match(text);
            if (m.Success)
            {
                text = m.Groups[1].Value;
                flags |= FLAG_DM;
                source = "";
            }
            r = new Regex(@"^" + screen_name + @": ", RegexOptions.Singleline);
            m = r.Match(text);
            if (m.Success)
            {
                text = Regex.Replace(text, @"^" + screen_name + @": ", "");
            }
            else
            {
                r = new Regex(@"^\(" + screen_name + @"\): ", RegexOptions.Singleline);
                m = r.Match(text);
                if (m.Success)
                {
                    text = Regex.Replace(text, @"^\(" + screen_name + @"\): ", "");
                }
                else
                {
                    text = Regex.Replace(text, @"^" + screen_name + @" ", "");
                }
            }
            if (Properties.Settings.Default.TipFilter)
            {
                r = new Regex(@"^(.*)\n\n(Tip: .*)$", RegexOptions.Singleline);
                m = r.Match(text);
                if (m.Success)
                {
                    string txt = m.Groups[1].Value;
                    string tip = m.Groups[2].Value;
                    r = new Regex(@"\n", RegexOptions.Singleline);
                    m = r.Match(tip);
                    if (!m.Success)
                    {
                        text = txt;
                        Debug.WriteLine("ParseXmpp: (Tip) " + tip);
                    }
                }
                r = new Regex(@"^(.*)\n\n(Twitter asks: .*)$", RegexOptions.Singleline);
                m = r.Match(text);
                if (m.Success)
                {
                    string txt = m.Groups[1].Value;
                    string ask = m.Groups[2].Value;
                    r = new Regex(@"\n", RegexOptions.Singleline);
                    m = r.Match(ask);
                    if (!m.Success)
                    {
                        text = txt;
                        Debug.WriteLine("ParseXmpp: (ask) " + ask);
                    }
                }
                r = new Regex(@"^(.*)\n$", RegexOptions.Singleline);
                m = r.Match(text);
                while (m.Success)
                {
                    text = m.Groups[1].Value;
                    m = r.Match(text);
                }
            }
            DataSetChattr.TableStatusRow row_new = dataSetChattr.TableStatus.NewTableStatusRow();
            row_new.ItemArray = new Object[] {
                id,
                at,
                text,
                source,
                source_url,
                user_id,
                user_name,
                screen_name,
                location,
                profile_image,
                flags
            };
            return row_new;
        }

        private void ParseUserName(StatusParser parser, DataSetChattr.TableStatusRow row)
        {
            LinkedList<string> users = parser.Users;
            LinkedListNode<string> node = users.First;
            while (node != null)
            {
                if (node.Value == Properties.Settings.Default.UserName)
                {
                    row.flags |= FLAG_INME;
                }
                node = node.Next;
            }
        }

        private void ParseTinyUrl(StatusParser parser)
        {
            LinkedList<string> urls = parser.URLs;
            LinkedListNode<string> node = urls.First;
            while (node != null)
            {
                RequestTinyUrl(node.Value);
                node = node.Next;
            }
        }

        private bool MatchKeyword(string text, string keyword)
        {
            foreach (string word in Regex.Split(keyword, " "))
            {
                Regex r = new Regex(@"^\-(.*)", RegexOptions.IgnoreCase);
                Match m = r.Match(word);
                if (m.Success)
                {
                    string replace = Regex.Escape(m.Groups[1].Value);
                    text = Regex.Replace(text, replace, "", RegexOptions.IgnoreCase);
                }
            }
            int match = 0;
            int matched = 0;
            foreach (string word in Regex.Split(keyword, " "))
            {
                Regex r = new Regex(@"^\-(.*)", RegexOptions.IgnoreCase);
                Match m = r.Match(word);
                if (!m.Success)
                {
                    match++;
                    r = new Regex(Regex.Escape(word), RegexOptions.IgnoreCase);
                    m = r.Match(text);
                    if (m.Success)
                    {
                        matched++;
                    }
                }
            }
            return (matched == match);
        }

        private bool ParseKeyword(StatusParser parser, DataSetChattr.TableStatusRow row)
        {
            foreach (string keyword in Regex.Split(Properties.Settings.Default.Keywords, "\n"))
            {
                if ((keyword != "") && (keyword != "\r"))
                {
                    string word = Regex.Replace(keyword, "\r", "");
                    if (MatchKeyword(row.user_screen_name, word))
                    {
                        row.flags |= FLAG_KEYWORDS;
                        return true;
                    }
                    if (MatchKeyword(row.user_name, word))
                    {
                        row.flags |= FLAG_KEYWORDS;
                        return true;
                    }
                    if (MatchKeyword(row.text, word))
                    {
                        row.flags |= FLAG_KEYWORDS;
                        return true;
                    }
                }
            }
            return false;
        }

        delegate int DelegateGetSelectedIdx();

        private long GetSelectedID()
        {
            long select = 0;
            DelegateGetSelectedIdx get = delegate
            {
                return listBoxStatuses.SelectedIndex;
            };
            int idx = (int)Invoke(get);
            if (idx != -1)
            {
                DataSetChattr.TableStatusRow row = dataSetChattr.TableStatus.Rows[idx] as DataSetChattr.TableStatusRow;
                select = row.id;
            }
            return select;
        }

        private long GetSelectedSearchID()
        {
            long select = 0;
            if (m_TblSearch != null)
            {
                DelegateGetSelectedIdx get = delegate
                {
                    return listBoxSearch.SelectedIndex;
                };
                int idx = (int)Invoke(get);
                if (idx != -1)
                {
                    DataSetChattr.TableStatusRow row = m_TblSearch.Rows[idx] as DataSetChattr.TableStatusRow;
                    select = row.id;
                }
            }
            return select;
        }

        private void SetSelectedID(long select, BackgroundWorker worker)
        {
            if (select == 0)
            {
                worker.ReportProgress((int)ProgressOp.LIST_SELECT, -1);
                worker.ReportProgress((int)ProgressOp.LIST_SELECT, 0);
            }
            else
            {
                int cnt = dataSetChattr.TableStatus.Rows.Count;
                for (int i = 0; i < cnt; i++)
                {
                    DataSetChattr.TableStatusRow row = dataSetChattr.TableStatus.Rows[i] as DataSetChattr.TableStatusRow;
                    if (row.id == select)
                    {
                        worker.ReportProgress((int)ProgressOp.LIST_SELECT, -1);
                        worker.ReportProgress((int)ProgressOp.LIST_SELECT, i);
                        break;
                    }
                }
            }
        }

        private void SetSelectedSearchID(long select, BackgroundWorker worker)
        {
            if (select == 0)
            {
                worker.ReportProgress((int)ProgressOp.LIST_SEARCH_SELECT, -1);
                worker.ReportProgress((int)ProgressOp.LIST_SEARCH_SELECT, 0);
            }
            else
            {
                int cnt = m_TblSearch.Rows.Count;
                for (int i = 0; i < cnt; i++)
                {
                    DataSetChattr.TableStatusRow row = m_TblSearch.Rows[i] as DataSetChattr.TableStatusRow;
                    if (row.id == select)
                    {
                        worker.ReportProgress((int)ProgressOp.LIST_SEARCH_SELECT, -1);
                        worker.ReportProgress((int)ProgressOp.LIST_SEARCH_SELECT, i);
                        break;
                    }
                }
            }
        }

        private void AddStatus(DataSetChattr.TableStatusRow row_new, LinkedList<IListItem> list)
        {
            AddRow(row_new);
            list.AddLast(new IListItemAdd(row_new.id, 0));
        }

        private void InsertStatus(DataSetChattr.TableStatusRow row_new, LinkedList<IListItem> list)
        {
            int cnt = dataSetChattr.TableStatus.Rows.Count;
            int x;
            for (x = 0; x < cnt; x++)
            {
                DataSetChattr.TableStatusRow row = (DataSetChattr.TableStatusRow)dataSetChattr.TableStatus.Rows[x];
                if (row.RowState == DataRowState.Deleted)
                {
                }
                else if (row_new.created_at > row.created_at)
                {
                    break;
                }
                else if (row_new.created_at == row.created_at)
                {
                    if ((row_new.id >= 0) && (row.id >= 0) && (row_new.id > row.id))
                    {
                        break;
                    }
                    else if ((row_new.id < 0) && (row.id < 0) && (row_new.id < row.id))
                    {
                        break;
                    }
                    else if ((row_new.id < 0) && (row.id >= 0))
                    {
                        break;
                    }
                }
            }
            InsertRow(row_new, x);
            list.AddLast(new IListItemInsert(row_new.id, x));
            Debug.WriteLine(row_new.user_screen_name + ": \'" + row_new.text + "\'");
        }

        private long ReplaceStatus(DataSetChattr.TableStatusRow row_new, int pos, long select, LinkedList<IListItem> list)
        {
            DataSetChattr.TableStatusRow row = dataSetChattr.TableStatus.Rows[pos] as DataSetChattr.TableStatusRow;
            if (row.id == select)
            {
                select = row_new.id;
            }
            if (row.id == m_LastId)
            {
                m_LastId = row_new.id;
            }
            row_new.flags = row.flags;
            row.Delete();
            if (row.RowState == DataRowState.Detached)
            {
                list.AddLast(new IListItemRemove(0, pos));
            }
            else
            {
                list.AddLast(new IListItemDelete(0, pos));
            }
            InsertStatus(row_new, list);
            return select;
        }

        private void AddRow(DataSetChattr.TableStatusRow row)
        {
            try
            {
                dataSetChattr.TableStatus.Rows.Add(row);
            }
            catch (SystemException ex)
            {
                dataSetChattr.TableStatus.RejectChanges();
                Debug.WriteLine("dataSetChattr.TableStatus.Rows.Add() Error\n" +
                    "in AddRow()\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
        }

        private void InsertRow(DataSetChattr.TableStatusRow row, int pos)
        {
            try
            {
                dataSetChattr.TableStatus.Rows.InsertAt(row, pos);
            }
            catch (SystemException ex)
            {
                dataSetChattr.TableStatus.RejectChanges();
                Debug.WriteLine("dataSetChattr.TableStatus.Rows.Add() Error\n" +
                    "in InsertRow()\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
        }

        private int GetTopIndex()
        {
            DelegateGetSelectedIdx get = delegate
            {
                return listBoxStatuses.TopIndex;
            };
            return (int)Invoke(get);
        }

        private int GetTopIndexSearch()
        {
            DelegateGetSelectedIdx get = delegate
            {
                return listBoxSearch.TopIndex;
            };
            return (int)Invoke(get);
        }

        private void TopIndex(int top, long id, BackgroundWorker worker)
        {
            if ((top == 0) && (Properties.Settings.Default.TopLog))
            {
                worker.ReportProgress((int)ProgressOp.LIST_TOP_INDEX, 0);
            }
            else if (id != 0)
            {
                int i = 0;
                foreach (DataSetChattr.TableStatusRow row in dataSetChattr.TableStatus.Rows)
                {
                    if (row.id == id)
                    {
                        break;
                    }
                    i++;
                }
                worker.ReportProgress((int)ProgressOp.LIST_TOP_INDEX, i);
            }
        }

        private void TopIndexSearch(int top, long id, BackgroundWorker worker)
        {
            if (Properties.Settings.Default.TopLog && (top == 0))
            {
                worker.ReportProgress((int)ProgressOp.LIST_SEARCH_TOP_INDEX, 0);
            }
            else if (id != 0)
            {
                int i = 0;
                foreach (DataSetChattr.TableStatusRow row in m_TblSearch.Rows)
                {
                    if (row.id == id)
                    {
                        break;
                    }
                    i++;
                }
                worker.ReportProgress((int)ProgressOp.LIST_SEARCH_TOP_INDEX, i);
            }
        }

        private static void ThreadGetProfileImage(object param)
        {
            if (param.GetType() == typeof(IGetHttp))
            {
                IGetHttp arg = param as IGetHttp;
                HttpWebResponse res = TwitterAPI.Get(arg.Url);
                arg.Response = res;
            }
        }

        private static void RunGetProfileImage(object param)
        {
            if (param.GetType() == typeof(IGetProfileImage))
            {
                IGetProfileImage arg = param as IGetProfileImage;
                IGetHttp igh = new IGetHttp(arg.Url);
                Thread t = new Thread(ThreadGetProfileImage);
                if (!RunThreadQueue(t, arg.Queue, igh))
                {
                    arg.Exit(true);
                    return;
                }
                HttpWebResponse res = igh.Response;
                if ((res != null) && (res.StatusCode == HttpStatusCode.OK))
                {
                    Bitmap bmp = null;
                    try
                    {
                        bmp = (Bitmap)Bitmap.FromStream(res.GetResponseStream());
                    }
                    catch (SystemException ex)
                    {
                        Debug.WriteLine("DoBackGround_GetProfileImage() Error\n" +
                            ex.Message + "\n" + "Source: " + ex.Source);
                    }
                    finally
                    {
                        res.Close();
                    }
                    arg.Mutex.WaitOne();
                    try
                    {
                        bool add = false;
                        if (bmp != null)
                        {
                            DataSetChattr.TableProfileImageRow row_new = arg.DataSet.TableProfileImage.NewTableProfileImageRow();
                            row_new.ItemArray = new object[] { arg.Url, Bitmap2ByteArray(bmp), bmp.Width, bmp.Height };
                            try
                            {
                                Debug.WriteLine("ProfileImag :" + arg.Url);
                                arg.DataSet.TableProfileImage.Rows.Add(row_new);
                                add = true;
                            }
                            catch (SystemException ex)
                            {
                                Debug.WriteLine("DoBackGround_GetProfileImage() Error\n" +
                                    ex.Message + "\n" + "Source: " + ex.Source);
                            }
                        }
                        else
                        {
                            arg.Request(arg.Url);
                        }
                        if (add)
                        {
                            if (!Properties.Settings.Default.NotCommitFromIM)
                            {
                                try
                                {
                                    arg.Adapter.Update(arg.DataSet.TableProfileImage);
                                    arg.DataSet.TableProfileImage.AcceptChanges();
                                }
                                catch (SystemException ex)
                                {
                                    arg.DataSet.TableProfileImage.RejectChanges();
                                    Debug.WriteLine("Update() Error\n" +
                                        "in RunGetProfileImage()" +
                                        ex.Message + "\n" + "Source: " + ex.Source);
                                }
                            }
                            bool begin = false;
                            try
                            {
                                int cnt = arg.DataSet.TableStatus.Rows.Count;
                                int profile = 0;
                                for (int i = 0; i < cnt; i++)
                                {
                                    DataSetChattr.TableStatusRow row = arg.DataSet.TableStatus.Rows[i] as DataSetChattr.TableStatusRow;
                                    if (row.user_profile_image == arg.Url)
                                    {
                                        if (arg.Queue.Count > 0)
                                        {
                                            arg.Exit(true);
                                            return;
                                        }
                                        Debug.WriteLine("ProfileImag :" + row.user_screen_name + ": " + row.text);
                                        profile++;
                                        if (!begin)
                                        {
                                            begin = true;
                                            arg.BeginUpdate();
                                        }
                                        arg.Replase(i);
                                    }
                                }
                                Debug.WriteLine("ProfileImag :" + profile);
                            }
                            catch (SystemException ex)
                            {
                                arg.DataSet.TableProfileImage.RejectChanges();
                                Debug.WriteLine("RunGetProfileImage() Error\n" +
                                    ex.Message + "\n" + "Source: " + ex.Source);
                            }
                            finally
                            {
                                if (begin)
                                {
                                    arg.EndUpdate();
                                }
                            }
                        }
                    }
                    catch (SystemException ex)
                    {
                        Debug.WriteLine("RunGetProfileImage() Error\n" +
                            ex.Message + "\n" + "Source: " + ex.Source);
                    }
                    finally
                    {
                        arg.Mutex.ReleaseMutex();
                    }
                }
                else if (res != null)
                {
                    res.Close();
                    bool request = true;
                    if (FormMain.DicUrl.ContainsKey(arg.Url))
                    {
                        int c = FormMain.DicUrl[arg.Url];
                        c++;
                        if (c < FormMain.RETRY_URL)
                        {
                            FormMain.DicUrl[arg.Url] = c;
                        }
                        else
                        {
                            request = false;
                            FormMain.DicUrl.Remove(arg.Url);
                        }
                    }
                    else
                    {
                        FormMain.DicUrl.Add(arg.Url, 0);
                    }
                    if (request)
                    {
                        arg.Request(arg.Url);
                    }
                }
            }
            ((IGetProfileImage)param).Exit(false);
        }

        int m_RunGetProfileImage = 0;

        private void ExitGetProfileImage(bool exit)
        {
            Interlocked.Decrement(ref m_RunGetProfileImage);
            if (exit && !backgroundWorker.IsBusy)
            {
                MethodInvoker quit = delegate
                {
                    this.Close();
                };
                Invoke(quit);
            }
        }

        private void InvokeReportProgress(int progressPercentage, object userState)
        {
            MethodInvoker method = delegate
            {
                ProgressChangedEventArgs arg = new ProgressChangedEventArgs(progressPercentage, userState);
                backgroundWorker_ProgressChanged(this, arg);
            };
            Invoke(method);
        }

        private void listBoxStatuses_BeginUpdate()
        {
            InvokeReportProgress((int)ProgressOp.LIST_BEGIN_UPDATE, null);
        }

        private void listBoxStatuses_EndUpdate()
        {
            InvokeReportProgress((int)ProgressOp.LIST_END_UPDATE, null);
        }

        private void listBoxStatuses_Replase(int idx)
        {
            InvokeReportProgress((int)ProgressOp.LIST_REPLACE, idx);
        }

        private object DoBackGround_GetProfileImage(String arg, BackgroundWorker worker)
        {
            object result = null;
            if ((m_QueueProfile.Count == 0) && (dataSetChattr.TableProfileImage.Rows.Find(arg) == null))
            {
                if (m_RunGetProfileImage > 0)
                {
                    Thread.Sleep(100);
                    RequestProfileImage(arg);
                }
                else
                {
                    IGetProfileImage igt = new IGetProfileImage(m_MutexProfile, arg, tableStatusTableAdapter, tableProfileImageTableAdapter,
                        dataSetChattr, m_QueueProfile, RequestProfileImage, ExitGetProfileImage, listBoxStatuses_BeginUpdate,
                        listBoxStatuses_EndUpdate, listBoxStatuses_Replase);
                    Thread t = new Thread(RunGetProfileImage);
                    Interlocked.Increment(ref m_RunGetProfileImage);
                    t.Start(igt);
                }
            }
            return result;
        }

        private static void ThreadGetTinyUrl(object param)
        {
            if (param.GetType() == typeof(IGetHttp))
            {
                IGetHttp arg = param as IGetHttp;
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(arg.Url);
                req.Method = "HEAD";
                req.KeepAlive = false;
                req.CookieContainer = null;
                req.Timeout = 5000;
                try
                {
                    arg.Response = (HttpWebResponse)req.GetResponse();
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("ThreadGetTinyUrl(\'" + arg + "\') Error\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                    if (ex.GetType() == typeof(WebException))
                    {
                        arg.Exception = ex;
                    }
                }
            }
        }

        private static void RunGetTinyUrl(object param)
        {
            if (param.GetType() == typeof(IGetTinyUrl))
            {
                IGetTinyUrl arg = param as IGetTinyUrl;
                IGetHttp igh = new IGetHttp(arg.Url);
                Thread t = new Thread(ThreadGetTinyUrl);
                if (!RunThreadQueue(t, arg.Queue, igh))
                {
                    arg.Exit(true);
                    return;
                }
                HttpWebResponse res = igh.Response;
                SystemException exc = igh.Exception;
                try
                {
                    if (res != null)
                    {
                        res.Close();
                    }
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("res.Close() Error\n" +
                        "in DoBackGround_GetTinyUrl(\'" + arg + "\')\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                if (exc != null)
                {
                    if (exc.GetType() == typeof(WebException))
                    {
                        WebException wex = (WebException)exc;
                        if (wex.Status == WebExceptionStatus.Timeout)
                        {
                            bool request = true;
                            if (FormMain.DicUrl.ContainsKey(arg.Url))
                            {
                                int c = FormMain.DicUrl[arg.Url];
                                c++;
                                if (c < FormMain.RETRY_URL)
                                {
                                    FormMain.DicUrl[arg.Url] = c;
                                }
                                else
                                {
                                    request = false;
                                    FormMain.DicUrl.Remove(arg.Url);
                                }
                            }
                            else
                            {
                                FormMain.DicUrl.Add(arg.Url, 0);
                            }
                            if (request)
                            {
                                arg.Request(arg.Url);
                            }
                        }
                    }
                }
                else if ((res != null) && (res.StatusCode == HttpStatusCode.OK))
                {
                    arg.Mutex.WaitOne();
                    try
                    {
                        arg.Table.Rows.Add(arg.Url, res.ResponseUri.AbsoluteUri);
                        if (arg.Queue.Count > 0)
                        {
                            return;
                        }
                        if (!Properties.Settings.Default.NotCommitFromIM)
                        {
                            arg.Adapter.Update(arg.Table);
                            arg.Table.AcceptChanges();
                            Debug.WriteLine("RunGetTinyUrl: Update()");
                        }
                        Debug.WriteLine("TinyUrl: " + arg.Url + " = " + res.ResponseUri.AbsoluteUri);
                    }
                    catch (SystemException ex)
                    {
                        Debug.WriteLine("RunGetTinyUrl(\'" + arg + "\') Error\n" +
                            ex.Message + "\n" + "Source: " + ex.Source);
                    }
                    finally
                    {
                        arg.Mutex.ReleaseMutex();
                    }
                }
            }
            ((IGetTinyUrl)param).Exit(false);
        }

        int m_RunGetTinyUrl = 0;

        private void ExitGetTinyUrl(bool exit)
        {
            Interlocked.Decrement(ref m_RunGetTinyUrl);
            if (exit && !backgroundWorker.IsBusy)
            {
                MethodInvoker quit = delegate
                {
                    this.Close();
                };
                Invoke(quit);
            }
        }

        private object DoBackGround_GetTinyUrl(String arg, BackgroundWorker worker)
        {
            object result = null;
            if ((m_QueueTnyUrl.Count == 0) && (dataSetChattr.TableTinyUrl.Rows.Find(arg) == null))
            {
                if (m_RunGetTinyUrl > 0)
                {
                    Thread.Sleep(100);
                    RequestTinyUrl(arg);
                }
                else
                {
                    Debug.WriteLine("TinyUrl: Get(" + arg + ")");
                    IGetTinyUrl igt = new IGetTinyUrl(m_MutexTinyUrl, arg, tableTinyUrlTableAdapter, dataSetChattr.TableTinyUrl,
                        m_QueueTnyUrl, RequestTinyUrl, ExitGetTinyUrl);
                    Thread t = new Thread(RunGetTinyUrl);
                    Interlocked.Increment(ref m_RunGetTinyUrl);
                    t.Start(igt);
                }
            }
            return result;
        }

        private object DoBackGround_DeleteAll(String arg, BackgroundWorker worker)
        {
            Debug.WriteLine("DoBackGround_DeleteAll");
            // Statuses
            m_MutexStatus.WaitOne();
            try
            {
                worker.ReportProgress((int)ProgressOp.LIST_BEGIN_UPDATE);
                worker.ReportProgress((int)ProgressOp.LIST_CLEAR);
                worker.ReportProgress((int)ProgressOp.LIST_END_UPDATE);
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("DoBackGround_DeleteAll() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            finally
            {
                m_MutexStatus.ReleaseMutex();
            }
            // Search
            m_MutexSearch.WaitOne();
            try
            {
                m_TblSearch = null;
                worker.ReportProgress((int)ProgressOp.LIST_SEARCH_BEGIN_UPDATE);
                worker.ReportProgress((int)ProgressOp.LIST_SEARCH_CLEAR);
                worker.ReportProgress((int)ProgressOp.LIST_SEARCH_END_UPDATE);
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("DoBackGround_Delete() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            finally
            {
                m_MutexSearch.ReleaseMutex();
            }
            worker.ReportProgress((int)ProgressOp.LIST_ENABLE);
            worker.ReportProgress((int)ProgressOp.NUM_STATUS);
            // Drop
            SQLite.DropTable(SQL_PATH);
            SQLite.CreateDB(SQL_PATH);
            SQLite.Vacuum(SQL_PATH);
            // Fill
            tableStatusTableAdapter.Fill(dataSetChattr.TableStatus);
            tableProfileImageTableAdapter.Fill(dataSetChattr.TableProfileImage);
            tableTinyUrlTableAdapter.Fill(dataSetChattr.TableTinyUrl);
            m_Load = 0;
            m_Loading = 0;
            m_LoadDone = true;
            return null;
        }

        private object DoBackGround_Favorite(String arg, BackgroundWorker worker)
        {
            long id = long.Parse(arg);
            if (id >= 0)
            {
                worker.ReportProgress((int)ProgressOp.STATUS_BAR, "お気に入り登録中...");
                HttpWebResponse res = TwitterAPI.Favorite(Properties.Settings.Default.UserName, m_Prefs.Password, id);
                if (res != null)
                {
                    res.Close();
                    if (res.StatusCode == HttpStatusCode.OK)
                    {
                        worker.ReportProgress((int)ProgressOp.STATUS_BAR, "お気に入り登録完了");
                    }
                    else
                    {
                        Debug.WriteLine("Favoring: " + res.StatusCode);
                        worker.ReportProgress((int)ProgressOp.STATUS_BAR, "お気に入り登録エラー");
                    }
                }
            }
            return null;
        }

        private static void ThreadUpdate(object param)
        {
            if (param.GetType() == typeof(IGetTimeline))
            {
                IGetTimeline arg = param as IGetTimeline;
                HttpWebResponse res = TwitterAPI.Update(arg.User, arg.Pass, arg.Option);
                arg.Response = res;
            }
        }

        private object DoBackGround_Update(String arg, BackgroundWorker worker)
        {
            IResultUpdate result = null;
            worker.ReportProgress((int)ProgressOp.STATUS_BAR, "ステータス送信中...");
            IGetTimeline igt = new IGetTimeline(Properties.Settings.Default.UserName, m_Prefs.Password, arg);
            Thread t = new Thread(ThreadUpdate);
            if (!RunThread(t, worker, igt))
            {
                return null;
            }
            HttpWebResponse res = igt.Response;
            if ((res != null) && (res.StatusCode == HttpStatusCode.OK))
            {
                try
                {
                    StreamReader reader = new StreamReader(res.GetResponseStream(), Encoding.UTF8);
                    string response = reader.ReadToEnd();
                    Debug.WriteLine("Update: " + response);
                    res.Close();
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("res.Close() Error\n" +
                        "in DoBackGround_Update(\'" + arg + "\')\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                worker.ReportProgress((int)ProgressOp.STATUS_BAR, "送信完了");
                result = new IResultUpdate(true);
            }
            else
            {
                if (res != null)
                {
                    res.Close();
                }
                string error = GetError(res);
                if (error != null)
                {
                    worker.ReportProgress((int)ProgressOp.STATUS_BAR, "送信エラー" + error);
                }
                result = new IResultUpdate(false);
            }
            return (object)result;
        }

        private object DoBackGround_SetFlag(String arg, BackgroundWorker worker)
        {
            string[] args = Regex.Split(arg, " ");
            if (args.Length >= 2)
            {
                long id = long.Parse(args[0]);
                int flags = int.Parse(args[1]);
                m_MutexStatus.WaitOne();
                try
                {
                    int cnt = dataSetChattr.TableStatus.Rows.Count;
                    for (int i = 0; i < cnt; i++)
                    {
                        DataSetChattr.TableStatusRow row = dataSetChattr.TableStatus.Rows[i] as DataSetChattr.TableStatusRow;
                        if ((row.id == id) && (row.flags != flags))
                        {
                            Debug.WriteLine(DateTime.Now + " DoBackGround_SetFlag() " + flags);
                            row.flags = flags;
                            break;
                        }
                    }
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("DoBackGround_SetFlag() Error\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                finally
                {
                    m_MutexStatus.ReleaseMutex();
                }
            }
            return null;
        }

        private String NumStatus()
        {
            if (m_TblSearch != null)
            {
                return listBoxSearch.Items.Count + " ";
            }
            return listBoxStatuses.Items.Count + " ";
        }

        private void SetToolStripStatusLabelText(string text)
        {
            toolStripStatusLabel.Text = text;
            if (text == "")
            {
                notifyIcon.Text = "Chattr";
            }
            else
            {
                notifyIcon.Text = "Chattr\n" + text;
            }
        }

        private void NotifyFlash(IResultGetFollowing result)
        {
            if (notifyIcon.Visible)
            {
                bool flash = false;
                foreach (IPopup popup in result.List)
                {
                    switch (Properties.Settings.Default.PopupKind)
                    {
                        case NOTIFY_INME:
                            flash = ((popup.Flags & (FLAG_INME | FLAG_NEW)) == (FLAG_INME | FLAG_NEW));
                            break;
                        case NOTIFY_KEYWORDS:
                            flash = ((popup.Flags & (FLAG_KEYWORDS | FLAG_NEW)) == (FLAG_KEYWORDS | FLAG_NEW));
                            break;
                        default:
                            flash = ((popup.Flags & FLAG_NEW) != 0);
                            break;
                    }
                    if (!flash)
                    {
                        flash = ((popup.Flags & (FLAG_NEW | FLAG_DM)) == (FLAG_NEW | FLAG_DM));
                    }
                    if (flash)
                    {
                        m_Popup.Add(popup.ID, popup.Flags, popup.User, popup.Text);
                    }
                }
            }
            else
            {
                bool flash = false;
                if (Properties.Settings.Default.NotifyTaskbar)
                {
                    switch (Properties.Settings.Default.NotifyTaskbarKind)
                    {
                        case NOTIFY_INME:
                            flash = ((result.Flags & (FLAG_INME | FLAG_NEW)) == (FLAG_INME | FLAG_NEW));
                            break;
                        case NOTIFY_KEYWORDS:
                            flash = ((result.Flags & (FLAG_KEYWORDS | FLAG_NEW)) == (FLAG_KEYWORDS | FLAG_NEW));
                            break;
                        default:
                            flash = ((result.Flags & FLAG_NEW) != 0);
                            break;
                    }
                }
                if (!flash)
                {
                    flash = ((result.Flags & (FLAG_NEW | FLAG_DM)) == (FLAG_NEW | FLAG_DM));
                }
                if (flash)
                {
                    FlashWindow(this.Handle, true);
                }
            }
        }

        private void Quit()
        {
            CloseXmpp();
            timer.Enabled = false;
            DataTable changes = null;
            try
            {
                changes = dataSetChattr.TableStatus.GetChanges();
                if ((changes != null) && (changes.Rows.Count != 0))
                {
                    if (CommitTableStatus(dataSetChattr.TableStatus))
                    {
                        dataSetChattr.TableStatus.AcceptChanges();
                    }
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("Commit Error (dataSetChattr.TableStatus)\n" +
                    "in Quit()\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            try
            {
                changes = dataSetChattr.TableProfileImage.GetChanges();
                if ((changes != null) && (changes.Rows.Count != 0))
                {
                    tableProfileImageTableAdapter.Update(dataSetChattr.TableProfileImage);
                    dataSetChattr.TableProfileImage.AcceptChanges();
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("Commit Error (dataSetChattr.TableProfileImage)\n" +
                    "in Quit()\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            try
            {
                changes = dataSetChattr.TableTinyUrl.GetChanges();
                if ((changes != null) && (changes.Rows.Count != 0))
                {
                    tableTinyUrlTableAdapter.Update(dataSetChattr.TableTinyUrl);
                    dataSetChattr.TableTinyUrl.AcceptChanges();
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("Commit Error (dataSetChattr.TableTinyUrl)\n" +
                    "in Quit()\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            Properties.Settings.Default.SelectedID = GetSelectedID();
            DeleteOldStatuses();
            UpdateLocation();
            m_Prefs.Save();
            m_fBgBusy = false;
        }

        private void DeleteOldStatuses()
        {
            DateTime now = DateTime.Today.ToUniversalTime();
            DateTime date = GetOldTime(now);
            if (date != DateTime.MinValue)
            {
                SQLite.DeleteOldStatuses(SQL_PATH, date);
            }
        }

        private DateTime GetOldTime(DateTime date)
        {
            switch ((LogLimit)Properties.Settings.Default.LogLimit)
            {
                case LogLimit.DAY1:
                    return date.AddDays(-1);
                case LogLimit.DAY3:
                    return date.AddDays(-3);
                case LogLimit.WEEK1:
                    return date.AddDays(-7);
                case LogLimit.WEEK2:
                    return date.AddDays(-14);
                case LogLimit.MONTH1:
                    return date.AddMonths(-1);
                case LogLimit.MONTH2:
                    return date.AddMonths(-2);
                case LogLimit.MONTH3:
                    return date.AddMonths(-3);
                case LogLimit.MONTH6:
                    return date.AddMonths(-6);
                case LogLimit.YEAR1:
                    return date.AddYears(-1);
            }
            return DateTime.MinValue;
        }
    }
}
