/// <summary>
        /// Import the contents of the CSV file
        /// </summary>
        /// <param name="file"></param>
        /// <param name="context"></param>
        public void Import(string file, FlightRecorderFactory factory)
        {
            Regex regex = new Regex(FlattenedSighting.CsvRecordPattern, RegexOptions.Compiled);

            using (StreamReader reader = new StreamReader(file))
            {
                int count = 0;
                while (!reader.EndOfStream)
                {
                    string line = reader.ReadLine();
                    count++;

                    if (count > 1)
                    {
                        // Check the line matches the pattern required for successful import
                        bool matches = regex.Matches(line).Any();
                        if (!matches)
                        {
                            Console.WriteLine(line);
                            string message = $"Invalid record format at line {count} of {file}";
                            throw new InvalidRecordFormatException(message);
                        }

                        // Inflate the CSV record to a sighting and store it in the database
                        FlattenedSighting sighting = FlattenedSighting.FromCsv(line);
                        factory.Sightings.Add(sighting);

                        RecordImport?.Invoke(this, new SightingDataExchangeEventArgs {
                            RecordCount = count - 1, Sighting = sighting
                        });
                    }
                }
            }
        }
        public void FlattenedToCsvTest()
        {
            FlattenedSighting sighting  = _factory.Sightings.Get(a => a.Id == _sightingId).Flatten();
            string            csvRecord = sighting.ToCsv();
            Regex             regex     = new Regex(FlattenedSighting.CsvRecordPattern);
            bool matches = regex.Matches(csvRecord).Any();

            Assert.IsTrue(matches);
        }
        /// <summary>
        /// Add a sighting to the database based on a flattened representation of a sighting
        /// </summary>
        /// <param name="flattened"></param>
        /// <returns></returns>
        public async Task <Sighting> AddAsync(FlattenedSighting flattened)
        {
            long yearOfManufacture = DateTime.Now.Year - flattened.Age;
            long aircraftId        = (await _factory.Aircraft.AddAsync(flattened.Registration, flattened.SerialNumber, yearOfManufacture, flattened.Model, flattened.Manufacturer)).Id;
            long flightId          = (await _factory.Flights.AddAsync(flattened.FlightNumber, flattened.Embarkation, flattened.Destination, flattened.Airline)).Id;
            long locationId        = (await _factory.Locations.AddAsync(flattened.Location)).Id;

            return(await AddAsync(flattened.Altitude, flattened.Date, locationId, flightId, aircraftId));
        }
        public void InflateFromCsvTest()
        {
            FlattenedSighting sighting  = _factory.Sightings.Get(a => a.Id == _sightingId).Flatten();
            string            csvRecord = sighting.ToCsv();
            FlattenedSighting inflated  = FlattenedSighting.FromCsv(csvRecord);

            Assert.AreEqual(sighting.FlightNumber, inflated.FlightNumber);
            Assert.AreEqual(sighting.Airline, inflated.Airline);
            Assert.AreEqual(sighting.Registration, inflated.Registration);
            Assert.AreEqual(sighting.SerialNumber, inflated.SerialNumber);
            Assert.AreEqual(sighting.Manufacturer, inflated.Manufacturer);
            Assert.AreEqual(sighting.Model, inflated.Model);
            Assert.AreEqual(sighting.Age, inflated.Age);
            Assert.AreEqual(sighting.Embarkation, inflated.Embarkation);
            Assert.AreEqual(sighting.Destination, inflated.Destination);
            Assert.AreEqual(sighting.Altitude, inflated.Altitude);
            Assert.AreEqual(sighting.Date, inflated.Date);
            Assert.AreEqual(sighting.Location, inflated.Location);
        }