using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace DHLib
{
    public class DataManager
    {
        #region Get latest scalar data
        private SensorData GetLatestScalarData(string publisherName, string sensorName)
        {
            DateTime timestamp;
            Double value;
            try
            {
                /// TODO: get rid of the code below, get data from database, 
                /// store its timestamp and value to timestamp and value, respectively
                timestamp = DateTime.Now;
                value = new Random().Next();
            }
            catch
            {
                return null;
            }
            SensorData data = new SensorData();
            data.DataType = DefaultDataType.Scalar;
            data.Timestamps = new DateTime[] { timestamp };
            data.Data = new double[] { value };
            return data;
        }

        /* SensorData[i] contains the latest reading of the scalar sensor uniquely 
         * identified by publisherNames[i] and sensorNames[i]. SensorData[i] = null 
         * if the sensor does not exist. If the sensor does exist and data is found, 
         * SensorData[i].timestamps[0] and SensorData[i].data[0] contain the timestamp 
         * and the data value, respectively.
         */
        public SensorData[] GetLatestScalarDataInBatch(string[] publisherName, string[] sensorName)
        {
            int count = Math.Min(publisherName.Length, sensorName.Length);
            SensorData[] data = new SensorData[count];
            for (int i = 0; i < count; i++)
                data[i] = GetLatestScalarData(publisherName[i], sensorName[i]);
            return data;
        }
        #endregion Get latest scalar data

        #region Get time series of scalar data
        private SensorData GetScalarDataSeries(string publisherName, string sensorName, DateTime startTime, DateTime endTime)
        {
            if (startTime >= endTime) return null;
            List<DateTime> timestamps = new List<DateTime>();
            List<double> values = new List<double>();
            try
            {
                /// TODO: get rid of the code below, get data from database, 
                /// store their timestamps and values to timestamps and 
                /// values, respectively
                TimeSpan diff = endTime.Subtract(startTime);
                diff = new TimeSpan(diff.Ticks / 100);
                DateTime currentTime = startTime;
                Random rand = new Random();
                for (int i = 0; i < 100; i++)
                {
                    timestamps.Add(currentTime);
                    values.Add(rand.Next());
                    currentTime = currentTime.Add(diff);
                }

            }
            catch
            {
                return null;
            }
            SensorData data = new SensorData();
            data.DataType = DefaultDataType.Scalar;
            data.Timestamps = timestamps.ToArray();
            data.Data = values.ToArray();
            return data;
        }

        /* SensorData[i] contains the series of readings taken between startTime and endTime 
         * by the scalar sensor uniquely identified by publisherNames[i] and sensorNames[i]. 
         * SensorData[i] = null if the sensor does not exist. If the sensor does exist and data 
         * is found, SensorData[i].timestamps and SensorData[i].data contain the series of timestamps 
         * and the corresponding data values, respectively.
         */
        public SensorData[] GetScalarDataSeriesInBatch(string[] publisherNames, string[] sensorNames, DateTime startTime, DateTime endTime)
        {
            if (startTime >= endTime) return null;
            int count = Math.Min(publisherNames.Length, sensorNames.Length);
            SensorData[] data = new SensorData[count];
            for (int i = 0; i < count; i++)
            {
                data[i] = GetScalarDataSeries(publisherNames[i], sensorNames[i], startTime, endTime);
            }
            return data;
        }
        #endregion Get time series of scalar data

        #region Get aggregate scalar data
        private SensorData GetAggregateScalarData(string publisherName, string sensorName, DateTime startTime, DateTime endTime)
        {
            DateTime timestamp;
            Double value;
            try
            {
                /// TODO: get rid of the code below, get data from database, 
                /// store its timestamp and value to timestamp and value, respectively
                timestamp = DateTime.Now;
                value = new Random().Next();
            }
            catch
            {
                return null;
            }
            SensorData data = new SensorData();
            data.DataType = DefaultDataType.Scalar;
            data.Timestamps = new DateTime[] { timestamp };
            data.Data = new double[] { value };
            return data;
        }

        /* SensorData[i] contains the average of the readings taken between startTime and 
         * endTime by the scalar sensor uniquely identified by publisherNames[i] and 
         * sensorNames[i]. SensorData[i] = null if the sensor does not exist. If the sensor 
         * does exist and data is found, SensorData[i].timestamps[0] and SensorData[i].data[0] 
         * contain the timestamp and the data value, respectively.
         */
        public SensorData[] GetAggregateScalarDataInBatch(string[] publisherNames, string[] sensorNames, DateTime startTime, DateTime endTime)
        {
            int count = Math.Min(publisherNames.Length, sensorNames.Length);
            SensorData[] data = new SensorData[count];
            for (int i = 0; i < count; i++)
                data[i] = GetAggregateScalarData(publisherNames[i], sensorNames[i], startTime, endTime);
            return data;
        }
        #endregion Get aggregate scalar data

        #region Get time series of aggregate scalar data
        private SensorData GetAggregateScalarDataSeries(string publisherName, string sensorName, DateTime startTime, DateTime endTime, int aggregateIntervalInSeconds)
        {
            if (startTime >= endTime || aggregateIntervalInSeconds <= 0) return null;
            List<double> values = new List<double>();
            List<DateTime> timestamps = new List<DateTime>();
            try
            {
                /// TODO: get rid of the code below, get data from database, 
                /// store their timestamps and values to timestamps and 
                /// values, respectively
                TimeSpan diff = new TimeSpan(0, 0, aggregateIntervalInSeconds);
                DateTime currentTime = endTime - new TimeSpan(diff.Ticks * 100);
                Random rand = new Random();
                for (int i = 0; i < 100; i++)
                {
                    timestamps.Add(currentTime);
                    values.Add(rand.Next());
                    currentTime = currentTime.Add(diff);
                }
            }
            catch
            {
                return null;
            }
            SensorData data = new SensorData();
            data.DataType = DefaultDataType.Scalar;
            data.Timestamps = timestamps.ToArray();
            data.Data = values.ToArray();
            return data;
        }

        /* SensorData[i] contains the series of aggregate data from the scalar sensor 
         * uniquely identi-fied by publisherNames[i] and sensorNames[i]. SensorData[i] = null 
         * if the sensor does not exist. If the sensor does exist and data is found, 
         * SensorData[i].timestamps contains an ascending series of timestamps, which should 
         * be a sub set of:
         *   {startTime + aggregateIntervalInSeconds * i | 
         *    i>=0 and startTime + aggregateIntervalInSeconds * i <= endTime}
         * SensorData[i].data[j] contains the aggregate value between SensorData[i].timestamps[j] 
         * and SensorData[i].timestamps[j] + aggregateIntervalInSeconds.
         */
        public SensorData[] GetAggregateScalarDataSeriesInBatch(string[] publisherNames, string[] sensorNames, DateTime startTime, DateTime endTime, int aggregateIntervalInSeconds)
        {
            if (startTime >= endTime || aggregateIntervalInSeconds <= 0) return null;
            int count = Math.Min(publisherNames.Length, sensorNames.Length);
            SensorData[] data = new SensorData[count];
            for (int i = 0; i < count; i++)
            {
                data[i] = GetAggregateScalarDataSeries(publisherNames[i], sensorNames[i], startTime, endTime, aggregateIntervalInSeconds);
            }
            return data;
        }
        #endregion Get time series of aggregate scalar data
    }
}