using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Windows.Media.Animation;
using EMDServer.Common;
using System.Diagnostics;
using System.Runtime.Remoting;
using System.Runtime.Serialization;

namespace EMDGui
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class EmdGui : Window, ICommandReceiver
    {
        private const int BUTTON1 = 210;
        private const int BUTTON2 = 211;
        private const int BUTTON3 = 212;
        private const int BUTTON4 = 213;
        private const int DISPLAY1 = 214;
        private const int DISPLAY2 = 215;
        private const int MAX_LAMP = 60;

        private IRemotingIPC remotingServer = null;
        private RemotingClient client = null;
        private double width = 0.4;
        private Dictionary<int, GradientStop[]> displays;
        private bool isConnected = false;

        public EmdGui()
        {
            InitializeComponent();

            this.displays = new Dictionary<int, GradientStop[]>();
            this.displays[0] = new GradientStop[2];
            this.displays[1] = new GradientStop[2];
            this.displays[0][0] = stopL;
            this.displays[0][1] = stopR;
            this.displays[1][0] = stopL2;
            this.displays[1][1] = stopR2;

            this.setupRemoting();
        }

        /// <summary>
        /// Connects to server over ipc (remoting)
        /// </summary>
        private void setupRemoting()
        {
            try
            {
                RemotingConfiguration.Configure("IPCClientConfig.xml", false);

                remotingServer = (IRemotingIPC)Activator.GetObject(typeof(IRemotingIPC), "ipc://emdServer/server");

                client = new RemotingClient();
                client.CommandReceiver = this;

                remotingServer.Register(client);

                this.isConnected = true;
            }
            catch (Exception e)
            {
                Debug.WriteLine(e.Message);
            }
        }

        /// <summary>
        /// Animates fading between values on buttons
        /// </summary>
        /// <param name="value">Value between 0 (left) and 1 (right)</param>
        /// <param name="buttonId">Display </param>
        /// <param name="valueString">Actual Power Consumption as a string without "Watt" at the end</param>
        public void setValue(double value, int displayId, string valueString)
        {
            value = (value - 0.5) * (1 + this.width) + 0.5;
            double valueLeft = value - this.width / 2;
            double valueRight = value + this.width / 2;

            //Animation on left side
            DoubleAnimation animate = new DoubleAnimation();
            animate.To = valueLeft;
            animate.Duration = new Duration(TimeSpan.FromMilliseconds(300));
            animate.FillBehavior = FillBehavior.HoldEnd;

            //Animation on right side
            DoubleAnimation animate2 = new DoubleAnimation();
            animate2.To = valueRight;
            animate2.Duration = new Duration(TimeSpan.FromMilliseconds(300));
            animate2.FillBehavior = FillBehavior.HoldEnd;

            if (displayId == EmdGui.DISPLAY1)
            {
                stopL.BeginAnimation(GradientStop.OffsetProperty, animate);
                stopR.BeginAnimation(GradientStop.OffsetProperty, animate2);
                display1.Text = valueString + " W";
            }
            else if (displayId == EmdGui.DISPLAY2)
            {
                stopL2.BeginAnimation(GradientStop.OffsetProperty, animate);
                stopR2.BeginAnimation(GradientStop.OffsetProperty, animate2);
                display2.Text = valueString + " W";
            }
        }

        private void border1_MouseDown(object sender, MouseButtonEventArgs e)
        {
            FrameworkElement element = (FrameworkElement)sender;
            if (((Border)element).Name == "border1")
                this.setValue(e.GetPosition((IInputElement)sender).X / element.Width, EmdGui.DISPLAY1, "30.0");
            else
                this.setValue(e.GetPosition((IInputElement)sender).X / element.Width, EmdGui.DISPLAY1, "15.7");
        }

        public void sendCommand(Command cmd)
        {
            try
            {
                if (isConnected)
                {
                    if (remotingServer != null)
                    {
                        remotingServer.Send(cmd);
                    }
                }
                else
                    this.setupRemoting();
            }
            catch (Exception e)
            {
                Debug.WriteLine(e.Message);
            }
        }

        private void dimmer_MouseDown(object sender, MouseButtonEventArgs e)
        {
            FrameworkElement element = (FrameworkElement)sender;
            if (((Border)element).Name == "border1")
                this.sendCommand(new Command(EmdGui.BUTTON1, (byte)Constants.EMD_COMMAND.BUTTON_PRESSED, new byte[4]));
            else if (((Border)element).Name == "border2")
                this.sendCommand(new Command(EmdGui.BUTTON2, (byte)Constants.EMD_COMMAND.BUTTON_PRESSED, new byte[4]));
        }

        private void dimmer_MouseUp(object sender, MouseButtonEventArgs e)
        {
            FrameworkElement element = (FrameworkElement)sender;
            if (((Border)element).Name == "border1")
                this.sendCommand(new Command(EmdGui.BUTTON1, (byte)Constants.EMD_COMMAND.BUTTON_RELEASED, new byte[4]));
            else if (((Border)element).Name == "border2")
                this.sendCommand(new Command(EmdGui.BUTTON2, (byte)Constants.EMD_COMMAND.BUTTON_RELEASED, new byte[4]));
        }

        private void switchAll_MouseUp(object sender, MouseButtonEventArgs e)
        {
            this.sendCommand(new Command(EmdGui.BUTTON3, (byte)Constants.EMD_COMMAND.TOGGLE_VALUE, new byte[4]));
        }

        private void switchBruno_MouseUp(object sender, MouseButtonEventArgs e)
        {
            this.sendCommand(new Command(EmdGui.BUTTON4, (byte)Constants.EMD_COMMAND.TOGGLE_VALUE, new byte[4]));
        }

        private void processCommand(Command cmd)
        {
            try
            {
                string val = string.Empty;

                if (cmd.Val != null && cmd.Val.Length > 2)
                {
                    int pos = (int)byte.Parse(((byte)cmd.Val[0]).ToString());

                    for (int i = 1; i < cmd.Val.Length; i++)
                    {
                        if (i == (cmd.Val.Length - pos))
                        {
                            val += ".";
                        }

                        val += ((int)cmd.Val[i]).ToString();
                    }

                    float value = float.Parse(val);
                    double valueScaled = float.Parse(val) / (double)EmdGui.MAX_LAMP;

                    this.Dispatcher.Invoke(new setValueDelegate(setValue), new object[] { valueScaled, cmd.Id, value.ToString() });
                }
            }
            catch (Exception e)
            {
                Debug.WriteLine("EMDGUI ProcessCommand:\t" + e.Message);
            }
        }

        public delegate void setValueDelegate(double value, int id, string valueString);

        #region ICommandReceiver Members
        // ----------------------------------------
        public void SendCommand(Command cmd)
        {
            this.processCommand(cmd);
        }
        // ----------------------------------------
        #endregion
    }
}
