void elevator_system_drawer::draw_system(Wt::WPainter& painter, options_t const& options)
	{
//		boost::lock_guard< async_system_drawer > guard(*this);

		size_t Margin = 10;

		painter.save();
		Wt::WPaintDevice* device = painter.device();

		Wt::WLength dev_width = device->width();
		Wt::WLength dev_height = device->height();
		
		double pix_width = dev_width.toPixels() - 2 * Margin;
		double pix_height = dev_height.toPixels() - 2 * Margin;
		auto avail_aspect = pix_width / pix_height;

		if(avail_aspect > DisplayAspect)
		{
			pix_width = pix_height * DisplayAspect;
		}
		else
		{
			pix_height = pix_width / DisplayAspect;
		}

		auto x_margin = (dev_width.toPixels() - pix_width) / 2.0;
		auto y_margin = (dev_height.toPixels() - pix_height) / 2.0;
		painter.setViewPort(
			x_margin,
			y_margin,
			pix_width,
			pix_height
			);
		painter.setWindow(
			0.0,
			0.0,
			pix_width,
			pix_height
			);

		set_pixel_multiplier(pix_height);

		auto const& st = m_sys.m_state;

		const auto entry_width = get_entry_width(SizeFormat::Pixels);
		const auto exit_width = get_exit_width(SizeFormat::Pixels);
		const auto door_gap = get_door_gap_width(SizeFormat::Pixels);
		const auto elevator_width = get_elevator_width(SizeFormat::Pixels);

		// On floor side
		Wt::WRectF rc_all_on_floors(
			0.0,
			0.0,
			entry_width,
			pix_height
			);
		draw_all_floors(painter, rc_all_on_floors);

		// Elevator shaft
		Wt::WRectF rc_shaft(entry_width + door_gap, 0.0, elevator_width, pix_height);
		draw_elevator(painter, rc_shaft);

		// Off floor side
		Wt::WRectF rc_all_off_floors(
			pix_width - exit_width,
			0.0,
			exit_width,
			pix_height
			);
		draw_all_floors(painter, rc_all_off_floors);

		// Queues
		draw_all_queues(painter, rc_all_on_floors);

		switch(m_stage)
		{
			case AnimationStage::Arrivals:
			draw_arrivals(painter, rc_all_on_floors);
			break;

			case AnimationStage::GettingOn:
			draw_getting_on(painter, rc_all_on_floors);
			break;

			case AnimationStage::GettingOff:
			draw_getting_off(painter, rc_all_off_floors);
			break;
		}

		/////
		Wt::WFont font = painter.font();
		font.setSize(30);
		painter.setFont(font);
		painter.drawText(
			Wt::WRectF(0.0, 0.0, 100.0, 30.0),
			Wt::AlignLeft | Wt::AlignTop,
			std::to_string((int)m_stage) + " / " + std::to_string(m_stage_step)
			);
		/////

		painter.restore();

		reset_pixel_multiplier();
	}
		void phys2d_system_drawer::draw_system(Wt::WPainter& painter, options_t const& options)
		{
			size_t const Margin = 0;

			Wt::WPaintDevice* device = painter.device();

			Wt::WLength dev_width = device->width();
			Wt::WLength dev_height = device->height();
			size_t avail_size = (size_t)std::min(dev_width.toPixels() - 2 * Margin, dev_height.toPixels() - 2 * Margin);

			painter.save();

			Wt::WPen pen(Wt::GlobalColor::lightGray);
			painter.setPen(pen);

			double const scale = (avail_size / 25.0) * options.zoom;

			size_t const GridDim = 5;
			double const GridSquareSize = avail_size / GridDim;

			// TODO: Hack - locking onto first agent
//			auto agent_ptr = dynamic_cast<object const*>(m_sys.m_agents.front().agent.get());
			b2Vec2 grid_ref_pos = b2Vec2(0, 0);//agent_ptr->get_position();

			double x_off = std::fmod(-grid_ref_pos.x * scale, GridSquareSize);
			if(x_off < 0.0)
			{
				x_off += GridSquareSize;
			}
			double y_off = std::fmod(-grid_ref_pos.y * -scale, GridSquareSize);
			if(y_off < 0.0)
			{
				y_off += GridSquareSize;
			}

			for(size_t i = 0; i < dev_width.toPixels() / GridSquareSize; ++i)
			{
				painter.drawLine(
					x_off + i * GridSquareSize,
					0.0,
					x_off + i * GridSquareSize,
					dev_height.toPixels()
					);
			}

			for(size_t i = 0; i < dev_height.toPixels() / GridSquareSize; ++i)
			{
				painter.drawLine(
					0.0,
					y_off + i * GridSquareSize,
					dev_width.toPixels(),
					y_off + i * GridSquareSize
					);
			}

			painter.translate(dev_width.toPixels() / 2, dev_height.toPixels() / 2);
			painter.scale(scale, -scale);
			painter.translate(-grid_ref_pos.x, -grid_ref_pos.y);

			pen = Wt::WPen(Wt::GlobalColor::black);
			painter.setPen(pen);
			Wt::WBrush br(Wt::GlobalColor::white);
			painter.setBrush(br);

			painter.save();

			auto world = m_sys.get_world();
			auto body = world->GetBodyList();
			while(body)
			{
				draw_body(body, painter);

				body = body->GetNext();
			}

			/* TODO: maybe use visitor pattern for entity specific drawing
			http://programmers.stackexchange.com/questions/185525/design-pattern-for-polymorphic-behaviour-while-allowing-library-separation

			m_sys.m_scenario->draw_fixed_objects(painter);

			//phys_system::const_agent_range agents = m_sys.get_agent_range();
			//for(auto it = agents.first; it != agents.second; ++it)
			for(auto const& agent : m_sys.m_agents)
			{
				//(*it)->draw(painter);
				agent.agent->draw(painter);
			}
*/
			painter.restore();
			painter.restore();

			Wt::WFont font = painter.font();
			//font.setFamily(Wt::WFont::Default);
			font.setSize(20);
			painter.setFont(font);
			pen.setColor(Wt::GlobalColor::blue);
			painter.setPen(pen);
			auto rc = Wt::WRectF(
				0,
				0,
				dev_width.toPixels(),
				30
				);
			std::stringstream text;
			text.precision(2);
			std::fixed(text);
			text << m_sys.get_time() << "s";
			painter.drawText(rc, Wt::AlignLeft | Wt::AlignMiddle, text.str());
		}