/// Dictionary.h
/** Provides a way to look up DICOM Element parameters
    by Tag value.
*/

#ifndef DICTIONARY_H_
#define DICTIONARY_H_

#include <map>
#include <vector>
#include <string>
#include <istream>
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>

#include <wx/defs.h>
#include <wx/filename.h>
#include <wx/stdpaths.h>
#include <wx/log.h>
#include <wx/app.h>

#include "DicomTag.h"
#include "DicomElement.h"

#define LEI_UID "1.2.840.10008.1.2"
#define LEE_UID "1.2.840.10008.1.2.1"
#define BEE_UID "1.2.840.10008.1.2.2"

namespace jcs {

enum {
LEI_CODE,
LEE_CODE,
BEE_CODE
};
  const wxUint32 UNDEFINED = 0xFFFFFFFF; // Undefined value length
  const std::string fnDicom = "dicom";
  const std::string fnExcite = "excite";
  const std::string fnNumaris = "numaris";
  const std::string fnPhilips = "philips_mr";

  ///
  /** Top-level class for various DICOM dictionaries.
  */
  class Dictionary {

  public:
    const DicomElement Lookup(const DicomTag& tag) const;
    const DicomElement Lookup(const std::string& desc) const;

    std::vector<std::string> TagList() const;

  protected:
    Dictionary(const std::string& dname);
    Dictionary& operator= (const Dictionary&);

  private:
    typedef std::map<DicomTag, DicomElement> TagMap;
    typedef std::map<std::string, DicomElement> StringMap;

    std::string mDictionaryName;
    TagMap mTagMap;
    StringMap mStringMap;
    DicomElement NULL_ENTRY;

    void mAddEntry(const DicomElement& e);
  };

  /// Minimum DICOM definitions.
  class Dicom_Dictionary : public Dictionary
  {
  public:
    /// Self-instantiator.
    static Dictionary* Instance()
    {
      static Dicom_Dictionary inst;
      return &inst;
    }

  protected:
    Dicom_Dictionary() : Dictionary(fnDicom) {}
  };

  /// Adds to Dicom_Dictionary field definitions.
  class Numaris_Dictionary : public Dictionary
  {
  public:
    /// Self-instantiator.
    static Dictionary* Instance()
    {
      static Numaris_Dictionary inst;
      return &inst;
    }

  protected:
    Numaris_Dictionary() : Dictionary(fnNumaris) {}
  };

  /// Adds to Dicom_Dictionary field definitions.
  class Excite_Dictionary : public Dictionary
  {
  public:
    /// Self-instantiator.
    static Dictionary* Instance()
    {
      static Excite_Dictionary inst;
      return &inst;
    }

  protected:
    Excite_Dictionary() : Dictionary(fnExcite) {}
  };

  /// Adds to Dicom_Dictionary field definitions.
  class PhilipsMr_Dictionary : public Dictionary
  {
  public:
    /// Self-instantiator.
    static Dictionary* Instance()
    {
      static PhilipsMr_Dictionary inst;
      return &inst;
    }

  protected:
    PhilipsMr_Dictionary() : Dictionary(fnPhilips) {}
  };
  
  DicomTag Tag(const std::string& s, 
  const Dictionary* dict = Dicom_Dictionary::Instance());

}

#endif
