/*
 *  TnNetworkResourceProxy.h
 *  Map Rendering Engine Proxy Common
 *
 *  Created by Thant on 03/25/2013
 *  Copyright 2013 TeleNav Inc. All rights reserved.
 *
 */

#ifndef TN_NETWORK_RESOURCE_PROXY_H
#define TN_NETWORK_RESOURCE_PROXY_H

#include <map>
#include <foundation/TnTypes.h>
#include <RenderEngine/ITnMapResourceProxy.h>
#include <GenericProxy/TnCache.h>
#include <TnUrl.h>
#include <boost/threadpool.hpp>
#include <foundation/Util/TnThreadSafeQueue.h>


class TnUrlWithProxy 
{
public:

    typedef Tn::Foundation::shared_ptr<TnUrlWithProxy> ptr;

    TnUrlWithProxy();
    
    bool Synchronized(size_t syncId) const;
    void Set(size_t syncId);
    void Set(size_t syncId,
             std::string const & httpProxyUrl,
             int httpProxyPort,
             std::string const & httpProxyAccount,
             std::string const & httpProxyPassword);
    
    Tn::Foundation::shared_ptr<TnUrl> const & URL() const { return m_url; }
private:
    Tn::Foundation::mutex m_mutex;
    Tn::Foundation::shared_ptr<TnUrl> m_url;
    size_t  m_syncId;
};








class TnNetworkResourceProxy : public ITnMapResourceProxy
{
public:

    typedef Tn::Foundation::shared_ptr<TnNetworkResourceProxy> ptr;

    static ptr Create(size_t threadCount);
    virtual ~TnNetworkResourceProxy();

    // ITnMapResourceProxy

    // TnNetworkResourceProxy doesn't support prefetch. (That's
    // TnCachingNetworkResourceProxy's job.)

    virtual bool PrefetchSupported(std::string const & cacheName) const;
    virtual void RequestResourcePrefetch(std::string const & url, std::string const & cacheName, uint32_t priority);
    virtual bool RequestResourceSynchronously(ITnMapResourceData::ptr const & data);

    virtual void RequestResource(ITnMapResourceData::ptr const & data, uint32_t priority);
    virtual void CancelRequest(ITnMapResourceData::ptr const & data);


    virtual void EnableHttpProxy(const std::string & url, 
                                 int port, 
                                 const std::string & name = "", 
                                 const std::string & password = "");
    virtual void DisableHttpProxy();

    bool IsPending(std::string const & name);

    // This is currently called only by the destructur, but it might
    // make sense to expose this.
    void CancelAll();

private:

    TnNetworkResourceProxy(size_t threadCount);
    /* Parse HTTP headers and check whether we may cache this, and if so, for how long.
     */
    boost::optional<time_t> FindExpirationDate(std::vector<std::string> const & headers) const;

    void AddToPending(ITnMapResourceData::ptr const & request);
    void RemoveFromPending(ITnMapResourceData::ptr const & request);

    void AddToThreadPool(ITnMapResourceData::ptr const & data, uint32_t priority);
    // Thread entry point
    void HandleRequest(ITnMapResourceData::ptr const & data);
    void HandleUrl(ITnMapResourceData::ptr const & request,
                   Tn::Foundation::shared_ptr<TnUrl> const & url) const;


    size_t m_numThreadsPerPool;
    
    typedef boost::threadpool::thread_pool<boost::threadpool::prio_task_func,
                                           boost::threadpool::prio_scheduler,
                                           boost::threadpool::static_size,
                                           boost::threadpool::resize_controller,
                                           boost::threadpool::wait_for_active_tasks>   prio_pool_shutdown;
    
    typedef std::map<std::string, Tn::Foundation::shared_ptr<prio_pool_shutdown> > ThreadPoolMap;
    ThreadPoolMap m_threadpoolMap;
    Tn::Foundation::mutex m_mutex;

    // Proxy info
    size_t m_syncId;
    bool m_usingHttpProxy;
    std::string m_httpProxyUrl;
    int m_httpProxyPort;
    std::string m_httpProxyAccount;
    std::string m_httpProxyPassword;

    // Collection of sent resource loads. We don't need a TnPruningMap
    // here because the threads themselves remove the items from the
    // Sent map after the fetch.
    typedef std::map<ITnMapResourceData::ptr, Tn::Foundation::shared_ptr<TnUrl> > Sent;
    typedef std::pair<ITnMapResourceData::ptr, Tn::Foundation::shared_ptr<TnUrl> > SentEntry;
    Sent m_sent;

    typedef std::multiset<std::string> Pending;
    Pending m_pending;

    TnThreadSafeQueue<TnUrlWithProxy::ptr> m_urlQueue;

    uint32_t m_defaultAge;
    
    bool m_shutdown;
};

#endif
