/**
* @file LabeledSet.h
* @brief Labeled set of vectors
* @author Erik Rodner
* @date 07.09.2007

*/
#ifndef LABELEDSETINCLUDE
#define LABELEDSETINCLUDE

#include <vector>
#include <map>

#include "core/basics/Persistent.h"
#include "core/vector/VVector.h"

#include "LabeledSetSelection.h"
#include "ImageInfo.h"

#define LOOP_ALL(ls) for(LabeledSetVector::const_iterator iLOOP_ALL = (ls).begin() ; iLOOP_ALL != (ls).end() ; iLOOP_ALL++) \
    for ( std::vector<NICE::Vector *>::const_iterator jLOOP_ALL = iLOOP_ALL->second.begin(); \
          jLOOP_ALL != iLOOP_ALL->second.end(); \
          jLOOP_ALL++ )
#define EACH(classno,x) int (classno) = iLOOP_ALL->first; \
  const NICE::Vector & (x) = *(*jLOOP_ALL);

#define LOOP_ALL_NONCONST(ls) for(LabeledSetVector::iterator iLOOP_ALL = (ls).begin() ; iLOOP_ALL != (ls).end() ; iLOOP_ALL++) \
    for ( std::vector<NICE::Vector *>::iterator jLOOP_ALL = iLOOP_ALL->second.begin(); \
          jLOOP_ALL != iLOOP_ALL->second.end(); \
          jLOOP_ALL++ )
#define EACH_NONCONST(classno,x) int (classno) = iLOOP_ALL->first; \
  NICE::Vector & (x) = *(*jLOOP_ALL);

#define LOOP_ALL_S(ls) for(LabeledSet::const_iterator iLOOP_ALL = (ls).begin() ; iLOOP_ALL != (ls).end() ; iLOOP_ALL++) \
    for ( std::vector<ImageInfo *>::const_iterator jLOOP_ALL = iLOOP_ALL->second.begin(); \
          jLOOP_ALL != iLOOP_ALL->second.end(); \
          jLOOP_ALL++ )
#define EACH_S(classno,x) int (classno) = iLOOP_ALL->first; \
  const std::string & (x) = (*jLOOP_ALL)->img();

#define EACH_INFO(classno,x) int (classno) = iLOOP_ALL->first; \
  const ImageInfo & (x) = *(*jLOOP_ALL);


namespace OBJREC {

class LabeledSet :
      public std::map< int, std::vector<ImageInfo *> >
{
  public:
    typedef std::vector<std::string *> ElementIterator;
    typedef std::pair<size_t, const ImageInfo *> ElementPointer;
    typedef std::vector< ElementPointer > Permutation;

  private:
    bool selection;

    Permutation insertOrder;

  public:

    void add_reference ( int classno, ImageInfo *pointer );

    LabeledSet ( bool selection = false );
    ~LabeledSet ();

    int numClasses () const
    {
      return size();
    }

    int count ( int classno ) const;
    int count () const;

    void clear ();

    void add ( int classno, ImageInfo *x );

    void getPermutation ( Permutation & permutation ) const;
    void getClasses ( std::vector<int> & classes ) const;

    void printInformation () const;

    friend class LabeledSetSelection<LabeledSet>;
};


/** simple labeled set of vectors as a specialization of std::map<> */
class LabeledSetVector :
      public std::map< int, std::vector<NICE::Vector *> >,
      public NICE::Persistent
{
  public:
    typedef std::vector<NICE::Vector *> ElementIterator;
    typedef std::pair<int, const NICE::Vector *> ElementPointer;
    typedef std::vector< ElementPointer > Permutation;

    enum {
      FILEFORMAT_INDEX = 0,
      FILEFORMAT_NOINDEX = 1,
      FILEFORMAT_RAW = 2,
      FILEFORMAT_INDEX_SPARSE_ONE = 3
    };

  private:
    bool selection;

    Permutation insertOrder;

  public:

    LabeledSetVector ( bool selection = false );
    ~LabeledSetVector ();

    void add_reference ( int classno, NICE::Vector *pointer );

    int dimension () const;

    int numClasses () const
    {
      return size();
    }

    void restore ( std::istream & is, int format = FILEFORMAT_INDEX );
    void restoreRAW ( std::istream & is );
    void restoreASCII ( std::istream & is, int format = FILEFORMAT_INDEX );
    void store ( std::ostream & os, int format = FILEFORMAT_INDEX ) const;
    static void storeElement ( std::ostream & os, int classno, const NICE::Vector & x, int format = FILEFORMAT_INDEX );

    ElementPointer pickRandomSample () const;

    int count ( int classno ) const;
    
    /**
     * @brief count all features
     *
     * @return int number of features
     **/
    int count () const;

    int pickRandomSample ( int classno, ElementPointer & i ) const;

    void clear ();

    /** most important function: add a labeled vector */
    void add ( int classno, const NICE::Vector & x );

    void getPermutation ( Permutation & permutation ) const;
    void getClasses ( std::vector<int> & classes ) const;

    void printInformation () const;

    void setSelection ( bool _selection = true ) {
      selection = _selection;
    };

    /**
     * returns the highest class number (not the number of classes!)
     */
    int getMaxClassno() const;

    /**
     * converts LabeledSetVector to a NICE::VVector Set (containing data) and a Labelvector (containing labels for each Data)
     * @param vecSet dataset (output)
     * @param vecSetLabels labels (output)
     */
    void getFlatRepresentation ( NICE::VVector & vecSet, NICE::Vector & vecSetLabels ) const;
    
    /**
     * @brief set all pointers to the data to NULL, i.e., keep the data in storage, but remove the pointers of this data struct
     */
    void removePointersToDataWithoutDeletion();

    friend class LabeledSetSelection<LabeledSetVector>;
};



} // namespace

#endif
