public static Dictionary<DayOfWeek, double> Distance(Int16 carId)
        {
            Dictionary<DayOfWeek, double> distancePerDay = new Dictionary<DayOfWeek, double>();
            distancePerDay.Add(DayOfWeek.Monday, 0);
            distancePerDay.Add(DayOfWeek.Tuesday, 0);
            distancePerDay.Add(DayOfWeek.Wednesday, 0);
            distancePerDay.Add(DayOfWeek.Thursday, 0);
            distancePerDay.Add(DayOfWeek.Friday, 0);
            distancePerDay.Add(DayOfWeek.Saturday, 0);
            distancePerDay.Add(DayOfWeek.Sunday, 0);

            TimeSpan day = new TimeSpan(24, 0, 0);

            DBController dbc = new DBController();
            List<Int64> tripIds = dbc.GetTripIdsByCarId(carId);
            dbc.Close();

            foreach (Int64 tripId in tripIds) {
                List<Fact> entries = dbc.GetSpatioTemporalByCarIdAndTripId(carId, tripId);

                for (int i = 1; i < entries.Count; i++) {
                    distancePerDay[entries[i].Temporal.Timestamp.DayOfWeek] += entries[i].Spatial.DistanceToLag;
                }
            }

            return distancePerDay;
        }
        public static Dictionary<DayOfWeek, int> Plots(Int16 carId)
        {
            Dictionary<DayOfWeek, int> plotsPerDay = new Dictionary<DayOfWeek, int>();
            plotsPerDay.Add(DayOfWeek.Monday, 0);
            plotsPerDay.Add(DayOfWeek.Tuesday, 0);
            plotsPerDay.Add(DayOfWeek.Wednesday, 0);
            plotsPerDay.Add(DayOfWeek.Thursday, 0);
            plotsPerDay.Add(DayOfWeek.Friday, 0);
            plotsPerDay.Add(DayOfWeek.Saturday, 0);
            plotsPerDay.Add(DayOfWeek.Sunday, 0);

            //Fetch all timestamps for all trips on car
            DBController dbc = new DBController();
            List<Int64> tripIds = dbc.GetTripIdsByCarId(carId);
            List<TemporalInformation> timestamps = new List<TemporalInformation>();
            foreach (Int64 tripId in tripIds) {
                timestamps = dbc.GetTimestampsByCarIdAndTripId(carId, tripId);
            }

            dbc.Close();

            foreach (TemporalInformation timestamp in timestamps) {
                plotsPerDay[timestamp.Timestamp.DayOfWeek] += 1;
            }

            return plotsPerDay;
        }
        public static Dictionary<DayOfWeek, TimeSpan> Time(Int16 carId)
        {
            Dictionary<DayOfWeek, TimeSpan> timePerDay = new Dictionary<DayOfWeek, TimeSpan>();
            timePerDay.Add(DayOfWeek.Monday, new TimeSpan(0, 0, 0));
            timePerDay.Add(DayOfWeek.Tuesday, new TimeSpan(0, 0, 0));
            timePerDay.Add(DayOfWeek.Wednesday, new TimeSpan(0, 0, 0));
            timePerDay.Add(DayOfWeek.Thursday, new TimeSpan(0, 0, 0));
            timePerDay.Add(DayOfWeek.Friday, new TimeSpan(0, 0, 0));
            timePerDay.Add(DayOfWeek.Saturday, new TimeSpan(0, 0, 0));
            timePerDay.Add(DayOfWeek.Sunday, new TimeSpan(0, 0, 0));

            DBController dbc = new DBController();
            List<Int64> tripIds = dbc.GetTripIdsByCarId(carId);
            dbc.Close();

            foreach (Int64 tripId in tripIds) {
                List<TemporalInformation> entries = dbc.GetTimestampsByCarIdAndTripId(carId, tripId);

                for (int i = 1; i < entries.Count; i++) {
                    timePerDay[entries[i].Timestamp.DayOfWeek] += entries[i].SecondsToLag;
                }
            }

            return timePerDay;
        }
        public static void Update(Int16 CarId)
        {
            DBController dbc = new DBController();
            List<Int64> tripIds = dbc.GetTripIdsByCarId(CarId);
            foreach (Int64 tripId in tripIds) {
                List<Fact> facts = dbc.GetFactsByTripId(tripId);
                dbc.UpdateGPSFactWithMeasures(UpdatedFacts(facts));
            }

            dbc.Close();
        }
        public static List<TimeSpan> TimePerTrip(Int16 carId)
        {
            DBController dbc = new DBController();
            List<Int64> tripIds = dbc.GetTripIdsByCarId(carId);
            dbc.Close();

            List<TimeSpan> minutesPerTrip = new List<TimeSpan>();

            foreach (Int64 tripId in tripIds) {
                minutesPerTrip.Add(TripStatistics.Duration(carId, tripId));
            }

            return minutesPerTrip;
        }
        public static List<double> DistancePerTrip(Int16 carId)
        {
            DBController dbc = new DBController();
            List<Int64> tripIds = dbc.GetTripIdsByCarId(carId);
            dbc.Close();

            List<double> kilometersPerTrip = new List<double>();

            foreach (Int64 tripId in tripIds) {
                kilometersPerTrip.Add(TripStatistics.Distance(carId, tripId));
            }

            return kilometersPerTrip;
        }
        public static double AveragePercentageDistanceAbove(double ignorableSpeed, TimeSpan ignorableTime, double ignorableDistance)
        {
            double totalDistanceAbove = 0;
            double totalDistanceBelow = 0;
            DBController dbc = new DBController();
            List<Int16> carIds = dbc.GetCarIds();

            foreach (Int16 carId in carIds) {
                List<Int64> tripIds = dbc.GetTripIdsByCarId(carId);
                foreach (Int64 tripId in tripIds) {
                    totalDistanceAbove += SpeedingStatistics.DistanceAbove(carId, tripId, ignorableSpeed, ignorableTime, ignorableDistance);
                    totalDistanceBelow += SpeedingStatistics.DistanceBelow(carId, tripId, ignorableSpeed, ignorableTime, ignorableDistance);
                }
            }

            dbc.Close();
            return totalDistanceAbove / (totalDistanceAbove + totalDistanceBelow) * 100;
        }
        public static double AveragePercentageTimeAbove(double ignorableSpeed, TimeSpan ignorableTime, double ignorableDistance)
        {
            TimeSpan totalTimeAbove = new TimeSpan(0, 0, 0);
            TimeSpan totalTimeBelow = new TimeSpan(0, 0, 0);
            DBController dbc = new DBController();
            List<Int16> carIds = dbc.GetCarIds();

            foreach (Int16 carId in carIds) {
                List<Int64> tripIds = dbc.GetTripIdsByCarId(carId);
                foreach (Int64 tripId in tripIds) {
                    totalTimeAbove += SpeedingStatistics.TimeAbove(carId, tripId, ignorableSpeed, ignorableTime, ignorableDistance);
                    totalTimeBelow += SpeedingStatistics.TimeBelow(carId, tripId, ignorableSpeed, ignorableTime, ignorableDistance);
                }
            }

            dbc.Close();
            return totalTimeAbove.Ticks / (totalTimeAbove.Ticks + totalTimeBelow.Ticks) * 100;
        }
        public static void OutlierHandling(Int16 carId)
        {
            List<Int64> tripIds = new List<long>();
            DBController dbc = new DBController();
            tripIds = dbc.GetTripIdsByCarId(carId);

            Int64 outliersCount = 0;

            foreach (Int64 tripId in tripIds) {
                List<Int64> outliers = OutlierDetection.RemoveOutliers(carId, tripId);
                if (outliers.Count != 0) {
                    dbc.UpdateEntriesWithNoTrip(outliers);
                }
                outliersCount += OutlierDetection.RemoveOutliers(carId, tripId).Count();
            }
            dbc.Close();
            Console.WriteLine("Car " + carId + " removed " + outliersCount + " outliers.");
        }
        public static void Update(Int16 carId)
        {
            DBController dbc = new DBController();
            List<Int64> tripIds = dbc.GetTripIdsByCarId(carId);
            List<Fact> facts;
            Trip trip;
            Int64 previousTripId = 0;
            DateTime previousEndTimestamp = new DateTime();

            for (int i = 0; i < tripIds.Count; i++) {
                trip = dbc.GetTripByTripId(tripIds[i]);
                facts = dbc.GetFactsByTripId(tripIds[i]);

                //If a previous trip exists, save ID and the time passed between them
                if (i > 0) {
                    trip.PreviousTripId = previousTripId;
                    trip.SecondsToLag = MeasureCalculator.SecondsToLag(facts[0].Temporal.Timestamp, previousEndTimestamp);
                }

                //Remember variables for next iteration
                previousTripId = trip.TripId;
                previousEndTimestamp = trip.EndTemporal.Timestamp;

                Console.WriteLine("Updating car {0}, trip {1} ({2} facts)", carId, trip.TripId, facts.Count);
                trip = UpdateTrip(trip, facts, dbc);
                trip.OptimalScore = FinalScore.CalculateOptimalScore(trip);
                List<double> fullscores = FinalScore.CalculateTripScores(trip);

                trip.RoadTypeScore = fullscores[0];
                trip.CriticalTimeScore = fullscores[1];
                trip.SpeedingScore = fullscores[2];
                trip.AccelerationScore = fullscores[3];
                trip.BrakeScore = fullscores[4];
                trip.JerkScore = fullscores[5];
                trip.TripScore = fullscores[6];
                dbc.UpdateTripFactWithMeasures(trip);
            }

            dbc.Close();
        }
        public static double AveragePercentageDistanceAboveInThreshold(double lowerPercentage, double upperPercentage, double ignorableSpeed, TimeSpan ignorableTime, double ignorableDistance)
        {
            List<double> percentages = new List<double>();

            DBController dbc = new DBController();
            List<Int16> carIds = dbc.GetCarIds();

            foreach (Int16 carId in carIds) {
                List<Int64> tripIds = dbc.GetTripIdsByCarId(carId);
                foreach (Int64 tripId in tripIds) {
                    percentages.Add(SpeedingStatistics.PercentageDistanceAboveInThreshold(carId, tripId, lowerPercentage, upperPercentage, ignorableSpeed, ignorableTime, ignorableDistance));
                }
            }

            double totalPercentage = 0;
            foreach (double percentage in percentages) {
                totalPercentage += percentage;
            }

            dbc.Close();
            return totalPercentage / percentages.Count;
        }
        public static void UpdateTrip(Int16 carId, Int64 tripId)
        {
            DBController dbc = new DBController();

            Trip trip = new Trip(tripId, carId);
            List<Fact> facts = dbc.GetFactsByTripIdNoQuality(tripId);

            //Getting the previous tripid and seconds to previous trip
            List<Int64> tripIds = dbc.GetTripIdsByCarId(carId);
            //In case this is the first trip - ignore computing measures for previous trip
            if (tripIds.Count > 1) {
                Int64 latestTrip = tripIds[tripIds.Count() - 2];
                Trip previousTrip = dbc.GetTripByCarIdAndTripId(carId, latestTrip);
                trip.SecondsToLag = MeasureCalculator.SecondsToLag(facts[0].Temporal.Timestamp, previousTrip.EndTemporal.Timestamp);
            } else {
                trip.SecondsToLag = new TimeSpan(0, 0, -1);
            }
            //Calc the trip updates
            trip = UpdateTrip(trip, facts, dbc);

            //Compute the scores
            trip.OptimalScore = FinalScore.CalculateOptimalScore(trip);
            List<double> fullscores = FinalScore.CalculateTripScores(trip);

            trip.RoadTypeScore = fullscores[0];
            trip.CriticalTimeScore = fullscores[1];
            trip.SpeedingScore = fullscores[2];
            trip.AccelerationScore = fullscores[3];
            trip.BrakeScore = fullscores[4];
            trip.JerkScore = fullscores[5];
            trip.TripScore = fullscores[6];

            //Update the trip in the database
            dbc.UpdateTripFactWithMeasures(trip);
            dbc.Close();
        }
        //Returns average kilometers per trip for each week number
        public static Dictionary<KeyValuePair<int, int>, double> AverageTripDistance(Int16 carId)
        {
            //Get calendar for week number reference
            DateTimeFormatInfo formatInformation = DateTimeFormatInfo.CurrentInfo;
            Calendar calendar = formatInformation.Calendar;

            //Dictionary of <Year, Week>, <TripCount, Distance>
            Dictionary<KeyValuePair<int, int>, KeyValuePair<int, double>> results = new Dictionary<KeyValuePair<int, int>, KeyValuePair<int, double>>();

            //Get trips to get distances from
            DBController dbc = new DBController();
            List<Int64> tripIds = dbc.GetTripIdsByCarId(carId);

            foreach (Int64 tripId in tripIds) {
                List<Fact> facts = dbc.GetSpatioTemporalByCarIdAndTripId(carId, tripId);
                //Save starting points of trip, in case trip is split up later
                int startIndex = 0;
                double distanceForWeek = 0;
                int startWeek = calendar.GetWeekOfYear(facts[0].Temporal.Timestamp, formatInformation.CalendarWeekRule, formatInformation.FirstDayOfWeek);
                int startYear = facts[0].Temporal.Timestamp.Year;

                for (int i = 1; i < facts.Count; i++) {

                    //If week or year changes in the trip, save that part from startIndex to current index
                    int week = calendar.GetWeekOfYear(facts[i].Temporal.Timestamp, formatInformation.CalendarWeekRule, formatInformation.FirstDayOfWeek);
                    int year = facts[i].Temporal.Timestamp.Year;
                    if (week != startWeek || year != startYear) {
                        for (int j = startIndex; j <= i; j++) {
                            distanceForWeek += facts[j].Spatial.DistanceToLag;
                        }

                        KeyValuePair<int, int> tripPartKey = new KeyValuePair<int, int>(startYear, startWeek);

                        if (results.ContainsKey(tripPartKey)) {
                            results[tripPartKey] = new KeyValuePair<int, double>(results[tripPartKey].Key + 1, results[tripPartKey].Value + distanceForWeek);
                        } else {
                            results.Add(new KeyValuePair<int, int>(startYear, startWeek), new KeyValuePair<int, double>(1, distanceForWeek));
                        }

                        //Update starting points for new part of trip
                        startIndex = i;
                        startWeek = week;
                        startYear = year;
                        distanceForWeek = 0;
                    }
                }

                //At the end of the trip, save current part from startIndex to current index.
                for (int j = startIndex; j < facts.Count; j++) {
                    distanceForWeek += facts[j].Spatial.DistanceToLag;
                }

                KeyValuePair<int, int> key = new KeyValuePair<int, int>(startYear, startWeek);

                if (results.ContainsKey(key)) {
                    results[key] = new KeyValuePair<int, double>(results[key].Key + 1, results[key].Value + distanceForWeek);
                } else {
                    results.Add(new KeyValuePair<int, int>(startYear, startWeek), new KeyValuePair<int, double>(1, distanceForWeek));
                }
            }

            dbc.Close();

            //Calculate average distance per week, and return result
            Dictionary<KeyValuePair<int, int>, double> weeklyAverageTripDistance = new Dictionary<KeyValuePair<int, int>, double>();

            foreach (KeyValuePair<KeyValuePair<int, int>, KeyValuePair<int, double>> kvp in results) {
                weeklyAverageTripDistance.Add(kvp.Key, (kvp.Value.Value / kvp.Value.Key));
            }

            return weeklyAverageTripDistance;
        }