﻿/* Copyright (c) Citrix Systems Inc. 
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, 
 * with or without modification, are permitted provided 
 * that the following conditions are met: 
 * 
 * *   Redistributions of source code must retain the above 
 *     copyright notice, this list of conditions and the 
 *     following disclaimer. 
 * *   Redistributions in binary form must reproduce the above 
 *     copyright notice, this list of conditions and the 
 *     following disclaimer in the documentation and/or other 
 *     materials provided with the distribution. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
 * SUCH DAMAGE.
 */

using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using XenAdmin.ConsoleView;
using XenAdmin.Core;

namespace XenAdmin.Controls.ConsoleTab
{
    public partial class ConnectionBar : UserControl
    {
        private const int HIDDEN_HEIGHT = 1;
        private const double ACCEL = 2.5;

        private readonly Timer timer = new Timer();

        private XSVNCScreen _selectedScreen;

        public ConnectionBar()
        {
            InitializeComponent();
            toolStrip1.Renderer = new CustomToolStripSystemRenderer();
            timer.Tick += timer_Tick;
            AttachMouseOnChildren(this);
        }

        public XSVNCScreen SelectedScreen
        {
            set
            {
                _selectedScreen = value;
                DisplayConnectionName();
            }
        }

        private void DisplayConnectionName()
        {
            if (_selectedScreen == null) //screen not assigned yet
                return; 

            string connectionName = _selectedScreen.Source.is_control_domain 
                ? _selectedScreen.Source.AffinityServerString 
                : _selectedScreen.Source.Name;

            using (Graphics g = toolStrip1.CreateGraphics())
            {
                int width = Drawing.MeasureText(g, connectionName, labelConnection.Font, TextFormatFlags.NoPadding).Width;
                if (width > labelConnection.ContentRectangle.Width)
                {
                    labelConnection.ToolTipText = connectionName;
                    connectionName = connectionName.Ellipsise(labelConnection.ContentRectangle, labelConnection.Font);
                }
                else
                {
                    labelConnection.ToolTipText = string.Empty;
                }
            }
            labelConnection.Text = connectionName;
        }

        private void AttachMouseOnChildren(Control control)
        {
            foreach (Control child in control.Controls)
            {
                child.MouseLeave += child_MouseLeave;
                child.MouseEnter += child_MouseEnter;
                AttachMouseOnChildren(child);
            }
        }

        private void child_MouseEnter(object sender, EventArgs e)
        {
            OnMouseEnter(e);
        }

        private void child_MouseLeave(object sender, EventArgs e)
        {
            OnMouseLeave(e);
        }

        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);
            ShowAnimated();
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);

            Point clientMouse = PointToClient(MousePosition);
            var r = new Rectangle(0, 0, Width, Height - HIDDEN_HEIGHT);

            if (!r.Contains(clientMouse))
                HideAnimated();
        }

        private void buttonExitFullScreen_Click(object sender, EventArgs e)
        {
            if (ParentForm != null)
                ParentForm.Close();
        }

        #region Animated Show/Hide

        private Animating state = Animating.Open;

        private int Y
        {
            get { return Location.Y; }
            set { Location = new Point(Location.X, value); }
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            if (state == Animating.Showing && Y < 0)
            {
                Y -= (int)(Y / ACCEL) - 1;
                if (Y == 0)
                {
                    timer.Stop();
                    state = Animating.Open;
                }
                Debug.WriteLine("Opening " + Y);
            }
            if (state == Animating.Hiding && Y > -(Height - HIDDEN_HEIGHT))
            {
                Y -= (int)((Y + Height - HIDDEN_HEIGHT) / ACCEL) + 1;
                if (Y == -(Height - HIDDEN_HEIGHT))
                {
                    timer.Stop();
                    state = Animating.Closed;
                }
                Debug.WriteLine("Closing " + Y);
            }
            timer.Interval = 100;
        }


        public void ShowAnimated()
        {
            if (state == Animating.Open)
                return;

            if (Properties.Settings.Default.PinConnectionBar)
            {
                ShowPinned();
                return;
            }
            state = Animating.Showing;
            timer.Stop();
            timer.Start();
        }

        public void HideAnimated()
        {
            if (state == Animating.Closed)
                return;
            if (Properties.Settings.Default.PinConnectionBar)
                return;
            state = Animating.Hiding;
            timer.Stop();
            timer.Start();
        }

        private enum Animating
        {
            Showing,
            Hiding,
            Open,
            Closed
        } 

        #endregion

        public void ShowPinned()
        {
            if (!buttonPin.Checked)
                buttonPin.Checked = true;

            if (state == Animating.Open)
                return;

            Y = 0;
            state = Animating.Open;
        }

        private void toolStrip1_Resize(object sender, EventArgs e)
        {
            labelConnection.Width = toolStrip1.Width - buttonPin.Width - buttonExitFullScreen.Width - 12;
            DisplayConnectionName();
        }

        private void buttonPin_CheckedChanged(object sender, EventArgs e)
        {
            if (Properties.Settings.Default.PinConnectionBar != buttonPin.Checked)
            {
                Properties.Settings.Default.PinConnectionBar = buttonPin.Checked;
                Settings.TrySaveSettings();
            }
            if (buttonPin.Checked)
                ShowPinned();
        }
    }

    public class CustomToolStripSystemRenderer : ToolStripSystemRenderer
    {
        protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e) { }

        protected override void OnRenderToolStripBackground(
         ToolStripRenderEventArgs e)
        {
            using (var brush = new LinearGradientBrush(e.AffectedBounds, Color.FromArgb(64, 64, 64), Color.Gray, 90))
            {
                e.Graphics.FillRectangle(brush, e.AffectedBounds); 
            }
            
            using (var borderPen = new Pen(Color.Black, 1))
            {
                e.Graphics.DrawRectangle(borderPen,
                    new Rectangle(e.AffectedBounds.Left, e.AffectedBounds.Top, e.AffectedBounds.Width - 1, e.AffectedBounds.Height - 2));
            }
        }
    }
}
