/*! 
 *   \file  CInventory.h
 *   \brief Declares singleton class to hold inventory.
 *    
 *   \details  
 *   CInventory loads the inventory and keeps it in memory. 
 *
 *   \date      October 24, 2011
 *   \copyright eBay Research Labs.
 */

#pragma once

// Include boost-specific headers.
#include "boost/filesystem.hpp"   // Includes all needed Boost.Filesystem declarations
#include "boost/thread/mutex.hpp"
#include "boost/thread/recursive_mutex.hpp"
#include "boost/thread/locks.hpp"
#include "Defines.h"

// Include standard C++ headers.
#include <unordered_map>
#include <list>
#include "CSignature.h"
#include "CFeatureMapper.hpp" 

namespace bfs = boost::filesystem;

using std::unordered_map;

class CInventory
{
 public:
  typedef unordered_map < std::string, int >       CategoryIndexMap;
  typedef std::vector <CSignature*> SignatureVector;
  typedef boost::recursive_mutex Mutex;

  class Category {
  public:
    Category(const bfs::path& rootDir, int siteid);

    bool                        addItem(const std::string& i, const std::string& path);
    bool                        deleteItem(const std::string& id);

    const SignatureVector&      signatureVector() const { return m_itemSignatureVector; }
    Mutex&                      getMutex() const { return m_accessMutex; }
    const std::string&          getID() const { return m_categoryID; }
           

    size_t                      getNumberOfItems() const;

    void                        doLoad(std::istream& in);

  private:

    void                        clearMap();
    CSignature*                 LoadInventoryItem(std::istream&);

    int                         m_siteID;
    std::string                 m_categoryID;
    SignatureVector             m_itemSignatureVector;
    //    SignatureMap                m_itemSignatureMap;
    // mutex is mutable because we need lock for read access, too.
    mutable Mutex               m_accessMutex;
    bfs::path 		    	m_catPath;
    time_t                      m_currTime;

    Category(const Category& rhs);
    Category& operator=(const Category&); // { return *this; }

    void Dedupe();

    friend class CInventory;
  };

  typedef std::vector<Category*>   Categories;             

  ~CInventory();

  Mutex&                                      getMutex() const { return m_inventoryMutex; }
  Category*                                   getCategory(int i) const { return m_categories[i]; }
  Category*                                   getCategory(const std::string& cat) const; 

  const int                                   getNumericSiteID() const { return m_siteId; }

  static void                                 setRoot(const std::string& r) { s_root = r; } 

  int                                         getNumberOfCategories() const { return (int)m_categories.size(); } 		

  static CInventory*		              Instance(int siteid);

  int					      GetCategoryCount(void) const;

  bool					      IsLoaded(void) const;

  bool                                        LoadInventory(std::istream& in, const std::string& cat_id);

  Category*                                   createNewCategory(const std::string& cat);

  void                                        UpdateCache();

  bool					      LoadFtrMappers(const std::string& contextRootDir);
  CFeatureMapper*			      GetFtrMapper() const { return m_ftrMapper;}


 private:

  const int                                   m_siteId;
  Categories                                  m_categories;     // List of categories in inventory.
  CategoryIndexMap                            m_cat_map;
		
       
  // mutex is mutable because we need lock for read access, too.
  mutable Mutex                               m_inventoryMutex;

 private:    

  // protect ctor for singleton
  CInventory(int, const std::string& root);

  // singleton
  static CInventory*		        s_instance[];
		
  // members
  bool					m_isLoaded;
  CFeatureMapper   *m_ftrMapper;	  // Pointer to feature mapper class.
  static std::string s_root;
};

extern boost::recursive_mutex g_io_mutex;
