text: /*
   * BSD 3-Clause License
   *
   * Full text: https://opensource.org/licenses/BSD-3-Clause
   *
   * Copyright (c) 2018, Viktor Seib
   * All rights reserved.
   *
   */
  
  #ifndef ISM3D_CODEBOOK_H
  #define ISM3D_CODEBOOK_H
  
  #include "../utils/json_object.h"
  #include "../utils/utils.h"
  #include "../utils/ism_feature.h"
  #include "codeword.h"
  
  #include <list>
  #include <string>
  #include <fstream>
  #include <boost/shared_ptr.hpp>
  
  #include <flann/flann.h>
  
  #define PCL_NO_PRECOMPILE
  #include <pcl/point_types.h>
  #include <pcl/point_cloud.h>
  #include <pcl/io/pcd_io.h>
  
  namespace ism3d
  {
      class ActivationStrategy;
      class CodewordDistribution;
      class Distance;
      class Voting;
  
      /**
       * @brief The Codebook class
       * The codebook contains a list of codewords, each of which is associated with an activation
       * distribution. The distribution contains information about where on an object a codeword
       * may be found and is being generated by activating codewords with an activation strategy.
       * When the codewords have been computed, a second iteration over all the features compares
       * features with the codewords according to an activation strategy. Whenever a features activates
       * a codeword, the feature position on the object is stored as an entry in the activation
       * distribution.
       * During detection, the activation procedure finds the activation distribution for a matching
       * codeword and casts a vote into a voting space at the stored feature positions.
       */
      class Codebook
              : public JSONObject
      {
      public:
          Codebook();
          ~Codebook();
  
          /**
           * @brief Activate codewords with detected features based on the activation strategy.
           * @param codewords the codewords which shall be activated with the features
           * @param features the features for each model in a class
           * @param boundingBoxes the bounding boxes for each model in a class
           * @param distance the distance measure to compare codewords to features
           */
          template<typename T>
          void activate(const std::vector<std::shared_ptr<Codeword>> &codewords,
                        const std::map<unsigned, std::vector<pcl::PointCloud<ISMFeature>::Ptr>> &features,
                        const std::map<unsigned, std::vector<Utils::BoundingBox>> &boundingBoxes,
                        const Distance* distance, flann::Index<T> &index, const bool flann_exact_match);
  
          /**
           * @brief Activate the codebook using detected features and cast the votes from activated codewords
           * into a voting space.
           * @param features the detected features
           * @param distance the distance measure to compare codewords to features
           * @param voting the class representing the voting space in which votes shall be cast
           */
          template<typename T>
          void castVotes(pcl::PointCloud<ISMFeature>::Ptr features, const Distance* distance, Voting& voting,
                          flann::Index<T>& index, const bool flann_exact_match) const;
  
  
          // as above, but used for const pointer
          template<typename T>
          void castVotes(pcl::PointCloud<ISMFeature>::ConstPtr features, const Distance* distance, Voting& voting,
                          flann::Index<T> &index, const bool flann_exact_match) const;
  
          /**
           * @brief Add another distribution entry to the codebook. If the codebook already contains a distribution
           * with the given codeword, the entries are added. Elsewise, a new entry is created.
           * @param distribution the distribution to add
           */
          void addDistribution(std::shared_ptr<CodewordDistribution> distribution);
  
          /**
           * @brief Remove the distribution with the given codeword id.
           * @param id the codeword id for which the distribution shall be removed
           * @return true if removing was successful
           */
          bool removeDistribution(int id);
  
          /**
           * @brief Remove a list of distributions with given codeword ids.
           * @param ids the list of codeword ids for which the distributions shall be removed
           * @return true if removing was successful
           */
          bool removeDistributions(const std::vector<int>& ids);
  
          /**
           * @brief Get a codeword for the given codeword id.
           * @param id the codeword id
           * @return the codeword for the given codeword id or std::shared_ptr<Codeword>() if not found
           */
          std::shared_ptr<Codeword> getCodewordById(int id) const;
  
          /**
           * @brief Get the distribution for the given codeword id.
           * @param id the codeword id
           * @return the distribution for the given codeword id or std::shared_ptr<CodewordDistribution>() if not found
           */
          std::shared_ptr<CodewordDistribution> getDistributionById(int id) const;
  
          /**
           * @brief Get all codewords contained in the codebook.
           * @return a list of codewords
           */
          std::vector<std::shared_ptr<Codeword> > getCodewords(std::string warn = "") const;
          std::vector<std::shared_ptr<Codeword> > getCompleteCodewords() const;
          std::vector<std::shared_ptr<Codeword> > getPartialCodewords() const;
  
          /**
           * @brief Get all distribution entries contained in the codebook.
           * @return a map of distribution entries
           */
          const std::map<int, std::shared_ptr<CodewordDistribution> >& getDistribution() const;
  
          /**
           * @brief Check if the codebook contains a codeword / distribution with the given codeword id
           * @param id the codeword id
           * @return true if the codebook contains an entry with the given codeword id
           */
          bool containsCodewordWithId(int id) const;
  
          /**
           * @brief Get the number of codewords for the specified class.
           * @param classId the class id
           * @return the number of codewords for the specified class
           */
          int getNumCodewordsForClass(unsigned classId) const;
  
          /**
           * @brief Get the number of features for a given class id that have been used in the training process.
           * @param classId the class id
           * @return the number of features for the class id
           */
          int getNumOfFeaturesForClass(unsigned classId) const;
  
          /**
           * @brief Get the class ids
           * @return the vector containing the class ids for the current codebook
           */
          std::vector<unsigned> getClasses() const;
  
          /**
           * @brief Check if the codebook is empty.
           * @return true if the codebook is empty
           */
          bool isEmpty() const;
  
          /**
           * @brief Clear the codebook.
           */
          void clear();
  
          bool usePartialShot() const
          {
              return m_use_partial_shot;
          }
  
          int getDim() const
          {
              return m_codeword_dim;
          }
  
          int getSize() const
          {
              return m_codewords.size();
          }
  
      protected:
          Json::Value iChildConfigsToJson() const;
          bool iChildConfigsFromJson(const Json::Value&);
  
          void iSaveData(boost::archive::binary_oarchive &oa) const;
          bool iLoadData(boost::archive::binary_iarchive &ia);
  
      private:
  
          std::vector<bool> getSignatureMask() const;
  
          typedef std::map<int, std::shared_ptr<CodewordDistribution>> distribution_t; // maps codeword id to corresponding distribution
          distribution_t m_distribution;
  
          std::map<unsigned, float> m_term1;
          std::map<int, float> m_term2;
          std::map<unsigned, float> m_term3;
  
          ActivationStrategy* m_activationStrategy;
          std::map<unsigned, float> m_classSigmas;
          bool m_useClassWeight;
          bool m_useVoteWeight;
          bool m_useMatchingWeight;
          bool m_useCodewordWeight;
  
          bool m_use_random_codebook;
          float m_random_codebook_factor;
  
          int m_codeword_dim; // feature dimensions (i.e. length of descriptor)
  
          bool m_use_partial_shot;
          std::string m_partial_shot_type;
  
          std::vector<std::shared_ptr<Codeword> > m_codewords;
          std::vector<std::shared_ptr<Codeword> > m_partial_codewords;
      };
  }
  
  #endif // ISM3D_CODEBOOK_H
  