public SimulationsModule(ISimulationService service, IUserService userService, IClusterService clusterService, IMapService mapService, IVehicleService vehicleService) : base("simulations")
        {
            this.RequiresAuthentication();

            Get("/", x =>
            {
                Debug.Log($"Listing simulations");
                try
                {
                    int page = Request.Query["page"];
                    // TODO: Items per page should be read from personal user settings.
                    //       This value should be independent for each module: maps, vehicles and simulation.
                    //       But for now 5 is just an arbitrary value to ensure that we don't try and Page a count of 0
                    int count = Request.Query["count"] > 0 ? Request.Query["count"] : Config.DefaultPageSize;
                    return(service.List(page, count, this.Context.CurrentUser.Identity.Name).Select(sim =>
                    {
                        sim.Status = service.GetActualStatus(sim, false);
                        return SimulationResponse.Create(sim);
                    }).ToArray());
                }
                catch (Exception ex)
                {
                    Debug.LogException(ex);
                    return(Response.AsJson(new { error = $"Failed to list simulations: {ex.Message}" }, HttpStatusCode.InternalServerError));
                }
            });

            Get("/{id:long}", x =>
            {
                long id = x.id;
                Debug.Log($"Getting simulation with id {id}");
                try
                {
                    var simulation = service.Get(id, this.Context.CurrentUser.Identity.Name);
                    if (simulation.TimeOfDay.HasValue)
                    {
                        simulation.TimeOfDay = DateTime.SpecifyKind(simulation.TimeOfDay.Value, DateTimeKind.Utc);
                    }
                    simulation.Status = service.GetActualStatus(simulation, false);
                    return(SimulationResponse.Create(simulation));
                }
                catch (IndexOutOfRangeException)
                {
                    Debug.Log($"Simulation with id {id} does not exist");
                    return(Response.AsJson(new { error = $"Simulation with id {id} does not exist" }, HttpStatusCode.NotFound));
                }
                catch (Exception ex)
                {
                    Debug.LogException(ex);
                    return(Response.AsJson(new { error = $"Failed to get simulation with id {id}: {ex.Message}" }, HttpStatusCode.InternalServerError));
                }
            });

            Post("/", x =>
            {
                Debug.Log($"Adding new simulation");
                try
                {
                    var req = this.BindAndValidate <SimulationRequest>();
                    if (!ModelValidationResult.IsValid)
                    {
                        var message = ModelValidationResult.Errors.First().Value.First().ErrorMessage;
                        Debug.Log($"Wrong request: {message}");
                        return(Response.AsJson(new { error = $"Failed to add simulation: {message}" }, HttpStatusCode.BadRequest));
                    }

                    var simulation = req.ToModel(this.Context.CurrentUser.Identity.Name);

                    simulation.Status = service.GetActualStatus(simulation, true);
                    if (simulation.Status != "Valid")
                    {
                        throw new Exception($"Simulation is invalid");
                    }

                    simulation.Status = service.GetActualStatus(simulation, false);
                    long id           = service.Add(simulation);
                    Debug.Log($"Simulation added with id {id}");
                    simulation.Id = id;

                    SIM.LogWeb(SIM.Web.SimulationAddName, simulation.Name);
                    try
                    {
                        SIM.LogWeb(SIM.Web.SimulationAddMapName, mapService.Get(simulation.Map.Value, this.Context.CurrentUser.Identity.Name).Name);

                        if (simulation.Vehicles != null)
                        {
                            foreach (var vehicle in simulation.Vehicles)
                            {
                                var vehicleModel = vehicleService.Get(vehicle.Vehicle, this.Context.CurrentUser.Identity.Name);
                                SIM.LogWeb(SIM.Web.SimulationAddVehicleName, vehicleModel.Name);
                                SIM.LogWeb(SIM.Web.SimulationAddBridgeType, vehicleModel.BridgeType);
                            }
                        }

                        SIM.LogWeb(SIM.Web.SimulationAddAPIOnly, simulation.ApiOnly.ToString());
                        SIM.LogWeb(SIM.Web.SimulationAddInteractiveMode, simulation.Interactive.ToString());
                        SIM.LogWeb(SIM.Web.SimulationAddHeadlessMode, simulation.Headless.ToString());
                        try
                        {
                            SIM.LogWeb(SIM.Web.SimulationAddClusterName, clusterService.Get(simulation.Cluster.Value, this.Context.CurrentUser.Identity.Name).Name);
                        }
                        catch { };
                        SIM.LogWeb(SIM.Web.SimulationAddUsePredefinedSeed, simulation.Seed.ToString());
                        SIM.LogWeb(SIM.Web.SimulationAddEnableNPC, simulation.UseTraffic.ToString());
                        SIM.LogWeb(SIM.Web.SimulationAddRandomPedestrians, simulation.UsePedestrians.ToString());
                        SIM.LogWeb(SIM.Web.SimulationAddTimeOfDay, simulation.TimeOfDay.ToString());
                        SIM.LogWeb(SIM.Web.SimulationAddRain, simulation.Rain.ToString());
                        SIM.LogWeb(SIM.Web.SimulationAddWetness, simulation.Wetness.ToString());
                        SIM.LogWeb(SIM.Web.SimulationAddFog, simulation.Fog.ToString());
                        SIM.LogWeb(SIM.Web.SimulationAddCloudiness, simulation.Cloudiness.ToString());
                    }
                    catch { };

                    return(SimulationResponse.Create(simulation));
                }
                catch (Exception ex)
                {
                    Debug.LogException(ex);
                    return(Response.AsJson(new { error = $"Failed to add simulation: {ex.Message}" }, HttpStatusCode.InternalServerError));
                }
            });

            Put("/{id:long}", x =>
            {
                long id = x.id;
                Debug.Log($"Updating simulation with id {id}");
                try
                {
                    var req = this.BindAndValidate <SimulationRequest>();
                    if (!ModelValidationResult.IsValid)
                    {
                        var message = ModelValidationResult.Errors.First().Value.First().ErrorMessage;
                        Debug.Log($"Wrong request: {message}");
                        return(Response.AsJson(new { error = $"Failed to update simulation: {message}" }, HttpStatusCode.BadRequest));
                    }

                    var original = service.Get(id, Context.CurrentUser.Identity.Name);

                    var simulation = req.ToModel(original.Owner);
                    simulation.Id  = id;

                    simulation.Status = service.GetActualStatus(simulation, true);
                    if (simulation.Status != "Valid")
                    {
                        throw new Exception($"Simulation is invalid");
                    }

                    simulation.Status = service.GetActualStatus(simulation, false);
                    int result        = service.Update(simulation);

                    SIM.LogWeb(SIM.Web.SimulationEditName, simulation.Name);
                    try
                    {
                        SIM.LogWeb(SIM.Web.SimulationEditMapName, mapService.Get(simulation.Map.Value, this.Context.CurrentUser.Identity.Name).Name);

                        if (simulation.Vehicles != null)
                        {
                            foreach (var vehicle in simulation.Vehicles)
                            {
                                try
                                {
                                    var vehicleModel = vehicleService.Get(vehicle.Vehicle, this.Context.CurrentUser.Identity.Name);
                                    SIM.LogWeb(SIM.Web.SimulationEditVehicleName, vehicleModel.Name);
                                    SIM.LogWeb(SIM.Web.SimulationEditBridgeType, vehicleModel.BridgeType);
                                }
                                catch
                                {
                                }
                            }
                        }

                        SIM.LogWeb(SIM.Web.SimulationEditAPIOnly, simulation.ApiOnly.ToString());
                        SIM.LogWeb(SIM.Web.SimulationEditInteractiveMode, simulation.Interactive.ToString());
                        SIM.LogWeb(SIM.Web.SimulationEditHeadlessMode, simulation.Headless.ToString());
                        try
                        {
                            SIM.LogWeb(SIM.Web.SimulationEditClusterName, clusterService.Get(simulation.Cluster.Value, this.Context.CurrentUser.Identity.Name).Name);
                        }
                        catch { };
                        SIM.LogWeb(SIM.Web.SimulationEditUsePredefinedSeed, simulation.Seed.ToString());
                        SIM.LogWeb(SIM.Web.SimulationEditEnableNPC, simulation.UseTraffic.ToString());
                        SIM.LogWeb(SIM.Web.SimulationEditRandomPedestrians, simulation.UsePedestrians.ToString());
                        SIM.LogWeb(SIM.Web.SimulationEditTimeOfDay, simulation.TimeOfDay.ToString());
                        SIM.LogWeb(SIM.Web.SimulationEditRain, simulation.Rain.ToString());
                        SIM.LogWeb(SIM.Web.SimulationEditWetness, simulation.Wetness.ToString());
                        SIM.LogWeb(SIM.Web.SimulationEditFog, simulation.Fog.ToString());
                        SIM.LogWeb(SIM.Web.SimulationEditCloudiness, simulation.Cloudiness.ToString());
                    }
                    catch
                    {
                    }

                    if (result > 1)
                    {
                        throw new Exception($"More than one simulation has id {id}");
                    }
                    else if (result < 1)
                    {
                        throw new IndexOutOfRangeException();
                    }

                    return(SimulationResponse.Create(simulation));
                }
                catch (IndexOutOfRangeException)
                {
                    Debug.Log($"Simulation with id {id} does not exist");
                    return(Response.AsJson(new { error = $"Simulation with id {id} does not exist" }, HttpStatusCode.NotFound));
                }
                catch (Exception ex)
                {
                    Debug.LogException(ex);
                    return(Response.AsJson(new { error = $"Failed to update simulation with id {id}: {ex.Message}" }, HttpStatusCode.InternalServerError));
                }
            });

            Delete("/{id:long}", x =>
            {
                long id = x.id;
                Debug.Log($"Removing simulation with id {id}");
                try
                {
                    int result = service.Delete(id, this.Context.CurrentUser.Identity.Name);
                    SIM.LogWeb(SIM.Web.SimulationDelete);
                    if (result > 1)
                    {
                        throw new Exception($"More than one simulation has id {id}");
                    }

                    if (result < 1)
                    {
                        throw new IndexOutOfRangeException();
                    }

                    return(new { });
                }
                catch (IndexOutOfRangeException)
                {
                    Debug.Log($"Simulation with id {id} does not exist");
                    return(Response.AsJson(new { error = $"Simulation with id {id} does not exist" }, HttpStatusCode.NotFound));
                }
                catch (Exception ex)
                {
                    Debug.LogException(ex);
                    return(Response.AsJson(new { error = $"Failed to remove simulation with id {id}: {ex.Message}" }, HttpStatusCode.InternalServerError));
                }
            });

            Post("/{id:long}/start", x =>
            {
                long id = x.id;
                Debug.Log($"Starting simulation with id {id}");
                try
                {
                    var current = service.GetCurrent(this.Context.CurrentUser.Identity.Name);
                    if (current != null)
                    {
                        throw new Exception($"Simulation with id {current.Id} is already running");
                    }

                    var simulation = service.Get(id, this.Context.CurrentUser.Identity.Name);
                    if (service.GetActualStatus(simulation, false) != "Valid")
                    {
                        simulation.Status = "Invalid";
                        service.Update(simulation);

                        throw new Exception("Cannot start an invalid simulation");
                    }

                    service.Start(simulation);
                    SIM.LogWeb(SIM.Web.WebClick, "SimulationStart");
                    return(new { });
                }
                catch (IndexOutOfRangeException)
                {
                    Debug.Log($"Simulation with id {id} does not exist");
                    return(Response.AsJson(new { error = $"Simulation with id {id} does not exist" }, HttpStatusCode.NotFound));
                }
                catch (Exception ex)
                {
                    Debug.LogException(ex);
                    return(Response.AsJson(new { error = $"Failed to start simulation with id {id}: {ex.Message}" }, HttpStatusCode.InternalServerError));
                }
            });

            Post("/{id:long}/stop", x =>
            {
                long id = x.id;
                Debug.Log($"Stopping simulation with id {id}");
                try
                {
                    var simulation = service.GetCurrent(this.Context.CurrentUser.Identity.Name);
                    if (simulation == null || simulation.Id != id)
                    {
                        throw new Exception($"Simulation with id {id} is not running");
                    }

                    service.Stop();
                    SIM.LogWeb(SIM.Web.WebClick, "SimulationStop");
                    return(new { });
                }
                catch (Exception ex)
                {
                    Debug.LogException(ex);
                    return(Response.AsJson(new { error = $"Failed to stop simulation with id {id}: {ex.Message}" }, HttpStatusCode.InternalServerError));
                }
            });
        }