using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Diagnostics;
namespace FlightRoutesCalculatorApp
public class FlightRoutesController : Controller
public ActionResult Index()
var service = FlightRoutesService.WithConnection("http://www.mocky.io/v2/5ce66fb8330000660073156e");
var flightRoutesViewModel = service.generateIndexView();
return View(flightRoutesViewModel);
public JsonResult ChangeOutbound(int selectedOutboundFlightId)
var service = FlightRoutesService.WithConnection("http://www.mocky.io/v2/5ce66fb8330000660073156e");
var combinableFlights = service.GetCombinableFlightsByOutboundFlightId(selectedOutboundFlightId);
var enabledFlightsIds = combinableFlights.Select(t => new { t.Id });
var route = service.CalculateBestRouteByOutboundFlight(selectedOutboundFlightId, combinableFlights);
return Json(new { route, enabledFlightsIds });
public JsonResult ExecuteTests()
var flightRoutesTest = new FlightRoutesTest();
var test1 = flightRoutesTest.Get_Combinable_Flights_By_OutboungFlight_Id_Test();
var test2 = flightRoutesTest.Calculate_Flight_Route_With_InboundFlights_Of_Same_Airline_Test();
var test3 = flightRoutesTest.Calculate_Flight_Route_Without_InboundFlights_Of_Same_Airline_Test();
var test4 = flightRoutesTest.Calculate_Cheapest_Route_Test();
var test5 = flightRoutesTest.Calculate_Cheapest_Route_Test_Fail();
return Json(new { test1, test2, test3, test4, test5 });
internal class FlightRoutesService
private FlightRepository FlightRepository { get; set; }
private FlightRoutesService() { }
internal static FlightRoutesService WithConnection(string _source)
return new FlightRoutesService() { FlightRepository = FlightRepository.WithConnection(_source) };
internal static FlightRoutesService WithJson(string _source)
return new FlightRoutesService() { FlightRepository = FlightRepository.WithJson(_source) };
internal FlightRoutesViewModel generateIndexView()
var flights = new List<Flight>();
var route = CalculateCheapestRoute(out flights);
var outboundflights = flights.Where(f => f.Type == FlightType.OutboundFlight).OrderBy(t => t.Price).ToList();
var inboundflights = flights.Where(f => f.Type == FlightType.InboundFlight).OrderBy(t => t.Price).ToList();
return new FlightRoutesViewModel() { OutboundFlights = outboundflights, InboundFlights = inboundflights, Route = route };
internal FlightRoute CalculateCheapestRoute(out List<Flight> _allFlights)
var route = new FlightRoute();
_allFlights = FlightRepository.GetAllFlights();
foreach (Flight f in _allFlights.Where(f => f.Type == FlightType.OutboundFlight))
var innerRoute = new FlightRoute();
innerRoute.SetOutBoundFlight(f);
var availableInboundFlights = GetCombinableFlightsByOutboundFlight(f);
foreach (Flight inbound in availableInboundFlights)
innerRoute.SetInBoundFlight(inbound);
route = new FlightRoute(f, inbound);
else if (innerRoute.Price < route.Price)
route = new FlightRoute(f, inbound);
internal FlightRoute CalculateBestRouteByOutboundFlight(int _selectedOutboundFlightId, List<Flight> _combinableFlights)
var flights = FlightRepository.GetAllFlights();
var selectedFlight = flights.First(i => i.Id == _selectedOutboundFlightId);
if (_combinableFlights.Any())
var cheapestFlight = _combinableFlights.OrderBy(i => i.Price).ToList().First();
return new FlightRoute() { OutboundFlight = selectedFlight, InboundFlight = cheapestFlight, Price = selectedFlight.Price + cheapestFlight.Price };
return new FlightRoute() { OutboundFlight = selectedFlight, Price = 0 };
internal List<Flight> GetCombinableFlightsByOutboundFlightId(int _selectedOutboundFlightId)
var selectedFlight = FlightRepository.GetFlightById(_selectedOutboundFlightId);
return GetCombinableFlightsByOutboundFlight(selectedFlight);
private List<Flight> GetCombinableFlightsByOutboundFlight(Flight _outboundFlight)
var inboundFlights = FlightRepository.GetAllFlights().Where(f => f.Type.Equals(FlightType.InboundFlight)).ToList();
var combinableFlights = GetFullyCombinableFlights(inboundFlights, _outboundFlight);
if (!combinableFlights.Any())
combinableFlights = GetPartiallyCombinableFlights(inboundFlights, _outboundFlight);
return combinableFlights;
private List<Flight> GetFullyCombinableFlights(List<Flight> _flights, Flight _flight)
return _flights.Where(f => IsFullyCombinable(_flight, f)).ToList();
private List<Flight> GetPartiallyCombinableFlights(List<Flight> _flights, Flight _flight)
return _flights.Where(f => IsPartiallyCombinable(_flight, f)).ToList();
private bool IsFullyCombinable(Flight _outboundFlight, Flight _inboundFlight)
return _inboundFlight.Airline == _outboundFlight.Airline && _outboundFlight.ArrivalAirportCode == _inboundFlight.DepartureAirportCode && _outboundFlight.DepartureAirportCode == _inboundFlight.ArrivalAirportCode;
private bool IsPartiallyCombinable(Flight _outboundFlight, Flight _inboundFlight)
return _outboundFlight.ArrivalAirportCode == _inboundFlight.DepartureAirportCode && _outboundFlight.DepartureAirportCode == _inboundFlight.ArrivalAirportCode;
internal class FlightRepository
private FlightRepository() { }
internal static FlightRepository WithConnection(string _sourceUrl)
var flightRepository = new FlightRepository();
using (WebClient wc = new WebClient())
json = wc.DownloadString(_sourceUrl);
flightRepository.Content = json;
internal static FlightRepository WithJson(string _json)
return new FlightRepository() { Content = _json };
internal List<Flight> GetAllFlights()
return ParseFlights(Content);
internal Flight GetFlightById(int _id)
var flights = GetAllFlights();
var enabledFlights = new List<Flight>();
return flights.First(i => i.Id == _id);
private List<Flight> ParseFlights(string _json)
var flights = new List<Flight>();
_json = _json.Replace('=', ':');
dynamic data = JObject.Parse(_json);
foreach (var flight in data.outboundFlights)
flights.Add(new Flight { Type = FlightType.OutboundFlight, Id = flight.id, Airline = flight.airline, ArrivalAirportCode = flight.arrivalAirportCode, DepartureAirportCode = flight.departureAirportCode, Price = Convert.ToDouble(flight.price) });
foreach (var flight in data.inboundFlights)
flights.Add(new Flight { Type = FlightType.InboundFlight, Id = flight.id, Airline = flight.airline, ArrivalAirportCode = flight.arrivalAirportCode, DepartureAirportCode = flight.departureAirportCode, Price = Convert.ToDouble(flight.price) });
internal class FlightRoutesTest
private readonly string Json_With_InboundFlights_Of_Same_Airline = @"
""airline"": ""Transavia"",
""departureAirportCode"" = ""BCN"",
""arrivalAirportCode"" = ""AMS"",
""airline"": ""Vueling"",
""departureAirportCode"" = ""BCN"",
""arrivalAirportCode"" = ""AMS"",
""airline"": ""Transavia"",
""departureAirportCode"" = ""AMS"",
""arrivalAirportCode"" = ""BCN"",
""airline"": ""Transavia"",
""departureAirportCode"" = ""AMS"",
""arrivalAirportCode"" = ""BCN"",
private readonly string Json_Without_InboundFlights_Of_Same_Airline = @"
""airline"": ""Transavia"",
""departureAirportCode"" = ""BCN"",
""arrivalAirportCode"" = ""AMS"",
""airline"": ""Vueling"",
""departureAirportCode"" = ""BCN"",
""arrivalAirportCode"" = ""ROT"",
""departureAirportCode"" = ""AMS"",
""arrivalAirportCode"" = ""BCN"",
""airline"": ""Transavia"",
""departureAirportCode"" = ""ROT"",
""arrivalAirportCode"" = ""BCN"",
public bool Get_Combinable_Flights_By_OutboungFlight_Id_Test()
var service = FlightRoutesService.WithJson(Json_With_InboundFlights_Of_Same_Airline);
var combinableFlights = service.GetCombinableFlightsByOutboundFlightId(1);
var countOK = combinableFlights.Count == 2;
public bool Calculate_Flight_Route_With_InboundFlights_Of_Same_Airline_Test()
var service = FlightRoutesService.WithJson(Json_With_InboundFlights_Of_Same_Airline);
var combinableFlights = service.GetCombinableFlightsByOutboundFlightId(1);
var route = service.CalculateBestRouteByOutboundFlight(1, combinableFlights);
var routeOk = route.Price == 45;
public bool Calculate_Flight_Route_Without_InboundFlights_Of_Same_Airline_Test()
var service = FlightRoutesService.WithJson(Json_Without_InboundFlights_Of_Same_Airline);
var combinableFlights = service.GetCombinableFlightsByOutboundFlightId(1);
var route = service.CalculateBestRouteByOutboundFlight(1, combinableFlights);
var routeOk = route.Price == 65;
public bool Calculate_Cheapest_Route_Test()
var service = FlightRoutesService.WithJson(Json_Without_InboundFlights_Of_Same_Airline);
var flights = new List<Flight>();
var route = service.CalculateCheapestRoute(out flights);
var routeOk = route.Price == 50;
public bool Calculate_Cheapest_Route_Test_Fail()
var service = FlightRoutesService.WithJson(Json_With_InboundFlights_Of_Same_Airline);
var flights = new List<Flight>();
var route = service.CalculateCheapestRoute(out flights);
var routeOk = route.Price == 435;