# the TestEnv environment is used to simply simulate the network
from flow.envs import TestEnv

# the Experiment class is used for running simulations
from flow.core.experiment import Experiment

# the base scenario class
from flow.scenarios import Scenario

# all other imports are standard
from flow.core.params import VehicleParams
from flow.core.params import NetParams
from flow.core.params import InitialConfig
from flow.core.params import EnvParams

# create some default parameters parameters
env_params = EnvParams()
initial_config = InitialConfig()
vehicles = VehicleParams()
vehicles.add('human', num_vehicles=1)

"""
Explanation: Tutorial 08: Networks from Custom Templates
In the previous tutorial, we discussed how OpenStreetMap files can be simulated in Flow. These networks, however, may at time be imperfect, as we can see in the toll section of the Bay Bridge (see the figure below). The simulators SUMO and Aimsun both possess methods for augmenting the network after they have been imported, and store the changes in their own versions of the initial template (whether it was generated via a custom scenario class or a network imported from OpenStreetMap). In order to utilize these newly generated networks, we demonstrate in this tutorial how simulator-generated template files can be imported when running a simulation in Flow. 
<img src="img/osm_to_template.png">
<center> Figure 1: Example benefit of converting OpenStreetMap to a custom template </center>
The remainder of the tutorial is organized as follows. In section 1, we begin by importing the classic set of parameters. In section 2, we introduce the template files that are used as examples for importing the template files. In section 3, we present how custom SUMO network templates, i.e. the generated .net.xml files, can be modified and simulated in Flow for the purposed of improving network features. Finally, in section 4, we demonstrate how custom Aimsun network files can be simulated in Flow.
1. Importing Modules
Before we begin, let us import all relevant Flow parameters as we have done for previous tutorials. If you are unfamiliar with these parameters, you are encouraged to review tutorial 1.
End of explanation
"""


LuST_dir = "/home/aboudy/LuSTScenario"

"""
Explanation: 2. Example Network
In this tutorial, we use the Luxembourg SUMO Traffic (LuST) Scenario as an example use case. This example consists of a well-calibrated model of vehicles in Luxembourg. A representation of the simulation can be seen in the figure below.
<img src="img/LuST_network.png" width="500">
<center><b>Figure 2</b>: Simulation of the LuST network </center>
Before, continuing with this tutorial, please begin by cloning the LuST scenario repository by running the following command.
git clone https://github.com/lcodeca/LuSTScenario.git

Once you have cloned the repository, please modify the code snippet below to match correct location of the repository's main directory.
End of explanation
"""


from flow.core.params import SumoParams

sim_params = SumoParams(render=True, sim_step=1)

"""
Explanation: 3. Sumo Network Files
Sumo generates several network and simulation-specifc template files prior to starting a simulation. This procedure when creating custom scenarios and scenarios from OpenStreetMap is covered by the scenario class. Three of these files (*.net.xml, *.rou.xml, and vtype.add.xml) can be imported once again via the scenario class to recreate a previously decided scenario.
We start by creating the simulation parameters:
End of explanation
"""


import os

net_params = NetParams(
    template=os.path.join(LuST_dir, "scenario/lust.net.xml"),
)

"""
Explanation: 3.1 Importing Network (*.net.xml) Files
The *.net.xml file covers the network geometry within a simulation, and can be imported independently of the SUMO route file (see section 1.2). This can be done through the template parameter within NetParams as follows:
End of explanation
"""


# specify the edges vehicles can originate on
initial_config = InitialConfig(
    edges_distribution=["-32410#3"]
)


# specify the routes for vehicles in the network
class TemplateScenario(Scenario):

    def specify_routes(self, net_params):
        return {"-32410#3": ["-32410#3"]}

"""
Explanation: This network alone, similar to the OpenStreetMap file, does not cover the placement of vehicles or the routes vehicles can traverse. These, however, can be defined a they were in the previous tutorial for importing networks from OpenStreetMap. For the LuST network, this looks something similar to the following code snippet (note that the specific edges were not spoken for any specific reason).
End of explanation
"""


# create the scenario
scenario = TemplateScenario(
    name="template",
    net_params=net_params,
    initial_config=initial_config,
    vehicles=vehicles
)

# create the environment
env = TestEnv(
    env_params=env_params,
    sim_params=sim_params,
    scenario=scenario
)

# run the simulation for 1000 steps
exp = Experiment(env=env)
_ = exp.run(1, 1000)

"""
Explanation: The simulation can then be executed as follows:
End of explanation
"""


new_net_params = NetParams(
    template={
        # network geometry features
        "net": os.path.join(LuST_dir, "scenario/lust.net.xml")
    }
)

"""
Explanation: 3.2 Importing Additional Files
Sumo templates will at times contain files other than the network templates that can be used to specify the positions, speeds, and properties of vehicles at the start of a simulation, as well as the departure times of vehicles while the scenario is running and the routes that all these vehicles are meant to traverse. All these files can also be imported under the template attribute in order to recreate the simulation in it's entirety.
When incorporating files other that the net.xml file to the simulation, the template attribute is treated as a dictionary instead, with a different element for each of the additional files that are meant to be imported. Starting with the net.xml file, it is added to the template attribute as follows:
End of explanation
"""


new_net_params = NetParams(
    template={
        # network geometry features
        "net": os.path.join(LuST_dir, "scenario/lust.net.xml"),
        # features associated with the properties of drivers
        "vtype": os.path.join(LuST_dir, "scenario/vtype.add.xml")
    }
)

# we no longer need to specify anything in VehicleParams
new_vehicles = VehicleParams()

"""
Explanation: 3.2.1 Vehicle Type (vtype.add.xml)
The vehicle types file describing the properties of different vehicle types in the network. These include parameters such as the max acceleration and comfortable deceleration of drivers. This file can be imported via the "vtype" attribute in template.
Note that, when vehicle information is being imported from a template file, the VehicleParams object does not need be modified, unless you would like additionally vehicles to enter the network as well.
End of explanation
"""


new_net_params = NetParams(
    template={
        # network geometry features
        "net": os.path.join(LuST_dir, "scenario/lust.net.xml"),
        # features associated with the properties of drivers
        "vtype": os.path.join(LuST_dir, "scenario/vtypes.add.xml"),
        # features associated with the routes vehicles take
        "rou": [os.path.join(LuST_dir, "scenario/DUARoutes/local.0.rou.xml"),
                os.path.join(LuST_dir, "scenario/DUARoutes/local.1.rou.xml"),
                os.path.join(LuST_dir, "scenario/DUARoutes/local.2.rou.xml")]
    }
)

# we no longer need to specify anything in VehicleParams
new_vehicles = VehicleParams()

"""
Explanation: 3.2.2 Route (*.rou.xml)
Next, the routes can be imported from the *.rou.xml files that are generated by SUMO. These files help define which cars enter the network at which point in time, whether it be at the beginning of a simulation or some time during it run. The route files are passed to the "rou" key in the templates attribute. Moreover, since the vehicle routes can be spread over multiple files, the "rou" key that a list of string filenames.
End of explanation
"""


# create the scenario
scenario = Scenario(
    name="template",
    net_params=new_net_params,
    vehicles=new_vehicles
)

# create the environment
env = TestEnv(
    env_params=env_params,
    sim_params=sim_params,
    scenario=scenario
)

# run the simulation for 100000 steps
exp = Experiment(env=env)
_ = exp.run(1, 100000)

"""
Explanation: 3.2.3 Running the Modified Simulation
Finally, the fully imported simulation can be run as follows. 
Warning: the network takes time to initialize while the departure positions and times and vehicles are specified.
End of explanation
"""


from flow.core.params import AimsunParams

sim_params = AimsunParams(
    sim_step=0.1,
    render=True,
    emission_path='data',
    replication_name="Replication 930",
    centroid_config_name="Centroid Configuration 910"
)

"""
Explanation: 4. Aimsun Network Files
Flow can run templates that have been created in Aimsun and saved into an *.ang file. Although it is possible to have control over the network, for instance add vehicles and monitor them directly from Flow, this tutorial only covers how to run the network.
We will use the template located at tutorials/networks/test_template.ang, which looks like this:
<img src="img/test_template.png">
<center><b>Figure 2</b>: Simulation of <code>test_template.ang</code> in Aimsun</center>
It contains two input and three output centroids that define the centroid configuration Centroid Configuration 910. The inflows are defined by two OD matrices, one for the type Car (in blue), the other for the type rl (in red). Note that there is no learning in this tutorial so the two types both act as regular cars. The two OD matrices form the traffic demand Traffic Demand 925 that is used by the scenario Dynamic Scenario 927. Finally, the experiment Micro SRC Experiment 928 and the replication Replication 930 are created, and we will run this replication in the following.
First, we create the Aimsun-specific simulation parameters:
End of explanation
"""


import os
import flow.config as config

net_params = NetParams(
    template=os.path.join(config.PROJECT_PATH,
                          "tutorials/networks/test_template.ang")
)

"""
Explanation: As you can see, we need to specify the name of the replication we want to run as well as the centroid configuration that is to be used. There is an other optional parameter, subnetwork_name, that can be specified if only part of the network should be simulated. Please refer to the documentation for more information. 
The template can then be imported as follows:
End of explanation
"""


scenario = Scenario(
    name="template",    
    net_params=net_params,
    initial_config=initial_config,
    vehicles=vehicles
)

env = TestEnv(
    env_params, 
    sim_params, 
    scenario, 
    simulator='aimsun' 
)

exp = Experiment(env)
exp.run(1, 1000)

"""
Explanation: Finally, we can run the simulation by specifying 'aimsun' as the simulator to be used:
End of explanation
"""


