using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.Diagnostics;
using EMDServer.Common;

namespace EMDHardwareClientSimulation.Core.Devices
{
    class Button:Device
    {
        #region Class variables
        // ----------------------------------------
        private int oldDeviceValue;

        private int dimStepSize;
        private int dimCounter;
        private int dimDirection;

        private bool dispatcherRunning;

        private Timer dispatcher;
        private Timer switchDimTimer;
        // ----------------------------------------
        #endregion

        #region Public methods
        // ----------------------------------------
        /// <summary>
        /// Creates a new instance of the Button class
        /// </summary>
        public Button()
        {
            initTimer();            
            oldDeviceValue = 0;

            //Debug.WriteLine("BUTTON - Instantiated!");
        }

        /// <summary>
        /// Creates a new instance of the Button class
        /// </summary>
        /// <param name="gateway">iEMDConnection interface to the Device</param>
        public Button(iEMDConnection gateway):base(gateway)
        {
            initTimer();
            oldDeviceValue = 0;

            //Debug.WriteLine("BUTTON - Instantiated with params EMDINTERFACE!");
        }

        /// <summary>
        /// Creates a new instance of the Button class
        /// </summary>
        /// <param name="id">int id of the Button</param>
        /// <param name="gateway">iEMDConnection interface to the Button</param>
        public Button(int id, iEMDConnection gateway)
            : base(id, Constants.EMD_DEVICE_TYPE.BUTTON , gateway)
        {
            initTimer();
            oldDeviceValue = 0;

            //Debug.WriteLine("BUTTON - Instantiated with params ID=" + id + ", TYPE=" + Constants.EMD_DEVICE_TYPE.BUTTON + ", EMDINTERFACE!");
        }

        /// <summary>
        /// Activates the timer which is responsible
        /// for sending dimming values to the connected
        /// output devices
        /// </summary>
        public void buttonPressed()
        {
            switchDimTimer.Start();

            Debug.WriteLine("BUTTON - Button pressed: " + deviceId);
        }

        /// <summary>
        /// Deactivates and resets the timer
        /// </summary>
        public void buttonReleased()
        {
            if (dispatcherRunning)
            {
                dispatcherRunning = false;
                dispatcher.Stop();
                resetDimTimer();
            }
            else
            {
                switchDimTimer.Stop();
                toggleValue();
            }

            Debug.WriteLine("BUTTON - Button released: " + deviceId);
        }
        // ----------------------------------------
        #endregion

        #region Private methods
        // ----------------------------------------
        /// <summary>
        /// Initializes the timer which is responsible for
        /// sending dimming commands on pressed button
        /// </summary>
        private void initTimer()
        {
            dimCounter = 0;
            dimStepSize = Constants.EMD_DEVICE_MIN_DIM_STEP_SIZE;
            dimDirection = 1;

            dispatcherRunning = false;

            dispatcher = new Timer(Constants.EMD_DEVICE_BUTTON_DIM_TIMER_INTERVAL);
            dispatcher.Elapsed += new ElapsedEventHandler(dispatcher_Elapsed);

            switchDimTimer = new Timer(Constants.EMD_DEVICE_SWITCH_TIMER_INTERVAL);
            switchDimTimer.Elapsed += new ElapsedEventHandler(switchDimCounter_Elapsed);
        }

        /// <summary>
        /// Resets the dim timer
        /// </summary>
        private void resetDimTimer()
        {
            dimCounter = 0;
            dimStepSize = Constants.EMD_DEVICE_MIN_DIM_STEP_SIZE;
        }

        /// <summary>
        /// Inverts the value of the Device, if bigger than zero --> 
        /// set to zero, if zero --> set to maximum
        /// </summary>
        private void toggleValue()
        {
            if (deviceValue > 0)
            {
                oldDeviceValue = deviceValue;
                deviceValue = 0;
            }
            else 
            {
                if (oldDeviceValue == 0)
                {
                    deviceValue = 255;
                }
                else
                {
                    deviceValue = oldDeviceValue;
                }
            }

            sendValue();
        }

        /// <summary>
        /// Increments (+1) the actual value of the Device on each call
        /// and restarts with zero on overflow --> miessti eigentli driiegg sii
        /// </summary>
        private void dimValue()
        {
            if (dimDirection > 0)
            {
                if (deviceValue <= (Constants.EMD_DEVICE_MAX_VALUE - dimStepSize))
                {
                    deviceValue = deviceValue + dimStepSize;
                }
                else
                {
                    deviceValue = Constants.EMD_DEVICE_MAX_VALUE;
                    dimDirection = -1;
                    resetDimTimer();
                }
            }
            else
            {
                if (deviceValue >= (0 + dimStepSize))
                {
                    deviceValue = deviceValue - dimStepSize;
                }
                else
                {
                    deviceValue = 0;
                    dimDirection = 1;
                    resetDimTimer();
                }
            }

            //deviceValue = (deviceValue + dimStepSize) % (Constants.EMD_DEVICE_MAX_VALUE + 1);
            Debug.WriteLine("BUTTON - Value dimmed: " + deviceValue);
        }
        // ----------------------------------------
        #endregion

        #region Eventhandler
        // ----------------------------------------
        private void dispatcher_Elapsed(object sender, ElapsedEventArgs e)
        {
            // count how much elapsed steps
            // on arriving at a threshold begin dimming
            // before invert value

            if ((dimStepSize < Constants.EMD_DEVICE_MAX_DIM_STEP_SIZE) && (dimCounter++ % 5 == 0))
            {
                dimStepSize += Constants.EMD_DEVICE_DIM_STEP_INCREMENT_SIZE;
            }

            dimValue();

            //mc.send
            sendValue();

            //Debug.WriteLine("BUTTON - Timer elapsed, VALUE=" + deviceValue);
        }

        void switchDimCounter_Elapsed(object sender, ElapsedEventArgs e)
        {
            switchDimTimer.Stop();

            dispatcherRunning = true;
            dispatcher.Start();            
        }
        // ----------------------------------------
        #endregion
    }
}
