using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;

namespace WiPoMServer
{
    public class WiPoMInterface : IWiPoMInterface, IDisposable
    {
        /*Demo Mode */
        private Thread demoThread;
        private DateTime lastAction;
        private bool DemoEnabled = false;
        private bool demoThreadRunning = true;

        private AutoResetEvent resetEvent;
        private System.Timers.Timer timer;
        private DimmerInterface dimmer;
        private int StepSize = 1;
        private int TimerInterval = 25;
        private bool LightEnabled = false;

        private string ActiveCommand = string.Empty;

        public int DimmerValue
        {
            get
            {
                return dimmerValue;
            }
            set
            {
                this.dimmerValue = value;
            }
        }
        private int dimmerValue;
        public float PowerValue
        {
            get
            {
                return powerValue;
            }
            set
            {
                this.powerValue = value;
                OnPowerValueChanged((int)value);
                this.resetEvent.Set();
            }
        }
        private float powerValue;
        public float OldValue;

        public WiPoMInterface()
        {
            this.StepSize = Properties.Settings.Default.StepSize;
            this.TimerInterval = Properties.Settings.Default.TimerInterval;

            this.dimmer = new DimmerInterface();
            timer = new System.Timers.Timer();
            timer.Interval = this.TimerInterval;
            timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);

            this.resetEvent = new AutoResetEvent(true);

            this.PowerValue = 0.0f;

            this.demoThread = new Thread(new ThreadStart(RunDemoLoop));
            this.demoThread.Start();
        }
        /// <summary>
        /// Demo loop, checks last acess and after timeout has expired without interaction by user,
        /// it begins to show any animations
        /// </summary>
        private void RunDemoLoop()
        {
            TimeSpan span = new TimeSpan(0);
            int timeOut = Properties.Settings.Default.DemoTimeOutInSec;
            
            try
            {
                while (demoThreadRunning)
                {
                    span = new TimeSpan(0);
                    while (span.TotalSeconds < timeOut)
                    {
                        Thread.Sleep(3000);
                        span = DateTime.Now - this.lastAction;
                    }
                    this.DemoEnabled = true;

                    while (DemoEnabled)
                    {
                        for (int i = 0; i < 255; i++)
                        {
                            WriteValue(i);
                            if(!DemoEnabled)break;
                            Thread.Sleep(5);
                        }
                        Thread.Sleep(1000);
                        for (int i = 0; i < 255; i++)
                        {
                            WriteValue(255 - i);
                            if(!DemoEnabled)break;
                            Thread.Sleep(8);
                        }
                        Thread.Sleep(1000);
                        if(!DemoEnabled)break;
                        WriteValue(255);
                        if (!DemoEnabled) break;
                        Thread.Sleep(2000);
                        if (!DemoEnabled) break;
                        WriteValue(0);
                        Thread.Sleep(1000);
                        if (!DemoEnabled) break;
                        WriteValue(255);
                        Thread.Sleep(10);
                        WriteValue(0);
                        if (!DemoEnabled) break;
                        Thread.Sleep(10);
                        WriteValue(255);
                        Thread.Sleep(10);
                        if (!DemoEnabled) break;
                        WriteValue(0);
                        if (!DemoEnabled) break;
                        Thread.Sleep(5000);
                    }
                }
            }
            catch (Exception e)
            {

            }
        }

        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (this.ActiveCommand != string.Empty)
            {
                if (this.ActiveCommand == "Up")
                {
                    this.DimmerValue += this.StepSize;
                    if (this.DimmerValue > 255)
                    {
                        this.DimmerValue = 255;
                        this.timer.Stop();
                        this.ActiveCommand = string.Empty;
                    }
                    
                    if(this.LightEnabled)
                        this.WriteValue(this.DimmerValue);
                }
                else if (this.ActiveCommand == "Down")
                {
                    this.DimmerValue -= this.StepSize;
                    if (this.dimmerValue < 0)
                    {
                        this.DimmerValue = 0;
                        this.timer.Stop();
                        this.ActiveCommand = string.Empty;
                    }

                    if(this.LightEnabled)
                        this.WriteValue(this.dimmerValue);
                }
            }
        }

        #region IWiPoMInterface Members

        /// <summary >
        /// Enable or disable following elements:
        /// 1.  button
        /// 2.  Up
        /// 3.  Down
        /// </summary>
        /// <param name="name"></param>
        /// <param name="enable"></param>
        public void setValue(string name, bool enable)
        {
            lock (this)
            {
                this.DemoEnabled = false;
                this.lastAction = DateTime.Now;

                OnVarNameChanged(name, enable);

                switch (name)
                {
                    case "button":
                        if (!enable)
                        {
                            this.LightEnabled = false;
                            this.WriteValue(0);
                        }
                        else
                        {
                            this.LightEnabled = true;

                            if (this.DimmerValue < 10) this.DimmerValue = 255;

                            this.WriteValue(this.DimmerValue);
                        }
                        break;
                    case "Up":
                        if (enable)
                        {
                            this.ActiveCommand = "Up";
                            this.timer.Start();
                            this.timer.Enabled = true;
                        }
                        else
                        {
                            this.timer.Stop();
                            this.ActiveCommand = string.Empty;
                        }

                        break;
                    case "Down":
                        if (enable)
                        {
                            this.ActiveCommand = "Down";
                            this.timer.Start();
                            this.timer.Enabled = true;
                        }
                        else
                        {
                            this.timer.Stop();
                            this.ActiveCommand = string.Empty;
                        }
                        break;
                    default:
                        break;
                }
            }
        }
        private void WriteValue(int no)
        {
            this.dimmer.WriteValue(no);
            this.ComputerPowerMeterValue(no);
        }

        public float getValue(int no)
        {
            if (PowerValue == OldValue)
                this.resetEvent.WaitOne(TimeSpan.FromSeconds(Properties.Settings.Default.AjaxTimeOut));
            this.OldValue = powerValue;
            return PowerValue;
        }

        private void ComputerPowerMeterValue(int no)
        {
            this.PowerValue = (float) (float)(Math.Pow(5d, no / 255.0) - 1) / 4.0f * 60.0f;
            Debug.WriteLine(this.powerValue);
        }

        public event EventHandler<ValueChangedEventArgs> ValueChanged;
        public event EventHandler<ValueChangedEventArgs> PowerValueChanged;

        public void OnPowerValueChanged(int no)
        {
            if (this.PowerValueChanged != null)
                PowerValueChanged(this, new ValueChangedEventArgs() { ChangedValueNumber = no });
        }

        public void OnVarNameChanged(string label, bool enable)
        {
            if (this.ValueChanged != null)
                ValueChanged(this, new ValueChangedEventArgs() { ChangeVarName = label, Enabled = enable });
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            try
            {
                this.demoThreadRunning = false;
                this.DemoEnabled = false;
                this.demoThread.Abort();

            }
            catch
            { }
        }

        #endregion
    }
}
