def _init_plots(self):
     self.sample_frequency = int(constants.plot_sample_frequency/self.timestep)
     self.plots = Plots(self.sample_frequency, self.parameters)
     self.create_plots = True
     self.plot_prefix = os.path.join(constants.plot_dir, self.parameters['name'])
class Scenario:
    """Parameters:
            'A'                  : A constant (see model)
            'B'                  : B constant (see model)
            'U'                  : U constant (see model)
            'lambda'             : lambda constant (see model)
            'initial_count'      : initial number of pedestrians to spawn
            'start_areas'        : rectangles pedestrians can spawn in (as quadruplets)
            'velocity_mean'      : mean value for initial pedestrian velocity
            'velocity_deviation' : deviation for initial pedestrian velocity
            'max_velocity_factor': max_velocity = initial_velocity * max_velocity_factor
            'radius_mean'        : mean value for radii
            'radius_deviation'   : deviation for radii
            'targets'            : list of targets pedestrians should move towards (randomly 
                                   distributed between multiple targets)
            'density_rectangle'  : rectangle to measure density within (quadruplet)
            'flowrate_line'      : line to measure flow at (quadruplet start + end)
            'continuous_rate'    : rate to spawn pedestrians throughout the simulation
            'continuous_start'   : lines to spawn new pedestrians at. start line i will move
                                   towards target i
            'stop_at'            : time to end the simulation at
            'random_seed'        : seed for the random number generator
            'walls'              : list of wall quadruplets
            'drawing_width'      : width for drawing images
            'drawing_height'     : height for drawing images
            'pixel_factor'       : number of pixels pr metre
            'relax_time'         : relaxation time for pedestrians
            'vary_parameters'    : dictionary of parameter names mapped to a tuple of
                                   interval start, interval end, stepsize for running
                                   multiple simulations varying each parameter"""

    def __init__(self, parameters = {}):
        self.parameters = parameters
        if not "random_seed" in self.parameters:
            self.parameters["random_seed"] = constants.random_seed

        if not "flowrate_lines" in self.parameters:
            self.parameters["flowrate_lines"] = [self.parameters["flowrate_line"]] 

        self.timestep = constants.timestep
        self.run_time = datetime.now()
        self.parameters['run_time'] = self.run_time.strftime("%Y-%m-%d %H:%M:%S")
        self.parameters['timestep'] = self.timestep

        self.average_desired_velocity = 0.0
        self.spawn_count = 0.0

        self.create_images = False
        self.create_plots = False
        self.spawning = False

    def run(self, options):
        self.options   = options
        self.drawing   = options.create_images or options.show_simulation
        self.aggregate = options.aggregate

        if options.create_images:
            self._init_images()
        if options.create_plots:
            self._init_plots()

        if self.parameters['continuous_rate'] is not None:
            self.spawning = True

        if self.aggregate:
            self._run_aggregate()
        else:
            self._run()

    def _init_drawing(self):
        if self.options.show_simulation:
            self.show_canvas = image_canvas(
                    self.parameters['drawing_width'],
                    self.parameters['drawing_height'],
                    self.parameters['pixel_factor'],
                    os.path.join(constants.image_dir, self.parameters['name']),
                    )
        if self.options.create_images:
            if self.options.tikz:
                self.image_canvas = tikz_canvas(
                        self.parameters['drawing_width'],
                        self.parameters['drawing_height'],
                        self.parameters['pixel_factor'],
                        os.path.join(constants.image_dir, self.parameters['name']),
                        )
            else:
                if self.options.show_simulation:
                    self.image_canvas = self.show_canvas
                else:
                    self.image_canvas = image_canvas(
                            self.parameters['drawing_width'],
                            self.parameters['drawing_height'],
                            self.parameters['pixel_factor'],
                            os.path.join(constants.image_dir, self.parameters['name']),
                            )


    def _uninit_drawing(self):
        self._canvas("quit")

    def _init_images(self):
        pfile = open("%s-parameters" % os.path.join(constants.image_dir, 
            self.parameters['name']), "w")
        pfile.write(pprint.pformat(self.parameters))
        pfile.write("\n")
        pfile.close()
        self.create_images = True

    def _init_plots(self):
        self.sample_frequency = int(constants.plot_sample_frequency/self.timestep)
        self.plots = Plots(self.sample_frequency, self.parameters)
        self.create_plots = True
        self.plot_prefix = os.path.join(constants.plot_dir, self.parameters['name'])


    def _create_pedestrians(self):
        desired_velocities = []
        for a in setup.generate_pedestrians(self.parameters, 
                self.parameters['start_areas'], self.parameters['initial_count']):
            desired_velocities.append(a['initial_desired_velocity'])
            optimised.add_pedestrian(a)

        self.average_desired_velocity = np.average(desired_velocities)

    def _tick(self):
        if self.drawing:
            return self._canvas("tick", constants.framerate_limit)
        return True

    def _plot_sample(self):
        if not optimised.a_count:
            return
        (x1, y1, x2, y2) = self.parameters['density_rectangle']
        density_c = 0
        density = 0.0
        density_area = (y2-y1)*(x2-x1)
        velocities = list()
        for i in xrange(optimised.a_count):
            (x,y) = optimised.a_property(i, "position")
            r = optimised.a_property(i, "radius")
            velocities.append(optimised.a_property(i, "velocity"))
            if x+r >= x1 and x-r <= x2 and y+r >= y1 and y-r <= y2:
                density_c += 1

        flowrates = []
        for i in xrange(len(self.parameters["flowrate_lines"])):
            (x1,y1,x2,y2) = self.parameters["flowrate_lines"][i][:4]
            flow_length = math.sqrt((x2-x1)**2+(y2-y1)**2)
            flow_count = optimised.flow_count(i)
            flowrate = flow_count/constants.plot_sample_frequency/flow_length
            flowrates.append(flowrate)

        density = density_c / density_area
        self.plots.add_sample(self.time, 
                density=density,
                velocities=velocities, 
                flowrate=flowrates)

    def _canvas(self, method, *args):
        retval = True
        if self.options.create_images:
            retval = getattr(self.image_canvas, method)(*args)
        if self.options.show_simulation and (self.options.tikz or not self.options.create_images):
            return getattr(self.show_canvas, method)(*args) and retval
        return retval

    def _draw(self):
        self._canvas("clear_screen")
        for i in xrange(optimised.a_count):
            (x,y) = optimised.a_property(i, "position")
            r = optimised.a_property(i, "radius")
            t = optimised.a_property(i, "target")
            self._canvas("draw_pedestrian", x,y,r,t)

        self._canvas("draw_text", "t = %.2f" % self.time, not self.create_images)
        for t in self.parameters['targets']:
            self._canvas("draw_target", *t)
        for w in self.parameters['walls']:
            self._canvas("draw_wall", w)
        if self.options.show_simulation:
            self.show_canvas.update()
        if self.create_images:
            self.image_canvas.create_image(self.frames)

    def _aggregate(self, p_name, p_value):
        if self.create_plots:
            self.plots.add_aggregate(p_name, p_value, 
                    desired_velocity=self.average_desired_velocity,
                    leaving_time=self.time)

    def _spawn(self):
        spawn_rate = self.parameters['continuous_rate']
        self.spawn_count += self.timestep * spawn_rate
        spawn = 0
        while self.spawn_count > 1.0:
            spawn += 1
            self.spawn_count -= 1.0

        if spawn > 0:
            for a in setup.generate_pedestrians(self.parameters,
                    self.parameters['continuous_start'], spawn):
                optimised.add_pedestrian(a)


    def _done(self):
        stop_at = self.parameters['stop_at']
        return (stop_at is not None and self.time >= stop_at) or not optimised.a_count

    def _run_aggregate(self):
        for p in self.parameters['vary_parameters']:
            if not p in self.parameters:
                print "Cannot vary non-existing parameter: %s" % p
                return

            (start, stop, step) = self.parameters['vary_parameters'][p]
            print "Aggregate of %s values %.2f-%.2f" % (p, start, stop)
            orig_value = self.parameters[p]
            values = np.arange(start, stop+step, step)
            for v in values:
                print "%s=%.2f" % (p, v)
                self.parameters[p] = v
                success = self._run()
                if not success:
                    return
                self._aggregate(p,v)
            self.parameters[p] = orig_value

            if self.create_plots:
                self.plots.save_aggr(self.plot_prefix)
                self._init_plots()

    def _run(self):
        optimised.set_parameters(self.parameters)

        self.time = 0.0
        self.frames = 0
        self.start_time = time()

        if self.parameters["random_seed"] is not None:
            np.random.seed(self.parameters["random_seed"])
            random.seed(self.parameters["random_seed"])

        self._create_pedestrians()

        if self.drawing:
            self._init_drawing()

        success = False

        try:
            while self._tick():

                optimised.update_pedestrians()

                if self.spawning:
                    self._spawn()
                
                if self.drawing: 
                    self._draw()
                else:
                    output = "\r%d frames, t=%.2f" % (self.frames+1, self.time)
                    print output,

                if self.create_plots and not self.frames % self.sample_frequency:
                    self._plot_sample()

                self.time += self.timestep
                self.frames += 1

                if self._done():
                    success = True
                    break

        except KeyboardInterrupt:
            pass
        print

        elapsed = time() - self.start_time
        print "%d frames in %f seconds. Avg %f fps" % (self.frames, elapsed,
                self.frames/elapsed)

        if self.drawing:
            self._uninit_drawing()

        if self.options.create_plots and not self.aggregate:
            self.plots.save(self.plot_prefix)

        return success