// 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 208 2009-08-16 07:27:51Z 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 Newtonsoft.Json;

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_RETWEET_VIA_API = "retweet_via_api";
        private const string BG_SET_FLAG = "setflag";
        private const string BG_USER_STREAM = "user_stream";
        private const string BG_DUMMY = "";

        private const string PROTECTED = "☹";

        private const string RTL = "‭";

        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_RETWEET = 0x08;
        public const int FLAG_PROTECTED = 0x10;
        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_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|bit\.ly)/[0-9a-zA-Z]+)";

        private Mutex m_MutexBgWork;
        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 bool m_FirstRetrieve = true;

        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 DataSetChattr.TableStatusDataTable m_TblSearch = null;
        private string m_Search;

        private long m_ReplyTo = 0;
        private string m_ReplyUser = null;

        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;

        private float m_IconWith = 0;

        private HttpWebResponse m_Stream = null;
        private Thread m_StreamThread = null;
        private ArrayList m_StreamArray = new ArrayList();
        private Boolean m_StreamEnable = false;

        private Boolean m_MouseHoverStatuses = false;
        private Boolean m_MouseHoverSearch = false;

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

        public static long GetSerializedLength(object objGraph)
        {
            long size = 0;
            MemoryStream stream = new MemoryStream();
            try
            {
                BinaryWriter writer = new BinaryWriter(stream);
                (new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()).Serialize(writer.BaseStream, objGraph);
                writer.Flush();
                size = stream.Length;
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("GetSerializedLength() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            finally
            {
                stream.Close();
            }
            return size;
        }

        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 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";
#if __CHATTR_X64__
                this.Text += " x64";
#endif //__CHATTR_X64__
            }
        }

        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 != "")
                    {
                        if (line[0] == RTL[0])
                        {
                            graph.DrawString(line, font, brush, rect, format);
                        }
                        else
                        {
                            graph.DrawString(RTL + 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)
        {
            rectF = (RectangleF)bounds;
            String retweet = "";
            if ((row.flags & FLAG_RETWEET) != 0)
            {
                retweet = "      ";
            }
            String str = RTL + retweet + row.user_screen_name;
            if (Properties.Settings.Default.OnlyScreenName)
            {
                if ((row.flags & FLAG_PROTECTED) != 0)
                {
                    str += " " + PROTECTED;
                }
                str += " ";
            }
            else if ((row.user_name != "") && (row.user_name != row.user_screen_name))
            {
                str += " / " + row.user_name;
                if ((row.flags & FLAG_PROTECTED) != 0)
                {
                    str += " " + PROTECTED;
                }
                str += "\n";
            }
            else
            {
                if ((row.flags & FLAG_PROTECTED) != 0)
                {
                    str += " " + PROTECTED;
                }
                str += "\n";
            }
            str += RTL + Regex.Replace(row.text, "\n", Properties.Settings.Default.NotEllipsis ? "\n" + RTL : " ");
            if (Properties.Settings.Default.IndicateFrom && (row.source != ""))
            {
                str += "\n" + RTL + "  from " + row.source;
            }
            if (Properties.Settings.Default.SmallIcon)
            {
                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 (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, ref float iconWith)
        {
            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;
                    int i = 0;
                    long id = 0;
                    try
                    {
                        if ((idx < 0) || (idx >= table.Rows.Count) || (idx >= listBox.Items.Count))
                        {
                            idx = 0;
                        }
                        IListItem item = listBox.Items[idx] as IListItem;
                        id = item.Id;
                    }
                    catch (SystemException ex)
                    {
                        Debug.WriteLine("listBox_MeasureItem(): listBox.Items[idx] Error. (idx:" + idx + ")\n" +
                            ex.Message + "\n" + "Source: " + ex.Source);
                    }
                    i = idx - 100;
                    if (i < 0)
                    {
                        i = 0;
                    }
                    int cnt = 0;
                    DataSetChattr.TableStatusRow row = table.Rows[i] as DataSetChattr.TableStatusRow;
                    try
                    {
                        cnt = table.Rows.Count;
                        while (i < cnt)
                        {
                            row = table.Rows[i] as DataSetChattr.TableStatusRow;
                            if ((row.RowState != DataRowState.Deleted) && (row.id == id))
                            {
                                break;
                            }
                            i++;
                        }
                    }
                    catch (SystemException ex)
                    {
                        Debug.WriteLine("listBox_MeasureItem(): table.Rows[i] Error. (i:" + i + " / cnt:" + cnt + ")\n" +
                            ex.Message + "\n" + "Source: " + ex.Source);
                    }
                    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;
                    }
                    if ((float?)iconWith != null)
                    {
                        iconWith = rectF.X;
                    }
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("listBox_MeasureItem() Error\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
            return height;
        }

        static private DataSetChattr.TableStatusRow m_LastRow = null;
        static private DataSetChattr.TableStatusRow m_LastSelectedRow = null;
        static private bool m_LastSelected = false;

        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))
                    {
                        //string draw = "  ";
                        bool selected = (listBox.SelectionMode != SelectionMode.None) && ((e.State & DrawItemState.Selected) != 0);
                        int idx = e.Index;
                        DataSetChattr.TableStatusRow row = table.Rows[idx] as DataSetChattr.TableStatusRow;
                        if ((selected != m_LastSelected) || (!selected && !row.Equals(m_LastRow)) || (selected && !row.Equals(m_LastSelectedRow)))
                        {
                            //draw = " D";
                            m_LastSelected = selected;
                            if (selected)
                            {
                                m_LastSelectedRow = row;
                            }
                            else
                            {
                                m_LastRow = row;
                            }
                            // 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.FormatFlags = StringFormatFlags.DirectionRightToLeft;
                            format.Alignment = StringAlignment.Far;
                            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);
                            if ((row.flags & FLAG_RETWEET) != 0)
                            {
                                Font fontRT = new Font(Properties.Settings.Default.FontStatuses, FontStyle.Bold);
                                DrawString(e.Bounds, e.Graphics, "RT", fontRT, 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();
                            }
                        }
                        //string sel = "  ";
                        //if (selected)
                        //{
                        //    sel = " S";
                        //}
                        //Debug.WriteLine("listBox_DrawItem: " + DateTime.Now + draw + sel + " " + row.text);
                    }
                }
                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) && (idx < listBox.Items.Count))
                {
                    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;
                if ((row.flags & FLAG_PROTECTED) == 0)
                {
                    menuStrip.Items[4].Enabled = true;
                    menuStrip.Items[5].Enabled = true;
                    menuStrip.Items[6].Enabled = true;
                }
                else
                {
                    menuStrip.Items[4].Enabled = false;
                    menuStrip.Items[5].Enabled = false;
                    menuStrip.Items[6].Enabled = false;
                }
            }
            else
            {
                menuStrip.Items[3].Enabled = false;
                menuStrip.Items[4].Enabled = false;
                menuStrip.Items[5].Enabled = false;
                menuStrip.Items[6].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;
                }
            }
            // Hash
            LinkedList<string> hashs = parser.Hashs;
            if (hashs.Count > 0)
            {
                int n = 0;
                menuStrip.Items.Add(new ToolStripSeparator());
                contextMenuStrip.Items.Add(new ToolStripSeparator());
                LinkedListNode<string> node = hashs.First;
                while (node != null)
                {
                    item = new ToolStripMenuItem(node.Value);
                    item.ShowShortcutKeys = shortcut;
                    switch (n)
                    {
                        case 0: item.ShortcutKeys = Keys.Control | Keys.H;              break;
                        case 1: item.ShortcutKeys = Keys.Control | Keys.Shift | Keys.H; break;
                        default: item.ShowShortcutKeys = false;                         break;
                    }
                    item.Click += new EventHandler(contextMenuStripStatusesHash_Click);
                    menuStrip.Items.Add(item);
                    contextMenuStrip.Items.Add(new ToolStripMenuItem(item.Text, null, new EventHandler(contextMenuStripStatusesLocation_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 contextMenuStripStatusesHash_Click(object sender, EventArgs e)
        {
            if (sender.GetType() == typeof(ToolStripMenuItem))
            {
                ToolStripMenuItem item = (ToolStripMenuItem)sender;
                Debug.WriteLine("contextMenuStripStatusesHash_Click: " + item.Text);
                Navigate("http://search.twitter.com/search?q=" + item.Text.Replace("#", "%23"));
            }
        }

        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 SetReplyTo(long replyTo, string replyUser)
        {
            m_ReplyTo = replyTo;
            m_ReplyUser = replyUser;
        }

        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();
                            SetReplyTo(row.id, row.user_screen_name);
                            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 ReTweet(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("RT @" + row.user_screen_name + ": " + row.text);
                    }
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("ReTweet() Error\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
        }

        private void ReTweetViaAPI(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))
                    {
                        DataSetChattr.TableStatusRow row = table.Rows[idx] as DataSetChattr.TableStatusRow;
                        long id = row.id;
                        if (id >= 0)
                        {
                            RequestRetweetViaAPI(id);
                        }
                    }
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("ReTweetViaAPI() 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();
            }
        }

        public void PostReTweet(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("RT @" + row.user_screen_name + ": " + 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 int BgWork_Count()
        {
            int count = 0;
            m_MutexBgWork.WaitOne();
            try
            {
                count = m_BgWork.Count;
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("BgWork_Count() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            finally
            {
                m_MutexBgWork.ReleaseMutex();
            }
            return count;
        }

        private void BgWork_AddLast(IBackGround item)
        {
            m_MutexBgWork.WaitOne();
            try
            {
                m_BgWork.AddLast(item);
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("BgWork_Count() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            finally
            {
                m_MutexBgWork.ReleaseMutex();
            }
        }

        private bool ExistRequest(string arg)
        {
            bool exist = false;
            m_MutexBgWork.WaitOne();
            try
            {
                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))
                        {
                            exist = true;
                            break;
                        }
                    }
                    node = node.Next;
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("ExistRequest() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            finally
            {
                m_MutexBgWork.ReleaseMutex();
            }
            return exist;
        }

        private void DeleteRequestBackGround(string arg)
        {
            m_MutexBgWork.WaitOne();
            try
            {
                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))
                        {
                            Debug.WriteLine("DeleteRequestBackGround: delete " + arg);
                            m_BgWork.Remove(node);
                            cnt = m_BgWork.Count;
                            if (cnt <= 0)
                            {
                                Debug.WriteLine("DeleteRequestBackGround: fin");
                                break;
                            }
                            i = 0;
                            node = m_BgWork.First;
                            continue;
                        }
                    }
                    node = node.Next;
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("DeleteRequestBackGround() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            finally
            {
                m_MutexBgWork.ReleaseMutex();
            }
        }

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

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

        private void RunBackGround(MethodInvoker method)
        {
            method();
            IBackGround bg = null;
            m_MutexBgWork.WaitOne();
            try
            {
                if (m_BgWork.Count > 0)
                {
                    if (!backgroundWorker.IsBusy && !m_fBgBusy)
                    {
                        m_fBgBusy = true;
                        bg = m_BgWork.First.Value;
                    }
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("RunBackGround() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            finally
            {
                m_MutexBgWork.ReleaseMutex();
            }
            if (bg != null)
            {
                backgroundWorker.RunWorkerAsync(bg);
            }
        }

        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 DeleteRequestLoad()
        {
            DeleteRequestBackGround(BG_LOAD);
        }

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

        private void DeleteRequestLoading()
        {
            DeleteRequestBackGround(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 RequestRetweetViaAPI(long id)
        {
            string req = BG_RETWEET_VIA_API + " " + id;
            if (!ExistRequest(req))
            {
                RequestBackGround(req);
                Debug.WriteLine("RequestRetweetViaAPI: " + 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 RequestUserStream()
        {
            MethodInvoker userStream = delegate
            {
                String req = BG_USER_STREAM;
                Debug.WriteLine("RecieveStream(" + DateTime.Now + ")");
                RequestBackGround(req);
            };
            Invoke(userStream);
        }

        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;
            try
            {
                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_RETWEET_VIA_API:
                        result = DoBackGround_RetweetViaAPI(v, worker);
                        break;
                    case BG_SET_FLAG:
                        result = DoBackGround_SetFlag(v, worker);
                        break;
                    case BG_USER_STREAM:
                        result = DoBackGround_UserStream(v, worker);
                        break;
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("DoBackGround_String() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            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 static void ThreadUserStream(object arg)
        {
            if (arg.GetType() == typeof(IStreamAPI))
            {
                try
                {
                    IStreamAPI api = arg as IStreamAPI;
                    FormMain main = api.main;
                    HttpWebResponse res = api.res;
                    StreamReader sr = new StreamReader(res.GetResponseStream());
                    TextReader ssr = TextReader.Synchronized(sr);
                    try
                    {
                        for (; ; )
                        {
                            String l = ssr.ReadLine();
                            if (l == null)
                            {
                                break;
                            }
                            else if (l != "")
                            {
                                Debug.WriteLine("Stream: " + l);
                                main.AddUserStream(l);
                            }
                        }
                    }
                    catch (SystemException ex)
                    {
                        Debug.WriteLine("Error ThreadUserStream\n" +
                            ex.Message + "\n" + "Source: " + ex.Source);
                    }
                    main.FinishUserStreamThread();
                }
                catch (SystemException ex)
                {
                    Debug.WriteLine("Error ThreadUserStream\n" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
            }
        }

        public void AddUserStream(String str)
        {
            try
            {
                ArrayList list = ArrayList.Synchronized(m_StreamArray);
                list.Add(str);
                RequestUserStream();
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("Error AddUserStream\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
        }

        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. m_Load = " + m_Load + " / m_Loading = " + m_Loading);
            if ((m_Load == 0) && (m_Loading == 0))
            {
                m_StreamEnable = true;
            }
            worker.ReportProgress((int)ProgressOp.STATUS_BAR, "ロード終了");
            if (dataSetChattr.TableStatus.Rows.Count > 0)
            {
                SetSelectedID(Properties.Settings.Default.SelectedID, -2, 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)
        {
            Debug.WriteLine("DoBackGround_Load: m_Load = " + m_Load + " / m_Loading = " + m_Loading);
            if (m_Loading < m_Load)
            {
                int cnt = dataSetChattr.TableStatus.Rows.Count;
                int idx = m_Loading - 200;
                if (idx >= cnt)
                {
                    idx = cnt - 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)
                {
                    row = dataSetChattr.TableStatus.Rows[idx] as DataSetChattr.TableStatusRow;
                    worker.ReportProgress((int)ProgressOp.LIST_ADD, new IListItem(row.id, idx));
                    m_LastId = row.id;
                    idx++;
                    m_Loading = idx;
                    i++;
                    if (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);
            }
            Debug.WriteLine("DoBackGround_Load: done. m_Load = " + m_Load + " / m_Loading = " + m_Loading);
            if (BgWork_Count() < 2)
            {
                worker.ReportProgress((int)ProgressOp.STATUS_BAR, "");
                Debug.WriteLine("DoBackGround_Load: done.");
            }
            m_StreamEnable = true;
            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)
        {
            Debug.WriteLine("DoBackGround_Load: m_Load = " + m_Load + " / m_Loading = " + m_Loading);
            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.AccessToken, arg.AccessTokenSecret, 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(m_Prefs.AccessToken, m_Prefs.AccessTokenSecret, Option(arg, m_SinceStatuses));
            int count = 0;
            if (m_FirstRetrieve)
            {
                count = Properties.Settings.Default.FirstRetrieve;
            }
            else
            {
                count = Properties.Settings.Default.RetrieveCount;
            }
            if (count > 20)
            {
                string option = igt.Option;
                if (option == "")
                {
                    option = "?";
                }
                else
                {
                    option += "&";
                }
                option += "count=" + count.ToString();
                Debug.WriteLine("DoBackGround_GetFollowingTimeline: " + option);
                igt.Option = option;
            }
            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();
                }
                result = RetrieveStatusesXml(doc, worker, true);
            }
            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 IResultGetFollowing RetrieveStatusesXml(XmlDocument doc, BackgroundWorker worker, Boolean retrieve)
        {
            IResultGetFollowing result = new IResultGetFollowing();
            try
            {
                //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];
                        if (retrieve && m_FirstRetrieve)
                        {
                            m_FirstRetrieve = false;
                        }
                    }
                    //foreach (DateTime at_ret in ret.Date)
                    //{
                    //    Debug.WriteLine("DoBackGround_GetFollowingTimeline: " + at_ret);
                    //}
                }
                if (retrieve && 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 RetrieveStatusXml()" +
                            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("RetrieveStatusXml: tableTinyUrlTableAdapter.Update()");
                        }
                    }
                    catch (SystemException ex)
                    {
                        dataSetChattr.TableTinyUrl.RejectChanges();
                        Debug.WriteLine("tableTinyUrlTableAdapter.Update() Error\n" +
                            "in RetrieveStatusXml()" +
                            ex.Message + "\n" + "Source: " + ex.Source);
                    }
                    finally
                    {
                        m_MutexTinyUrl.ReleaseMutex();
                    }
                }
            }
            catch (SystemException ex)
            {
                dataSetChattr.TableTinyUrl.RejectChanges();
                Debug.WriteLine("RetrieveStatusXml() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            return result;
        }

        private static void ThreadGetUserTimeline(object param)
        {
            if (param.GetType() == typeof(IGetTimeline))
            {
                IGetTimeline arg = param as IGetTimeline;
                HttpWebResponse res = TwitterAPI.GetUserTimeline(arg.AccessToken, arg.AccessTokenSecret, 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(m_Prefs.AccessToken, m_Prefs.AccessTokenSecret, 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.AccessToken, arg.AccessTokenSecret, 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(m_Prefs.AccessToken, m_Prefs.AccessTokenSecret, 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.AccessToken, arg.AccessTokenSecret, 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(m_Prefs.AccessToken, m_Prefs.AccessTokenSecret, 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 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;
        }

        delegate int DelegateItemsCount();
        delegate void DelegateGcCollect();

        private void AddjustTableLimie(BackgroundWorker worker, int limit)
        {
            limit = (limit / 1000) * 1000;
            if (limit > 0)
            {
                try
                {
                    Debug.WriteLine("AddjustTableLimie: " + dataSetChattr.TableStatus.Rows.Count + " / " + listBoxStatuses.Items.Count + "\n" + GC.GetTotalMemory(false));
                    Debug.WriteLine("AddjustTableLimie: m_Load = " + m_Load + " / m_Loading = " + m_Loading);
                    if (dataSetChattr.TableStatus.Rows.Count > limit)
                    {
                        DelegateItemsCount items_count = delegate
                        {
                            return listBoxStatuses.Items.Count;
                        };
                        while ((int)Invoke(items_count) > limit)
                        {
                            worker.ReportProgress((int)ProgressOp.LIST_REMOVE, limit);
                        }
                        while (dataSetChattr.TableStatus.Rows.Count > limit)
                        {
                            dataSetChattr.TableStatus.Rows.RemoveAt(limit);
                        }
                        DataSetChattr.TableStatusRow row = dataSetChattr.TableStatus.Rows[limit - 1] as DataSetChattr.TableStatusRow;
                        m_LastId = row.id;
                        m_LastDate = row.created_at;
                        if (m_Load > limit)
                        {
                            m_Load = limit;
                        }
                        if (m_Loading > m_Load)
                        {
                            m_Loading = m_Load;
                        }
                        m_LoadDone = false;
                        DeleteRequestLoading();
                        DeleteRequestLoad();
                        DelegateGcCollect gc_collect = delegate
                        {
                            GC.Collect(2);
                        };
                        Debug.WriteLine("AddjustTableLimie: GC.Collect() " + GC.GetTotalMemory(false));
                        Invoke(gc_collect);
                        Debug.WriteLine("AddjustTableLimie: done. m_Load = " + m_Load + " / m_Loading = " + m_Loading + "\n" + GC.GetTotalMemory(false));
                    }
                }
                catch (SystemException ex)
                {
                    dataSetChattr.TableProfileImage.RejectChanges();
                    Debug.WriteLine("dataSetChattr.TableStatus.Rows.RemoveAt() Error\n" +
                        "in AddjustTableLimie()" +
                        ex.Message + "\n" + "Source: " + ex.Source);
                }
            }
        }

        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"))
                {
                    Boolean stream = (root.Attributes["stream"] != null);
                    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();
                    int selectedIdx = GetSelectedIndex();
                    int selectedSearchIdx = GetSelectedSearchIndex();
                    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 + "取得しました";
                        }
                        if (!stream)
                        {
                            worker.ReportProgress((int)ProgressOp.STATUS_BAR, statusBar);
                        }
                        //if (add)
                        //{
                        //    m_Log.SetStatusBar(statusBar);
                        //}
                        if (list.Count > 0)
                        {
                            worker.ReportProgress((int)ProgressOp.LIST_BEGIN_UPDATE);
                            try
                            {
                                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);
                                }
                                Debug.WriteLine("RetrieveStatuses() Top: " + topIdx + " / " + topId);
                                Debug.WriteLine("RetrieveStatuses() Sel: " + selectedIdx + " / " + selected);
                                AddjustTableLimie(worker, Properties.Settings.Default.ListLimit);
                                SetSelectedID(selected, selectedIdx, worker);
                                TopIndex(topIdx, topId, worker);
                            }
                            catch (SystemException ex)
                            {
                                Debug.WriteLine("RetrieveStatuses() Error\n" +
                                    ex.Message + "\n" + "Source: " + ex.Source);
                            }
                            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();
                    int selectedIdx = GetSelectedIndex();
                    int selectedSearchIdx = GetSelectedSearchIndex();
                    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, selectedIdx, 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);
            }
            else if (toolStripMenuItemSearchReply.Checked)
            {
                return tableStatusTableAdapter.GetDataBySearchReply(m_Search);
            }
            else if (toolStripMenuItemSearchDM.Checked)
            {
                return tableStatusTableAdapter.GetDataBySearchDM(m_Search);
            }
            return tableStatusTableAdapter.GetDataBySearchAll(m_Search);
        }

        private int? ParseStatus(XmlNode node, ref DateTime at, ref DataSetChattr.TableStatusRow row_new)
        {
            int flag = FLAG_NEW;
            XmlNode orgNode = node;
            XmlNode retweet = node["retweeted_status"];
            if (retweet != null)
            {
                flag |= FLAG_RETWEET;
                node = retweet;
            }
            String str = node["id"].InnerText;
            if ((str == null) || (str == ""))
            {
                return null;
            }
            Int64 id = Int64.Parse(str);
            String created_at = node["created_at"].InnerText;
            if (retweet != null)
            {
                created_at = orgNode["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;
            String user_protected = node["user"]["protected"].InnerText;
            if (user_protected != "false")
            {
                flag |= FLAG_PROTECTED;
            }
            r = new Regex(@"^(.*)\?");
            m = r.Match(profile_image);
            if (m.Success)
            {
                profile_image = m.Groups[1].Value;
            }
            if (retweet != null)
            {
                text += "\n Retweeted by @" + orgNode["user"]["screen_name"].InnerText; ;
            }
            row_new.ItemArray = new Object[] {
                    id,
                    at,
                    text,
                    source,
                    source_url,
                    user_id,
                    user_name,
                    screen_name,
                    location,
                    profile_image,
                    flag
                };
            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 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 int GetSelectedIndex()
        {
            DelegateGetSelectedIdx get = delegate
            {
                return listBoxStatuses.SelectedIndex;
            };
            return (int)Invoke(get);
        }

        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 int GetSelectedSearchIndex()
        {
            if (m_TblSearch != null)
            {
                DelegateGetSelectedIdx get = delegate
                {
                    return listBoxSearch.SelectedIndex;
                };
                return (int)Invoke(get);
            }
            return -1;
        }

        private void SetSelectedID(long select, int selectedIdx, BackgroundWorker worker)
        {
            Debug.WriteLine("SetSelectedID");
            if (select == 0)
            {
                Debug.WriteLine("SetSelectedID: ZERO");
                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)
                    {
                        Debug.WriteLine("SetSelectedID: ID = " + row.id + " / " + i);
                        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)
        {
            Debug.WriteLine("TopIndex");
            if ((top == 0) && Properties.Settings.Default.TopLog && (!Properties.Settings.Default.NotTopLog || !m_MouseHoverStatuses))
            {
                Debug.WriteLine("TopIndex: TOP");
                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++;
                }
                Debug.WriteLine("TopIndex: " + i);
                worker.ReportProgress((int)ProgressOp.LIST_TOP_INDEX, i);
            }
        }

        private void TopIndexSearch(int top, long id, BackgroundWorker worker)
        {
            if ((top == 0) && Properties.Settings.Default.TopLog && (!Properties.Settings.Default.NotTopLog || !m_MouseHoverSearch))
            {
                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_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 RunGetTinyUrl(\'" + 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)
                            {
                                //Debug.WriteLine("RunGetTinyUrl: Request(" + arg.Url + ")");
                                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(m_Prefs.AccessToken, m_Prefs.AccessTokenSecret, 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, "お気に入り登録エラー");
                    }
                }
                else
                {
                    worker.ReportProgress((int)ProgressOp.STATUS_BAR, "お気に入り登録エラー");
                }
            }
            return null;
        }

        private object DoBackGround_RetweetViaAPI(String arg, BackgroundWorker worker)
        {
            long id = long.Parse(arg);
            if (id >= 0)
            {
                worker.ReportProgress((int)ProgressOp.STATUS_BAR, "Retweet中...");
                HttpWebResponse res = TwitterAPI.Retweet(m_Prefs.AccessToken, m_Prefs.AccessTokenSecret, id);
                if (res != null)
                {
                    res.Close();
                    if (res.StatusCode == HttpStatusCode.OK)
                    {
                        worker.ReportProgress((int)ProgressOp.STATUS_BAR, "Retweet完了");
                    }
                    else
                    {
                        Debug.WriteLine("Retweet: " + res.StatusCode);
                        worker.ReportProgress((int)ProgressOp.STATUS_BAR, "Retweeエラー");
                    }
                }
                else
                {
                    worker.ReportProgress((int)ProgressOp.STATUS_BAR, "Retweeエラー");
                }
            }
            return null;
        }

        private static void ThreadUpdate(object param)
        {
            if (param.GetType() == typeof(IUpdate))
            {
                IUpdate arg = param as IUpdate;
                HttpWebResponse res = TwitterAPI.Update(arg.AccessToken, arg.AccessTokenSecret, arg.Status, arg.ReplyTo);
                arg.Response = res;
            }
        }

        private object DoBackGround_Update(String arg, BackgroundWorker worker)
        {
            IResultUpdate result = null;
            String bitlyUser = Properties.Settings.Default.BitlyUser;
            String bitlyKey = m_Prefs.BitlyKey;
            if ((bitlyUser != "") && (bitlyKey != ""))
            {
                StatusParser parser = new StatusParser(arg);
                LinkedList<string> urls = parser.URLs;
                if (urls.Count > 0)
                {
                    worker.ReportProgress((int)ProgressOp.STATUS_BAR, "bit.ly短縮中...");
                    try
                    {
                        LinkedListNode<string> node = urls.First;
                        while (node != null)
                        {
                            string url = node.Value;
                            string bitly = BitlyAPI.CreateShorten(url, bitlyUser, bitlyKey);
                            if (bitly != null)
                            {
                                arg = arg.Replace(url, bitly);
                            }
                            node = node.Next;
                        }
                    }
                    catch (SystemException ex)
                    {
                        Debug.WriteLine("BitlyAPI.CreateShorten() Error\n" +
                            "in DoBackGround_Update(\'" + arg + "\')\n" +
                            ex.Message + "\n" + "Source: " + ex.Source);
                    }
                }
            }
            worker.ReportProgress((int)ProgressOp.STATUS_BAR, "ステータス送信中...");
            IUpdate iu = new IUpdate(m_Prefs.AccessToken, m_Prefs.AccessTokenSecret, arg, m_ReplyTo);
            Thread t = new Thread(ThreadUpdate);
            if (!RunThread(t, worker, iu))
            {
                return null;
            }
            HttpWebResponse res = iu.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 object DoBackGround_UserStream(String arg, BackgroundWorker worker)
        {
            object result = null;
            try
            {
                ArrayList list = ArrayList.Synchronized(m_StreamArray);
                if (toolStripButtonOffline.CheckState == CheckState.Unchecked)
                {
                    while (list.Count > 0)
                    {
                        try
                        {
                            Object obj = list[0];
                            if (obj.GetType() == typeof(String))
                            {
                                String str = obj as String;
                                Debug.WriteLine("DoBackGround_UserStream: " + str);
                                if (Regex.Match(str, "\"friends\":{").Success)
                                {
                                }
                                else if (Regex.Match(str, "\"event\":").Success)
                                {
                                }
                                else if (Regex.Match(str, "\"delete\":{").Success)
                                {
                                    if (Regex.Match(str, "\"delete\":{\"status\":").Success)
                                    {
                                        result = UserStreamDeleteStatus(str, worker);
                                    }
                                }
                                else if (Regex.Match(str, "^{\"direct_message\":").Success)
                                {
                                    result = UserStreamDirectMessage(str, worker);
                                }
                                else if (Regex.Match(str, "\"text\":").Success)
                                {
                                    result = UserStreamTimeline(str, worker);
                                }
                            }
                            list.RemoveAt(0);
                        }
                        catch (SystemException ex)
                        {
                            Debug.WriteLine("DoBackGround_UserStream() Error\n" +
                                ex.Message + "\n" + "Source: " + ex.Source);
                        }
                    }
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("DoBackGround_UserStream() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            return result;
        }

        private IResultGetFollowing UserStreamTimeline(String arg, BackgroundWorker worker)
        {
            IResultGetFollowing result = new IResultGetFollowing();
            try
            {
                XmlDocument xd = new XmlDocument();
                XmlElement root = xd.CreateElement("statuses");
                root.SetAttribute("type", "array");
                root.SetAttribute("stream", "true");
                XmlElement xml = null;
                if (Regex.Match(arg, "\"retweeted_status\":").Success)
                {
                    TwitterJsonReTweet tweet = JsonConvert.DeserializeObject<TwitterJsonReTweet>(arg);
                    xml = UserStreamParseTweet(xd, tweet, "status");
                    xml.AppendChild(UserStreamParseTweet(xd, tweet.retweeted_status, "retweeted_status"));
                }
                else
                {
                    TwitterJsonTweet tweet = JsonConvert.DeserializeObject<TwitterJsonTweet>(arg);
                    xml = UserStreamParseTweet(xd, tweet, "status");
                }
                root.AppendChild(xml);
                xd.AppendChild(root);
                result = RetrieveStatusesXml(xd, worker, false);
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("UserStreamTimeline() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            return result;
        }

        private IResuleGetDirectMessage UserStreamDirectMessage(String arg, BackgroundWorker worker)
        {
            Debug.WriteLine("UserStreamDirectMessage()");
            IResuleGetDirectMessage result = new IResuleGetDirectMessage();
            try
            {
                XmlDocument xd = new XmlDocument();
                XmlElement root = xd.CreateElement("direct-messages");
                root.SetAttribute("type", "array");
                root.SetAttribute("stream", "true");
                XmlElement xml = null;
                TwitterJsonDirectMessage tweet = JsonConvert.DeserializeObject<TwitterJsonDirectMessage>(arg);
                xml = UserStreamParseDM(xd, tweet.direct_message, "direct_message");
                root.AppendChild(xml);
                xd.AppendChild(root);
                IResuleGetDirectMessage ret = RetrieveDirectMessage(xd.DocumentElement, worker, "メッセージ", false);
                if (ret != null)
                {
                    result.Flags = ret.Flags;
                    result.List = ret.List;
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("UserStreamDirectMessage() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            return result;
        }

        delegate long DelegateGetItemId(int row);
        delegate int DelegateGetItemCount();

        private Object UserStreamDeleteStatus(String arg, BackgroundWorker worker)
        {
            Debug.WriteLine("UserStreamDeleteStatus()");
            long id = -1; 
            m_MutexStatus.WaitOne();
            try
            {
                TwitterJsonDeleteStatus delete = JsonConvert.DeserializeObject<TwitterJsonDeleteStatus>(arg);
                id = long.Parse(delete.delete.status.id_str);
                DataSetChattr.TableStatusDataTable table = tableStatusTableAdapter.GetDataByID(id);
                if ((table != null) && (table.Rows.Count > 0))
                {
                    DataSetChattr.TableStatusRow row = table.Rows[0] as DataSetChattr.TableStatusRow;
                    Debug.WriteLine("UserStreamDeleteStatus: " + row.created_at);
                    int n = dataSetChattr.TableStatus.Rows.Count;
                    int y = 0;
                    while (y < n)
                    {
                        row = dataSetChattr.TableStatus.Rows[y] as DataSetChattr.TableStatusRow;
                        if (row.id == id)
                        {
                            dataSetChattr.TableStatus.Rows.RemoveAt(y);
                            break;
                        }
                        y++;
                    }
                    if (y < n)
                    {
                        tableStatusTableAdapter.Delete(row.id, row.created_at, row.text, row.source, row.source_url, row.user_id, row.user_name, row.user_screen_name, row.user_location, row.user_profile_image, row.flags);
                    }
                    if (listBoxSearch.Visible)
                    {
                        n = m_TblSearch.Rows.Count;
                        y = 0;
                        while (y < n)
                        {
                            row = m_TblSearch.Rows[y] as DataSetChattr.TableStatusRow;
                            if (row.id == id)
                            {
                                m_TblSearch.Rows.RemoveAt(y);
                                break;
                            }
                            y++;
                        }
                    }
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("UserStreamDeleteStatus() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            finally
            {
                m_MutexStatus.ReleaseMutex();
            }
            try
            {
                DelegateGetItemId getListStatusItemID = delegate(int idx)
                {
                    IListItem item = listBoxStatuses.Items[idx] as IListItem;
                    return item.Id;
                };
                DelegateGetItemCount getListStatusItemCount = delegate()
                {
                    return listBoxStatuses.Items.Count;
                };
                int n = (int)Invoke(getListStatusItemCount);
                int y = 0;
                int topIdx = GetTopIndex();
                int topIdxSearch = GetTopIndexSearch();
                long topId = 0;
                long topIdSearch = 0;
                long selected = GetSelectedID();
                long selectedSearch = GetSelectedSearchID();
                int selectedIdx = GetSelectedIndex();
                int selectedSearchIdx = GetSelectedSearchIndex();
                worker.ReportProgress((int)ProgressOp.LIST_BEGIN_UPDATE);
                while (y < n)
                {
                    if ((long)Invoke(getListStatusItemID, y) == id)
                    {
                        Debug.WriteLine("UserStreamDeleteStatus: " + y + " / " + id);
                        worker.ReportProgress((int)ProgressOp.LIST_REMOVE, y);
                        break;
                    }
                    y++;
                }
                SetSelectedID(selected, selectedIdx, worker);
                TopIndex(topIdx, topId, worker);
                worker.ReportProgress((int)ProgressOp.LIST_END_UPDATE);
                Debug.WriteLine("UserStreamDeleteStatus: " + y + " / " + n);

                if (listBoxSearch.Visible)
                {
                    DelegateGetItemId getListSearchItemID = delegate(int idx)
                    {
                        IListItem item = listBoxSearch.Items[idx] as IListItem;
                        return item.Id;
                    };
                    DelegateGetItemCount getListSearchItemCount = delegate()
                    {
                        return listBoxSearch.Items.Count;
                    };
                    n = (int)Invoke(getListSearchItemCount);
                    y = 0;
                    worker.ReportProgress((int)ProgressOp.LIST_SEARCH_BEGIN_UPDATE);
                    while (y < n)
                    {
                        if ((long)Invoke(getListSearchItemID, y) == id)
                        {
                            Debug.WriteLine("UserStreamDeleteStatus: " + y + " / " + id);
                            worker.ReportProgress((int)ProgressOp.LIST_SEARCH_REMOVE, y);
                            break;
                        }
                        y++;
                    }
                    SetSelectedID(selectedSearch, selectedSearchIdx, worker);
                    TopIndex(topIdxSearch, topIdSearch, worker);
                    worker.ReportProgress((int)ProgressOp.LIST_SEARCH_END_UPDATE);
                    Debug.WriteLine("UserStreamDeleteStatus: " + y + " / " + n);
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("UserStreamDeleteStatus() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            return null;
        }

        private XmlElement UserStreamParseTweet(XmlDocument xd, TwitterJsonTweet tweet, String name)
        {
            XmlElement root = xd.CreateElement(name);
            try
            {
                root.AppendChild(UserStreamXmlTweet(xd, "id", tweet.id_str));
                root.AppendChild(UserStreamXmlTweet(xd, "created_at", tweet.created_at));
                root.AppendChild(UserStreamXmlTweet(xd, "text", tweet.text));
                root.AppendChild(UserStreamXmlTweet(xd, "source", tweet.source));
                XmlElement user = xd.CreateElement("user");
                user.AppendChild(UserStreamXmlTweet(xd, "id", tweet.user.id_str));
                user.AppendChild(UserStreamXmlTweet(xd, "name", tweet.user.name));
                user.AppendChild(UserStreamXmlTweet(xd, "screen_name", tweet.user.screen_name));
                user.AppendChild(UserStreamXmlTweet(xd, "location", tweet.user.location));
                user.AppendChild(UserStreamXmlTweet(xd, "profile_image_url", tweet.user.profile_image_url));
                user.AppendChild(UserStreamXmlBool(xd, "protected", tweet.user.Protected));
                root.AppendChild(user);
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("UserStreamParseTweet() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            return root;
        }

        private XmlElement UserStreamParseDM(XmlDocument xd, TwitterJsonDM tweet, String name)
        {
            XmlElement root = xd.CreateElement(name);
            try
            {
                root.AppendChild(UserStreamXmlTweet(xd, "id", tweet.id_str));
                root.AppendChild(UserStreamXmlTweet(xd, "created_at", tweet.created_at));
                root.AppendChild(UserStreamXmlTweet(xd, "text", tweet.text));
                XmlElement sender = xd.CreateElement("sender");
                sender.AppendChild(UserStreamXmlTweet(xd, "id", tweet.sender.id_str));
                sender.AppendChild(UserStreamXmlTweet(xd, "name", tweet.sender.name));
                sender.AppendChild(UserStreamXmlTweet(xd, "screen_name", tweet.sender.screen_name));
                sender.AppendChild(UserStreamXmlTweet(xd, "location", tweet.sender.location));
                sender.AppendChild(UserStreamXmlTweet(xd, "profile_image_url", tweet.sender.profile_image_url));
                sender.AppendChild(UserStreamXmlBool(xd, "protected", tweet.sender.Protected));
                root.AppendChild(sender);
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("UserStreamParseDM() Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
            return root;
        }

        private XmlElement UserStreamXmlTweet(XmlDocument xd, String name, String text)
        {
            XmlElement x = xd.CreateElement(name);
            x.InnerText = text;
            return x;
        }

        private XmlElement UserStreamXmlBool(XmlDocument xd, String name, Boolean flag)
        {
            XmlElement x = xd.CreateElement(name);
            if (flag)
            {
                x.InnerText = "true";
            }
            else
            {
                x.InnerText = "false";
            }
            return x;
        }

        public void FinishUserStreamThread()
        {
            m_StreamThread = null;
        }

        private bool CheckUserStreamThread()
        {
            bool result = true;
            switch (m_StreamThread.ThreadState)
            {
                case System.Threading.ThreadState.AbortRequested:
                    result = true;
                    break;
                case System.Threading.ThreadState.Aborted:
                    result = true;
                    break;
                case System.Threading.ThreadState.Background:
                    result = false;
                    break;
                case System.Threading.ThreadState.Running:
                    result = false;
                    break;
                case System.Threading.ThreadState.Stopped:
                    result = true;
                    break;
                case System.Threading.ThreadState.StopRequested:
                    result = true;
                    break;
                case System.Threading.ThreadState.Suspended:
                    result = true;
                    break;
                case System.Threading.ThreadState.SuspendRequested:
                    result = true;
                    break;
                case System.Threading.ThreadState.Unstarted:
                    result = true;
                    break;
                case System.Threading.ThreadState.WaitSleepJoin:
                    result = true;
                    break;
                default:
                    result = true;
                    break;
            }
            return result;
        }

        private void StartUserStreamThread()
        {
            try
            {
                if (Properties.Settings.Default.UseStreamAPI)
                {
                    if (m_StreamEnable && (m_StreamThread == null))
                    {
                        Debug.WriteLine("StartUserStreamThread: start");
                        m_Stream = TwitterAPI.UserStream(m_Prefs.AccessToken, m_Prefs.AccessTokenSecret);
                        if (m_Stream != null)
                        {
                            IStreamAPI api = new IStreamAPI();
                            api.main = this;
                            api.bgWoker = backgroundWorker;
                            api.res = m_Stream;
                            m_StreamThread = new Thread(ThreadUserStream);
                            m_StreamThread.Priority = ThreadPriority.Lowest;
                            m_StreamThread.Start(api);
                        }
                    }
                }
                else if (m_StreamThread != null)
                {
                    Debug.WriteLine("StartUserStreamThread: stop");
                    StopUserStreamThread();
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("StartUserStreamThread Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
        }

        private void StopUserStreamThread()
        {
            Debug.WriteLine("StopUserStreamThread");
            try
            {
                if (m_Stream != null)
                {
                    m_Stream.Close();
                    m_Stream = null;
                }
                if (m_StreamThread != null)
                {
                    m_StreamThread.Interrupt();
                    m_StreamThread.Abort();
                    m_StreamThread = null;
                }
            }
            catch (SystemException ex)
            {
                Debug.WriteLine("StopUserStreamThread Error\n" +
                    ex.Message + "\n" + "Source: " + ex.Source);
            }
        }

        private void CheckUserStream()
        {
            ArrayList list = ArrayList.Synchronized(m_StreamArray);
            if (list.Count > 0)
            {
                //RequestUserStream();
            }
        }

        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)
            {
                foreach (IPopup popup in result.List)
                {
                    bool flash = false;
                    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)
                {
                    foreach (IPopup popup in result.List)
                    {
                        if (!Properties.Settings.Default.NoMyPost || (popup.User != Properties.Settings.Default.UserName))
                        {
                            switch (Properties.Settings.Default.NotifyTaskbarKind)
                            {
                                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 = ((result.Flags & (FLAG_NEW | FLAG_DM)) == (FLAG_NEW | FLAG_DM));
                }
                if (flash && (ActiveForm != this))
                {
                    FlashWindow(this.Handle, true);
                }
            }
        }

        private void Quit()
        {
            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);
            }
            StopUserStreamThread();
            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;
        }
    }
}
