/*
 * Property.cs
 * Copyright (c) 2007-2009 kbinani
 *
 * This file is part of LipSync.
 *
 * LipSync is free software; you can redistribute it and/or
 * modify it under the terms of the BSD License.
 *
 * LipSync is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

using Boare.Lib.AppUtil;

namespace LipSync {

    public delegate void TelopAddingEventHandler();
    public delegate void TelopDeletingEventHandler( ZorderItem e );
    public delegate void EditingItemChangedEventHandler( ZorderItem e );
    public delegate void ListUpdateRequiredEventHandler();

    public partial class Property : UserControl {
        private ZorderItem m_editing = null;
        FormObjectList m_form_objectlist;
        int m_last_splitter_distance = 126;
        bool[] m_sort_ascend = new bool[] { true, true, true };     // start, type, abstの各項目が昇順で並べ替えられているかどうかを表す
        int[] m_sort_order = new int[] { 0, 1, 2 };                 // start, type, abstの列のデータが，項目を並べ替える際に順番の判定に使用される順位．
        private static Property m_instance = null;

        /// <summary>
        /// プロパティ・ビューの値が変更されたときに発生します
        /// </summary>
        public event PropertyValueChangedEventHandler PropertyValueChanged;
        /// <summary>
        /// テロップの追加が要求されたときに発生します
        /// </summary>
        public event TelopAddingEventHandler TelopAdding;
        /// <summary>
        /// テロップの削除が要求されたときに発生します
        /// </summary>
        public event TelopDeletingEventHandler TelopDeleting;
        /// <summary>
        /// オブジェクトリストで選択アイテムが変更されたとき発生します
        /// </summary>
        public event EventHandler SelectedIndexChanged;
        public event EditingItemChangedEventHandler EditingItemChanged;
        /// <summary>
        /// オブジェクトリストの更新が必要となったとき発生します
        /// </summary>
        public event ListUpdateRequiredEventHandler ListUpdateRequired;

        public void UpdateLayout() {
            // panel1
            titleUpper.Left = 0;
            titleUpper.Top = 0;
            titleUpper.Width = sContainer.Panel1.Width;
            panelListView.Left = 0;
            panelListView.Top = titleUpper.Height;
            panelListView.Width = sContainer.Panel1.Width;
            panelListView.Height = sContainer.Panel1.Height - titleUpper.Height;

            // panel2
            titleLower.Left = 0;
            titleLower.Top = 0;
            titleLower.Width = sContainer.Panel2.Width;
            panel1.Left = 0;
            panel1.Top = titleLower.Height;
            panel1.Width = sContainer.Panel2.Width;
            panel1.Height = sContainer.Panel2.Height - titleLower.Height;
        }

        public void ApplyLanguage() {
            menuAddTelop.Text = _( "Add Telop" ) + "(&A)";
            menuDeleteTelop.Text = _( "Delte Delop" ) + "(&D)";
            m_form_objectlist.ApplyLanguage();
        }

        public static string _( string s ) {
            return Messaging.GetMessage( s );
        }

        public static Property Instance {
            get {
                return m_instance;
            }
        }

        public void Sort() {
            if ( listView.Items.Count < 2 ) {
                return;
            }
            bool changed = true;
            List<ListViewItem> sorting = new List<ListViewItem>();
            for ( int i = 0; i < listView.Items.Count; i++ ) {
                sorting.Add( listView.Items[i] );
            }
            while ( changed ) {
                changed = false;
                for ( int i = 0; i < sorting.Count - 1; i++ ) {
                    if ( Compare( sorting[i], sorting[i + 1] ) > 0 ) {
                        ListViewItem cp = (ListViewItem)sorting[i].Clone();
                        sorting[i] = (ListViewItem)sorting[i + 1].Clone();
                        sorting[i + 1] = cp;
                        changed = true;
                    }
                }
            }
            listView.Items.Clear();
            listView.Items.AddRange( sorting.ToArray() );
        }

        /// <summary>
        /// 第index1項目が第index2項目より順位が低いときtrue，そうでないときfalse
        /// </summary>
        /// <param name="index1"></param>
        /// <param name="index2"></param>
        /// <returns></returns>
        public int Compare( ListViewItem item1, ListViewItem item2 ) {
            int[] order = new int[3];
            order[0] = CompareWithStart( item1, item2 );
            order[1] = CompareWithType( item1, item2 );
            order[2] = CompareWithAbst( item1, item2 );
            if ( order[m_sort_order[0]] == 0 ) {
                if ( order[m_sort_order[1]] == 0 ) {
                    return order[m_sort_order[2]];
                } else {
                    return order[m_sort_order[1]];
                }
            } else {
                return order[m_sort_order[0]];
            }
        }

        private int CompareWithAbst( ListViewItem item1, ListViewItem item2 ) {
            string t1 = item1.SubItems[2].Text;
            string t2 = item2.SubItems[2].Text;
            int res = t1.CompareTo( t2 );
            if ( !m_sort_ascend[2] ) {
                res = -1 * res;
            }
            return res;
        }

        private int CompareWithType( ListViewItem item1, ListViewItem item2 ) {
            if ( !(item1.Tag is ZorderItem) || !(item2.Tag is ZorderItem) ) {
                return 0;
            }
            ZorderItem zitem1 = (ZorderItem)item1.Tag;
            ZorderItem zitem2 = (ZorderItem)item2.Tag;
            ZorderItemType t1 = zitem1.Type;
            ZorderItemType t2 = zitem2.Type;
            int res = t1.CompareTo( t2 );
            if ( !m_sort_ascend[1] ) {
                res = -1 * res;
            }
            return res;
        }

        private int CompareWithStart( ListViewItem item1, ListViewItem item2 ) {
            float titem1 = ((ZorderItem)item1.Tag).Start;
            float titem2 = ((ZorderItem)item2.Tag).Start;
            int res = 0;
            if ( titem1 > titem2 ) {
                res = 1;
            } else if ( titem1 < titem2 ) {
                res = -1;
            } else {
                res = 0;
            }
            if ( !m_sort_ascend[0] ) {
                res = -1 * res;
            }
            return res;
        }

        public ZorderItem this[int index] {
            get {
                return (ZorderItem)listView.Items[index].Tag;
            }
        }

        public int Count {
            get {
                return listView.Items.Count;
            }
        }

        public int SelectedIndex {
            get {
                if ( listView.SelectedItems.Count > 0 ) {
                    foreach ( ListViewItem item in listView.SelectedItems ) {
                        return item.Index;
                    }
                }
                return -1;
            }
            set {
                for ( int i = 0; i < listView.Items.Count; i++ ) {
                    if ( i == value ) {
                        listView.Items[i].Selected = true;
                    } else {
                        listView.Items[i].Selected = false;
                    }
                }
            }
        }

        public ZorderItem SelectedItem {
            get {
                int index = SelectedIndex;
                if ( index < 0 || listView.Items.Count <= index ) {
                    return null;
                } else {
                    return (ZorderItem)listView.Items[index].Tag;
                }
            }
        }

        public ListView ListView {
            get {
                return listView;
            }
        }

        public ZorderItem Editing {
            get {
                return m_editing;
            }
            set {
                m_editing = value;
                if ( this.EditingItemChanged != null ) {
                    this.EditingItemChanged( m_editing );
                }
            }
        }

        public object SelectedObject {
            get {
                return PropertyGrid.SelectedObject;
            }
            set {
                PropertyGrid.SelectedObject = value;
            }
        }

        public Property() {
            InitializeComponent();
            m_form_objectlist = new FormObjectList();
            m_form_objectlist.FormClosing += new FormClosingEventHandler( m_form_objectlist_FormClosing );
            m_instance = this;
        }

        void m_form_objectlist_FormClosing( object sender, FormClosingEventArgs e ) {
            listView.Parent = panelListView;
            listView.Dock = DockStyle.Fill;
            sContainer.SplitterDistance = m_last_splitter_distance;
            sContainer.IsSplitterFixed = false;
        }

        private void PropertyGrid_Click( object sender, EventArgs e ) {
            this.sContainer.Panel2.Focus();
        }

        private void splitContainer1_Panel2_Enter( object sender, EventArgs e ) {
            this.titleLower.BackColor = SystemColors.ActiveCaption;
            this.titleLower.ForeColor = SystemColors.ActiveCaptionText;
        }

        private void splitContainer1_Panel2_Leave( object sender, EventArgs e ) {
            this.titleLower.BackColor = SystemColors.InactiveCaption;
            this.titleLower.ForeColor = SystemColors.InactiveCaptionText;
        }

        private void splitContainer1_Panel1_Leave( object sender, EventArgs e ) {
            this.titleUpper.BackColor = SystemColors.InactiveCaption;
            this.titleUpper.ForeColor = SystemColors.InactiveCaptionText;
        }

        private void splitContainer1_Panel1_Enter( object sender, EventArgs e ) {
            this.titleUpper.BackColor = SystemColors.ActiveCaption;
            this.titleUpper.ForeColor = SystemColors.ActiveCaptionText;
        }

        private void titleUpper_MouseDown( object sender, MouseEventArgs e ) {
            this.sContainer.Panel1.Focus();
        }

        private void titleLower_MouseDown( object sender, MouseEventArgs e ) {
            this.sContainer.Panel2.Focus();
        }

        private void ListView_Enter( object sender, EventArgs e ) {
            this.titleUpper.BackColor = SystemColors.ActiveCaption;
            this.titleUpper.ForeColor = SystemColors.ActiveCaptionText;
        }

        private void PropertyGrid_PropertyValueChanged( object s, PropertyValueChangedEventArgs e ) {
            if ( this.PropertyValueChanged != null ) {
                this.PropertyValueChanged( s, e );
            }
            if ( ListUpdateRequired != null ) {
                ListUpdateRequired();
            }
        }

        private void menuAddTelop_Click( object sender, EventArgs e ) {
            if ( this.TelopAdding != null ) {
                this.TelopAdding();
            }
            if ( ListUpdateRequired != null ) {
                ListUpdateRequired();
            }
        }

        private void menuDeleteTelop_Click( object sender, EventArgs e ) {
            if ( this.SelectedIndex < 0 ) {
                return;
            }
            if ( this.TelopDeleting != null ) {
                this.TelopDeleting( this.SelectedItem );
            }
            if ( ListUpdateRequired != null ) {
                ListUpdateRequired();
            }
        }

        public ZorderItem Selected {
            get {
                return m_editing;
            }
        }

        void listView_SelectedIndexChanged( object sender, EventArgs e ) {
            if ( listView.SelectedItems.Count > 0 && this.EditingItemChanged != null ) {
                ZorderItem zi = (ZorderItem)listView.SelectedItems[0].Tag;
                Editing = zi;
            }
        }

        private void TreeView_MouseDown( object sender, MouseEventArgs e ) {
            if ( this.PropertyValueChanged != null ) {
                this.PropertyValueChanged( sender, null );
            }
        }

        private void titleUpper_DoubleClick( object sender, EventArgs e ) {
            m_form_objectlist.Show( listView );
            m_last_splitter_distance = sContainer.SplitterDistance;
            sContainer.SplitterDistance = 0;
            sContainer.IsSplitterFixed = true;
        }

        private void listView_ColumnClick( object sender, ColumnClickEventArgs e ) {
            int column = e.Column;
            if ( m_sort_order[0] == column ) {
                m_sort_ascend[column] = !m_sort_ascend[column];
                List<ListViewItem> coll = new List<ListViewItem>();
                for ( int i = listView.Items.Count - 1; i >= 0; i-- ) {
                    coll.Add( listView.Items[i] );
                }
                listView.Items.Clear();
                listView.Items.AddRange( coll.ToArray() );
                this.Sort();
            } else {
                List<int> list = new List<int>();
                for ( int i = 0; i < 3; i++ ) {
                    if ( m_sort_order[i] != column ) {
                        list.Add( m_sort_order[i] );
                    }
                }
                m_sort_order[0] = column;
                m_sort_order[1] = list[0];
                m_sort_order[2] = list[1];
                this.Sort();
            }
        }

        private void Property_FontChanged( object sender, EventArgs e ) {
            cmenu.Font = this.Font;
        }
    }

}
