/// <summary>
        /// Calculates the energy in kWh for a given meter reading.  Previous reading is retrieved from the Register of the meter and
        /// used in the calculation.  NB kWh calculated to nearest whole number, rounding away from zero.
        /// </summary>
        /// <param name="reading">the MeterReading object of the current reading</param>
        /// <param name="meter">the Id of the meter the reading belongs to</param>
        /// <returns>kWh consumed as integer</returns>
        public int calculatekWh(MeterReading reading, Meter meter)
        {
            int kWh = 0;
            ///find the most recent reading before this one
            ///caculate the units consumed
            ///calculate the energy consumed --> need to know which meter this reading belongs to

            MeterReading previousReading = getPreviousReadingOnMeter(reading, meter);
            int unitsConsumed = calculateUnits(previousReading, reading, meter);

            ///to determine kWh need to know type of meter
            var elecMeter = meter as ElectricityMeter;
            if (elecMeter != null)
            {
                ///must be an electricity meter
                ///only coeff is scaling factor
                ///
                kWh = (int)Math.Round((double)unitsConsumed * elecMeter.ScalingFactor, MidpointRounding.AwayFromZero);
            }
            else
            {
                ///must be a gas meter
                var gasMeter = meter as GasMeter;
                kWh = (int)Math.Round(
                    (double)unitsConsumed
                    * gasMeter.MeterCoefficient     ///converts from units on meter to m3 (defined in constructor)
                    * gasMeter.CalorificValue       ///converts from m3 into joules (defined in constructor)
                    * gasMeter.CorrectionFactor     ///corrects joules for standard room temp and pressure
                    / EMConverter.fromJoulesTokWh,  ///converts from joules to kWh, static property of EMConverter class
                    MidpointRounding.AwayFromZero);
            }

            return kWh;
        }
 public abstract MeterReading editMeterReading(int meterReadingId, MeterReading newReading);
 public abstract int saveMeterReading(MeterReading meterReading);
        /// <summary>
        /// Gets the previous reading on this meter, using the date of the reading object passed in
        /// </summary>
        /// <param name="currentReading"></param>
        /// <param name="meter"></param>
        /// <returns></returns>
        private MeterReading getPreviousReadingOnMeter(MeterReading currentReading, Meter meter)
        {
            MeterReading previousReading = new MeterReading();
            meter.Register = meter.Register.OrderByDescending(rdg => rdg.Date).ToList();

            foreach (MeterReading rdg in meter.Register)
            {
                ///where there is only one other reading, the other reading is the start date of the meter
                ///it is acceptable to have a reading on the start date so currentReading date >= rdg date
                if (meter.Register.Count == 1)
                {
                    if (rdg.Date <= currentReading.Date)
                        return rdg;
                }
                else
                {
                    ///there are other non-zero readings, so currentReading date > rdg date
                    if (rdg.Date < currentReading.Date)
                        return rdg;
                }
            }

            ///
            return null;
        }
        private int calculateUnits(MeterReading previousReading, MeterReading rdg, Meter meter)
        {
            int unitsConsumed = 0;
            string readingAsString = rdg.Reading.ToString();
            ///truncate reading length if greater than no digits on meter
            if (readingAsString.Length > meter.NumbDigits)
            {
                readingAsString = readingAsString.Substring(0, meter.NumbDigits);
                rdg.Reading = int.Parse(readingAsString);
            }

            ///get max possible reading on this meter
            StringBuilder maxRead = new StringBuilder();
            maxRead.Append('9', meter.NumbDigits);
            int maxPossibleReading = int.Parse(maxRead.ToString());

            ///check if the meter has 'ticked over', ie gone past max reading
            if (previousReading.Reading > rdg.Reading)
            {
                ///meter has gone past the max read and started again
                ///therefore need units from previous --> max
                ///and from 0 --> current reading
                ///+1 for max --> 0 (eg 999999 + 1 will take the meter back to 0)
                unitsConsumed = maxPossibleReading - previousReading.Reading + rdg.Reading + 1;
            }
            else
            {
                ///units consumed is just the difference between prev and present
                unitsConsumed = rdg.Reading - previousReading.Reading;
            }

            return unitsConsumed;
        }
        private MeterReading getNextReading(Meter meter, MeterReading reading)
        {
            ///deal with no meter readings
            if (meter.Register == null | meter.Register.Count == 0)
            {
                return null;
            }
            else
            {
                meter.Register = meter.Register.OrderBy(rdg => rdg.Date).ToList();
                foreach (MeterReading rdg in meter.Register)
                {
                    ///register is in ascending date order so the first reading with a date greater than the
                    ///submitted reading is the required reading
                    if (rdg.Date > reading.Date)
                        return rdg;
                }

                ///if all readings are younger than the submitted reading return null
                return null;
            }
        }
        public void editMeterReading(int readingId, int meterId, string readingJSON, int propertyId)
        {
            ///desrialise reading and update in the database
            MeterReading updatedReading = EMConverter.fromJSONtoA<MeterReading>(readingJSON);
            mediator.DataManager.editMeterReading(readingId, updatedReading);

            ///get the meter (now with updated reading) and recalc the consumption for each reading
            Meter meter = mediator.DataManager.getMeter(meterId);
            meter.Register = meter.Register.OrderBy(rdg => rdg.Date).ToList();
            foreach (MeterReading rdg in meter.Register)
            {
                if (rdg.Date >= updatedReading.Date)
                {
                    MeterReading revisedReading = new MeterReading
                    {
                        Date = rdg.Date,
                        Reading = rdg.Reading
                    };

                    revisedReading.Consumption = calculatekWh(revisedReading, meter);
                    mediator.DataManager.editMeterReading(rdg.Id, revisedReading);
                }
            }

            mediator.updateAnnualCO2(propertyId);
            mediator.updatePropertyAnnualTotalkWh(propertyId);
        }
        public void deleteReading(int readingId, int meterId, int propertyId)
        {
            Meter meter = mediator.DataManager.getMeter(meterId);
            MeterReading deletedRead = mediator.DataManager.getReading(readingId);
            MeterReading nextRead = getNextReading(meter, deletedRead);

            ///check the deleted reading isn't the only or oldest reading in the list
            if(nextRead != null)
            {
                ///the consumption in the deleted reading needs to be added to the consumption
                ///of the next reading to maintain data integrity
                MeterReading updatedReading = new MeterReading
                {
                    Date = nextRead.Date,
                    Reading = nextRead.Reading,
                    Consumption = nextRead.Consumption + deletedRead.Consumption
                };

                mediator.DataManager.editMeterReading(nextRead.Id, updatedReading);
            }

            ///if the reading IS the only/oldest we can just delete it
            mediator.DataManager.deleteReading(readingId);

            mediator.updateAnnualCO2(propertyId);
            mediator.updatePropertyAnnualTotalkWh(propertyId);
        }
        public int createMeterReading(string date, int reading, int meterId, int propertyId)
        {
            Meter meter = mediator.DataManager.getMeter(meterId);

            MeterReading newReading = new MeterReading
            {
                Date = Convert.ToDateTime(date),
                Reading = reading
            };

            ///check if this is the first reading for this meter
            if (meter.Register.Count == 0)
            {
                MeterReading firstReading = new MeterReading();
                firstReading.Date = newReading.Date;
                firstReading.Reading = newReading.Reading;
                firstReading.Consumption = 0;

                int firstReadingId = mediator.DataManager.saveMeterReading(firstReading);
                mediator.DataManager.addReadingToMeter(firstReadingId, meter.Id);
                return firstReadingId;
            }

            newReading.Consumption = calculatekWh(newReading, meter);
            int readingId = mediator.DataManager.saveMeterReading(newReading);
            mediator.DataManager.addReadingToMeter(readingId, meterId);

            ///update property's annual kWh total

            mediator.updatePropertyAnnualTotalkWh(propertyId);
            mediator.updateAnnualCO2(propertyId);

            return readingId;
        }
 /// <summary>
 /// Saves the meter reading object to the database
 /// </summary>
 /// <param name="meterReading"></param>
 public override int saveMeterReading(MeterReading meterReading)
 {
     emdb.MeterReadings.Add(meterReading);
     emdb.SaveChanges();
     return meterReading.Id;
 }
        public override MeterReading editMeterReading(int meterReadingId, MeterReading newReading)
        {
            MeterReading oldReading = emdb.MeterReadings.Find(meterReadingId);

            oldReading.Consumption = newReading.Consumption;
            oldReading.Date = newReading.Date;
            oldReading.Reading = newReading.Reading;

            emdb.SaveChanges();
            return oldReading;
        }