using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace ComentEditorSample
{
    using WebServiceClient.Forms;
    using WebServiceClient.NicoVideo;

    public partial class Form1 : Form
    {
        private const string WindowTitle = "API コメント編集機能の紹介 ";
        private string _commentFile;
        private NicoThread _thread;
        private bool _isEdit;
        private int _sortColumn = -1;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (_isEdit == true && e.CloseReason == CloseReason.UserClosing)
            {
                DialogResult result = MessageBox.Show(this, "コメントが変更されています。保存しますか？", "終了", MessageBoxButtons.YesNoCancel);
                switch (result)
                {
                case DialogResult.Yes:
                    string header = string.Format("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- BoonSutazioData={0} -->\n", _thread.VideoId);
                    _thread.SaveThreadXml(NicoThreadType.Default, _commentFile, new UTF8Encoding(false), header, "");
                    break;

                case DialogResult.No:
                    break;

                case DialogResult.Cancel:
                    e.Cancel = true;
                    break;
                }
            }
        }

        private void NewFileButton_Click(object sender, EventArgs e)
        {
            if (_isEdit == true)
            {
                if (MessageBox.Show(this, "コメントが変更されています。\n変更が失われますがよろしいですか？", "", MessageBoxButtons.OKCancel) == DialogResult.Cancel)
                {
                    return;
                }
            }

            _commentFile = null;
            _isEdit = false;
            this.Text = WindowTitle;
            MergeButton.Enabled = false;
            SaveFileButton.Enabled = false;
            toolStripStatus.Text = "";
            toolStripFileName.Text = "";

            listViewNormal.Items.Clear();
            listViewFork.Items.Clear();
            listViewOptional.Items.Clear();
            listViewNicos.Items.Clear();
        }

        private void FileOpenButton_Click(object sender, EventArgs e)
        {
            if (_isEdit == true)
            {
                if (MessageBox.Show(this, "コメントが変更されています。\n変更が失われますがよろしいですか？", "", MessageBoxButtons.OKCancel) == DialogResult.Cancel)
                {
                    return;
                }
            }

            OpenFileDialog openFile = new OpenFileDialog();
            openFile.InitialDirectory = Directory.GetCurrentDirectory();
            openFile.Filter = "コメントファイル(*.xml)|*.xml|すべてのファイル(*.*)|*.*";
            openFile.FilterIndex = 1;
            openFile.Title = "コメントファイルを選択してください";
            openFile.Multiselect = false;

            if (openFile.ShowDialog() == DialogResult.OK)
            {
                LoadCommentFile(openFile.FileName);
                toolStripStatus.Text = string.Format("一般 {0:N0}  投稿者 {1:N0}  コミュ＆チャンネル {2:N0}  ニコスクリプト {3:N0}", _thread.CommentCount, _thread.ForkCount, _thread.OptionalCount, _thread.NicoScriptCount);
                toolStripFileName.Text = _commentFile;
            }
        }

        private void MergeButton_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFile = new OpenFileDialog();
            openFile.InitialDirectory = Directory.GetCurrentDirectory();
            openFile.Filter = "コメントファイル(*.xml)|*.xml|すべてのファイル(*.*)|*.*";
            openFile.FilterIndex = 1;
            openFile.Title = "マージするコメントファイルを選択してください";
            openFile.Multiselect = true;

            if (openFile.ShowDialog() == DialogResult.OK)
            {
                MergeCommentFile(openFile.FileNames);
                toolStripStatus.Text = string.Format("一般 {0:N0}  投稿者 {1:N0}  コミュ＆チャンネル {2:N0}  ニコスクリプト {3:N0}", _thread.CommentCount, _thread.ForkCount, _thread.OptionalCount, _thread.NicoScriptCount);
            }
        }

        private void SaveFileButton_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFile = new SaveFileDialog();
            saveFile.InitialDirectory = Path.GetDirectoryName(_commentFile);
            saveFile.FileName = Path.GetFileName(_commentFile);
            saveFile.Filter = "コメントファイル(*.xml)|*.xml|すべてのファイル(*.*)|*.*";
            saveFile.FilterIndex = 1;
            saveFile.Title = "名前を付けて保存";

            if (saveFile.ShowDialog() == DialogResult.OK)
            {
                string header = string.Format("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- BoonSutazioData={0} -->\n", _thread.VideoId);
                _thread.SaveThreadXml(NicoThreadType.Default, saveFile.FileName, new UTF8Encoding(false), header, "");
                _isEdit = false;
                this.Text = WindowTitle;
            }
        }

        private void listViewNormal_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                CommentDelete(listViewNormal, _thread.CommentThread.Comments);
            }
        }

        private void listViewFork_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                CommentDelete(listViewFork, _thread.ForkThread.Comments);
            }
        }

        private void listViewOptional_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                CommentDelete(listViewOptional, _thread.OptionalThread.Comments);
            }
        }

        private void listViewNicos_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                CommentDelete(listViewNicos, _thread.ScriptThread.Comments);
            }
        }

        private void CommentDelete(ListView listView, NicoCommentEntries comments)
        {
            if (listView.SelectedItems.Count > 0)
            {
                _isEdit = true;
                this.Text = WindowTitle + "*";

                listView.BeginUpdate();
                foreach (ListViewItem item in listView.SelectedItems)
                {
                    comments.Remove(int.Parse(item.Text));
                    listView.Items.Remove(item);
                }
                listView.EndUpdate();
            }
        }

        private void listViewNormal_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            ListViewItemSort(listViewNormal, e);
        }

        private void listViewFork_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            ListViewItemSort(listViewFork, e);
        }

        private void listViewOptional_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            ListViewItemSort(listViewOptional, e);
        }

        private void listViewNicos_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            ListViewItemSort(listViewNicos, e);
        }

        private void ListViewItemSort(ListView listView, ColumnClickEventArgs e)
        {
            listView.ListViewItemSorter = null;
            switch (e.Column)
            {
            case 0:
                listView.ListViewItemSorter = new ListViewItemAsInt(e.Column, (_sortColumn == e.Column) ? SortOrder.Descending : SortOrder.Ascending);
                break;
            case 1:
                listView.ListViewItemSorter = new ListViewItemAsDateTime(e.Column, (_sortColumn == e.Column) ? SortOrder.Descending : SortOrder.Ascending);
                break;
            case 2:
                listView.ListViewItemSorter = new ListViewItemAsString(e.Column, (_sortColumn == e.Column) ? SortOrder.Descending : SortOrder.Ascending);
                break;
            case 3:
                listView.ListViewItemSorter = new ListViewItemAsString(e.Column, (_sortColumn == e.Column) ? SortOrder.Descending : SortOrder.Ascending);
                break;
            case 4:
                listView.ListViewItemSorter = new ListViewItemAsDateTime(e.Column, (_sortColumn == e.Column) ? SortOrder.Descending : SortOrder.Ascending);
                break;
            case 5:
                listView.ListViewItemSorter = new ListViewItemAsString(e.Column, (_sortColumn == e.Column) ? SortOrder.Descending : SortOrder.Ascending);
                break;
            }
            _sortColumn = (_sortColumn == e.Column) ? -1 : e.Column;
        }

        private void listViewNormal_DragEnter(object sender, DragEventArgs e)
        {
            CommentFileDragEnter(e);
        }

        private void listViewFork_DragEnter(object sender, DragEventArgs e)
        {
            CommentFileDragEnter(e);
        }

        private void listViewOptional_DragEnter(object sender, DragEventArgs e)
        {
            CommentFileDragEnter(e);
        }

        private void listViewNicos_DragEnter(object sender, DragEventArgs e)
        {
            CommentFileDragEnter(e);
        }

        private void CommentFileDragEnter(DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
                if (_commentFile == null && files.Length > 1)
                {
                    e.Effect = DragDropEffects.None;
                    return;
                }

                foreach (string fileName in files)
                {
                    if (fileName.EndsWith(".xml", true, null) == false)
                    {
                        e.Effect = DragDropEffects.None;
                        return;
                    }
                }

                e.Effect = DragDropEffects.All;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void listViewNormal_DragDrop(object sender, DragEventArgs e)
        {
            CommentFileDrop(listViewNormal, e);
        }

        private void listViewFork_DragDrop(object sender, DragEventArgs e)
        {
            CommentFileDrop(listViewFork, e);
        }

        private void listViewOptional_DragDrop(object sender, DragEventArgs e)
        {
            CommentFileDrop(listViewOptional, e);
        }

        private void listViewNicos_DragDrop(object sender, DragEventArgs e)
        {
            CommentFileDrop(listViewNicos, e);
        }

        /// <summary>リストビューにドロップしたコメントファイルを読み込みます。</summary>
        private void CommentFileDrop(ListView listView, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
                if (_commentFile == null)
                {
                    if (files[0].EndsWith(".xml", true, null) == true)
                    {
                        LoadCommentFile(files[0]);
                    }
                }
                else
                {
                    DialogResult result = MessageBox.Show(this, "現在のコメントファイルに以下のファイルをマージしますか？\n" + string.Join("\n", files), "コメントのマージ", MessageBoxButtons.YesNoCancel);
                    switch (result)
                    {
                    case DialogResult.Yes:
                        MergeCommentFile(files);
                        break;

                    case DialogResult.No:
                        if (files[0].EndsWith(".xml", true, null) == true)
                        {
                            LoadCommentFile(files[0]);
                        }
                        break;

                    case DialogResult.Cancel:
                        break;
                    }
                }

                toolStripStatus.Text = string.Format("一般 {0:N0}  投稿者 {1:N0}  コミュ＆チャンネル {2:N0}  ニコスクリプト {3:N0}", _thread.CommentCount, _thread.ForkCount, _thread.OptionalCount, _thread.NicoScriptCount);
                toolStripFileName.Text = _commentFile;
            }
        }

        /// <summary>指定のコメントファイルをリストビューに追加します。</summary>
        private void LoadCommentFile(string path)
        {
            _commentFile = path;
            _thread = new NicoThread(path, new UTF8Encoding(false));
            _isEdit = false;
            this.Text = WindowTitle;

            MergeButton.Enabled = true;
            SaveFileButton.Enabled = true;

            // 一般コメント
            SetThread(listViewNormal, _thread.CommentThread.Comments);
            // 投稿者コメント
            SetThread(listViewFork, _thread.ForkThread.Comments);
            // チャンネル＆コミュニティコメント
            SetThread(listViewOptional, _thread.OptionalThread.Comments);
            // ニコスクリプト
            SetThread(listViewNicos, _thread.ScriptThread.Comments);
        }

        /// <summary>指定のコメントファイルをリストビューに追加します。</summary>
        private void MergeCommentFile(string[] files)
        {
            bool isMerge = false;
            foreach (string fileName in files)
            {
                if (fileName.EndsWith(".xml", true, null) == true)
                {
                    _thread.Merge(new NicoThread(fileName, new UTF8Encoding(false)));
                    isMerge = true;
                }
            }

            if (isMerge == true)
            {
                _isEdit = true;
                this.Text = WindowTitle + "*";

                // 一般コメント
                SetThread(listViewNormal, _thread.CommentThread.Comments);
                // 投稿者コメント
                SetThread(listViewFork, _thread.ForkThread.Comments);
                // チャンネル＆コミュニティコメント
                SetThread(listViewOptional, _thread.OptionalThread.Comments);
                // ニコスクリプト
                SetThread(listViewNicos, _thread.ScriptThread.Comments);
            }
        }

        /// <summary>指定のコメントをリストビューに追加します。</summary>
        private void SetThread(ListView listView, NicoCommentEntries thread)
        {
            listView.BeginUpdate();
            listView.Items.Clear();

            listView.ListViewItemSorter = null;
            _sortColumn = -1;

            foreach (KeyValuePair<int, NicoCommentEntry> pair in thread)
            {
                NicoCommentEntry entry = pair.Value;
                ListViewItem item = new ListViewItem(new string[] {
                    entry.No.ToString(),
                    string.Format("{0:D2}:{1:D2}", entry.Position / 60000, entry.Position % 60000 / 1000),
                    entry.Command,
                    entry.Comment,
                    entry.Date.ToString("MM/dd HH:mm"),
                    entry.UserId
                });
                listView.Items.Add(item);
            }

            listView.EndUpdate();
        }
    }
}