// Chattr - Twitter client on .NET
//
// Copyright (c) 2007 Katsuhiko Ichinose <ichi@users.sourceforge.jp>
//
// Chattr is Free Software released under GNU General Public License.
//
// $Id: FormPopup.cs 19 2007-10-14 09:14:36Z ichi $

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

using System.Diagnostics;
using System.Collections;

namespace Chattr
{
    public partial class FormPopup : Form
    {
        private enum State
        {
            IDLE,
            FADE_IN,
            DISPLAY,
            FADE_OUT
        }
        private const double FADE_IN = 500;
        private const double FADE_OUT = 1000;

        private State m_State = State.IDLE;
        private DateTime m_Time;
        private LinkedList<IPopup> m_List = new LinkedList<IPopup>();

        public FormPopup()
        {
            InitializeComponent();
            m_State = State.IDLE;
            this.Opacity = 0;
            this.Show();
        }

        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
        }

        public void Add(string user, string text)
        {
            m_List.AddLast(new IPopup(0, user, text));
            AddItem();
        }

        private void AddItem()
        {
            if (m_List.Count > 0)
            {
                int cnt = listBoxStatuses.Items.Count;
                listBoxStatuses.BeginUpdate();
                while (m_List.Count > 0)
                {
                    IPopup popup = m_List.First.Value;
                    listBoxStatuses.Items.Add(popup);
                    ChangeLocation();
                    if (this.Location.Y >= 0)
                    {
                        m_List.RemoveFirst();
                    }
                    else
                    {
                        listBoxStatuses.Items.RemoveAt(listBoxStatuses.Items.Count - 1);
                        ChangeLocation();
                        break;
                    }
                }
                listBoxStatuses.EndUpdate();
                if (cnt == 0)
                {
                    FadeIn();
                }
                else
                {
                    Display(listBoxStatuses.Items.Count - cnt);
                }
                Debug.WriteLine("AddItem: " + this.Location + " / " + this.Height);
            }
        }

        private int MeasureHeight()
        {
            int height = 0;
            for (int i = 0; i < listBoxStatuses.Items.Count; i++)
            {
                height += listBoxStatuses.GetItemHeight(i);
            }
            return height;
        }

        private void ChangeLocation()
        {
            int height = MeasureHeight();
            Rectangle rect = Screen.PrimaryScreen.Bounds;
            int workHeight = Screen.GetWorkingArea(new Point(0, 0)).Height;
            this.Height = height + 8;
            this.Location = new Point(rect.Width - this.Width - 2, workHeight - this.Height - 2);
        }

        private void Idle()
        {
            m_State = State.IDLE;
            this.Opacity = 0;
            timer.Enabled = false;
            listBoxStatuses.Items.Clear();
            AddItem();
        }

        private void FadeIn()
        {
            m_State = State.FADE_IN;
            m_Time = DateTime.Now;
            timer.Interval = 100;
            timer.Enabled = true;
        }

        private void FadeOut()
        {
            m_State = State.FADE_OUT;
            m_Time = DateTime.Now;
            timer.Enabled = false;
            timer.Interval = 100;
            timer.Enabled = true;
        }

        private void Display(int count)
        {
            m_State = State.DISPLAY;
            this.Opacity = 1;
            timer.Enabled = false;
            timer.Interval = 3000 + (1000 * (count - 1));
            timer.Enabled = true;
        }

        private void ReDisplay()
        {
            m_State = State.DISPLAY;
            this.Opacity = 1;
            timer.Enabled = false;
            timer.Interval = 500;
            timer.Enabled = true;
        }

        private void FormPopup_Load(object sender, EventArgs e)
        {
            Rectangle rect = Screen.PrimaryScreen.Bounds;
            int workHeight = Screen.GetWorkingArea(new Point(0, 0)).Height;
            this.Location = new Point(rect.Width - this.Width, workHeight - this.Height);
        }

        private void listBoxStatuses_MeasureItem(object sender, MeasureItemEventArgs e)
        {
            IPopup popup = listBoxStatuses.Items[e.Index] as IPopup;
            int width = listBoxStatuses.Width - 4;
            Font font = new Font(listBoxStatuses.Font.FontFamily, listBoxStatuses.Font.Size, FontStyle.Bold);
            SizeF u = e.Graphics.MeasureString(popup.User, font, width - 2);
            SizeF t = e.Graphics.MeasureString(popup.Text + "\n", listBoxStatuses.Font, width - 2);
            e.ItemHeight = (int)(u.Height + t.Height + 0.5) + 5;
            if (e.ItemHeight > 255)
            {
                e.ItemHeight = 255;
            }
        }

        private void listBoxStatuses_DrawItem(object sender, DrawItemEventArgs e)
        {
            if ((e.Index >= 0) && (e.Index < listBoxStatuses.Items.Count))
            {
                IPopup popup = listBoxStatuses.Items[e.Index] as IPopup;
                Brush brush = new SolidBrush(listBoxStatuses.ForeColor);
                Font font = new Font(listBoxStatuses.Font.FontFamily, listBoxStatuses.Font.Size, FontStyle.Bold);
                SizeF u = e.Graphics.MeasureString(popup.User, font, e.Bounds.Width - 2);
                RectangleF rect = new RectangleF(1, e.Bounds.Top + 1, e.Bounds.Width - 2, Bounds.Height - 1);
                e.Graphics.DrawString(popup.User, font, brush, rect);
                rect = new RectangleF(1, e.Bounds.Top + u.Height + 1, e.Bounds.Width - 2, Bounds.Height - u.Height - 1);
                e.Graphics.DrawString(popup.Text, listBoxStatuses.Font, brush, rect);
            }
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            DateTime now = DateTime.Now;
            TimeSpan span = now - m_Time;
            switch ((int)m_State)
            {
                case (int)State.DISPLAY:
                    if (listBoxStatuses.Bounds.Contains(this.PointToClient(MousePosition)))
                    {
                        ReDisplay();
                    }
                    else
                    {
                        FadeOut();
                    }
                    break;
                case (int)State.FADE_IN:
                    if (span.TotalMilliseconds >= FADE_IN)
                    {
                        Display(listBoxStatuses.Items.Count);
                    }
                    else
                    {
                        this.Opacity = span.TotalMilliseconds / FADE_IN;
                    }
                    break;
                case (int)State.FADE_OUT:
                    if (listBoxStatuses.Bounds.Contains(this.PointToClient(MousePosition)))
                    {
                        ReDisplay();
                    }
                    else if (span.TotalMilliseconds >= FADE_OUT)
                    {
                        Idle();
                    }
                    else
                    {
                        this.Opacity = 1.0 - (span.TotalMilliseconds / FADE_OUT);
                    }
                    break;
            }
        }
    }
}