/*
 *  TnNavSimRouteData.h
 *  OpenGL Map Engine
 *
 *  Copyright 2013 TeleNav Inc. All rights reserved.
 *
 *  The engine calls RequestRoute in response to a NewRoute
 *  notify event. At that point the client is expected to feed the
 *  route data into the ITnMapRouteData object.
 *
 *  The purpose of the generic route proxy is to allow the client to
 *  feed in the route data before invoking the notify event.
 *
 *  The routes are double-buffered. The routes currently being fed in
 *  by the client are stored in m_routesFeeding. When the client calls
 *  SetRequestResult, the set of routes is thread-safely copied to
 *  m_routes, and m_routesFeeding is cleared.
 *
 *  When the engine calls RequestRoute, whatever routes happen to be
 *  in m_routes at the time is delivered to the engine.
 *
 */

#ifndef TN_MAP_GENERIC_ROUTE_PROXY_H
#define TN_MAP_GENERIC_ROUTE_PROXY_H

#include <deque>
#include <string>

#include <foundation/Mutex.h>

#include <RenderEngine/ITnMapRouteProxy.h>

class TnGenericRouteProxy : public ITnMapRouteProxy
{
public:
    typedef Tn::Foundation::shared_ptr<TnGenericRouteProxy> ptr;
    
    // ITnMapRouteProxy
    virtual void RequestRoute(ITnMapRouteData::ptr const & data);
    virtual void RequestRoute(std::string const & name,
                              ITnMapRouteData::ptr const & data);
    
    // ITnMapRouteProxyControl
    void Clear();
    void NewRoute(std::string const & name,
                  std::string const & style,
                  TnMapArrowParams const & arrowParams);
    void NewSegment();
    void NewSegment(TnMapArrowParams const & arrowParams);
    void NewEdge();
    void NewEdge(std::string const & style);
    void AddPoint(double degreesLatitude, double degreesLongitude, double metersHeight);
    void SetRequestResult(eTnMapRequestResult result);
    
private:
    struct RoutePoint
    {
        double lat;
        double lon;
        double alt;
    };
    
    struct RouteEdge {
        std::string style;
        std::deque<RoutePoint> points;
    };
    
    struct RouteSegment : public std::deque<RouteEdge>
    {
        RouteSegment(TnMapArrowParams const & arrowParams) :
            std::deque<RouteEdge>(),
            arrowParams(arrowParams) {}

        TnMapArrowParams arrowParams;
    };

    typedef std::deque<RouteSegment> RouteSegments;
    
    struct Route
    {
        Route(std::string const & name,
              std::string const & style,
              TnMapArrowParams const & arrowParams) :
        name(name),
        style(style),
        arrowParams(arrowParams) {}
        
        RouteSegments segments;
        std::string name;
        std::string style;
        TnMapArrowParams arrowParams;
    };

    void ProcessRoute(Route const & route, 
                      ITnMapRouteData::ptr const & data);

private:
    typedef std::deque<Route> Routes;

    // Container of routes
    Routes m_routes;
    Routes m_routesFeeding;

    Tn::Foundation::mutex m_mutex;
};

#endif
