/// ValueRepresentations.h
/** The start of definitions for "intelligent" DICOM data
    values. Each VR in the DICOM standard has a corresponding 
    class that can process an input stream to extract the
    value(s).
*/

#ifndef VALUEREPRESENTATIONS_H_
#define VALUEREPRESENTATIONS_H_

#include <string>
#include <vector>
#include <istream>
#include <wx/wx.h>

#include "DicomTag.h"
//#include "DicomElementInstance.h"

namespace jcs {

  //class DicomElementInstance;
  
  class DicomValue {
  public:
    DicomValue(wxUint32 vLength, wxUint8 transferSyntaxCode) : value_length(vLength), transferSyntaxCode(transferSyntaxCode) {}
    virtual ~DicomValue() {}
    wxUint8 transferSyntaxCode;
    wxUint32 value_length;
    std::vector<wxString> values;
    wxString value;
    wxString first();
    virtual void GetStrings(std::istream &in);
    wxInt16 EndianSwapInt16(wxInt16 value);
    wxInt32 EndianSwapInt32(wxInt32 value);
    wxUint16 EndianSwapUint16(wxUint16 value);
    wxUint32 EndianSwapUint32(wxUint32 value);
    wxUint64 EndianSwapUint64(wxUint64 value);
    bool operator== (DicomValue &dv);
    friend std::ostream &operator<<(std::ostream &out, DicomValue &ve);
  };

  // Application Entity
  class VR_AE : public DicomValue {
  public:
    VR_AE(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_AE &ae);
  };

  // Age String
  class VR_AS : public DicomValue {
  public:
    VR_AS(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_AS &as);
  };
  
  // Attribute Tag
  class VR_AT : public DicomValue {
  public:
    VR_AT(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    DicomTag val;
    std::vector<DicomTag> values;
    friend std::istream &operator>>(std::istream &in, VR_AT &at);
  };
  
  // Code String
  class VR_CS : public DicomValue {
  public:
    VR_CS(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_CS &cs);
  };
  
  // Date
  class VR_DA : public DicomValue {
  public:
    VR_DA(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_DA &da);
  };
  
  // Decimal String
  class VR_DS : public DicomValue {
  public:
    VR_DS(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_DS &ds);
  };
  
  // Date Time
  class VR_DT : public DicomValue {
  public:
    VR_DT(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_DT &dt);
  };
  
  // Floating Point Single
  class VR_FL : public DicomValue {
  public:
    VR_FL(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    std::vector<float> values;
    friend std::istream &operator>>(std::istream &in, VR_FL &fl);
    friend std::ostream &operator<<(std::istream &out, VR_FL &fl);
  };
  
  // Floating Point Double
  class VR_FD : public DicomValue {
  public:
    VR_FD(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    std::vector<double> values;
    friend std::istream &operator>>(std::istream &in, VR_FD &fd);
    friend std::ostream &operator<<(std::istream &out, VR_FD &fd);
  };
  
  // Integer String
  class VR_IS : public DicomValue {
  public:
    VR_IS(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_IS &is);
  };
  
  // Long String
  class VR_LO : public DicomValue {
  public:
    VR_LO(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_LO &lo);
  };
  
  // Long Text
  class VR_LT : public DicomValue {
  public:
    VR_LT(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_LT &lt);
  };
  
  // Other Byte String
  class VR_OB : public DicomValue {
  public:
    VR_OB(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_OB &ob);
  };
  
  // Other Float String
  class VR_OF : public DicomValue {
  public:
    VR_OF(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    std::vector<float> values;
    friend std::istream &operator>>(std::istream &in, VR_OF &of);
    friend std::ostream &operator<<(std::istream &out, VR_OF &of);

  };
  
  // Other Word String
  class VR_OW : public DicomValue {
  public:
    VR_OW(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    std::vector<wxUint16> values;
    friend std::istream &operator>>(std::istream &in, VR_OW &ow);
    friend std::ostream &operator<<(std::istream &out, VR_OW &ow);    
  };
  
  // Person Name
  class VR_PN : public DicomValue {
  public:
    VR_PN(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_PN &pn);
  };
  
  // Short String
  class VR_SH : public DicomValue {
  public:
    VR_SH(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_SH &sh);
  };
  
  // Signed Long
  class VR_SL : public DicomValue {
  public:
    VR_SL(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    std::vector<wxInt32> values;
    friend std::istream &operator>>(std::istream &in, VR_SL &sl);
    friend std::ostream &operator<<(std::istream &out, VR_SL &sl);
  };
  
  // Sequence of Items
  class VR_SQ : public DicomValue {
  public:
    VR_SQ(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_SQ &sq);
  };

  // Signed Short
  class VR_SS : public DicomValue {
  public:
    VR_SS(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    std::vector<wxInt16> values;
    friend std::istream &operator>>(std::istream &in, VR_SS &ss);
    friend std::ostream &operator<<(std::istream &out, VR_SS &ss);
  };
  
  // Short Text
  class VR_ST : public DicomValue {
  public:
    VR_ST(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_ST &st);
  };
  
  // Time
  class VR_TM : public DicomValue {
  public:
    VR_TM(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_TM &tm);
  };
  
  // Unique Identifier (UID)
  class VR_UI : public DicomValue {
  public:
    VR_UI(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_UI &ui);
  };
  
  // Unsigned Long
  class VR_UL : public DicomValue {
  public:
    VR_UL(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    std::vector<wxUint32> values;
    friend std::istream &operator>>(std::istream &in, VR_UL &ul);
    friend std::ostream &operator<<(std::istream &out, VR_UL &ul);
  };

  // Unknown
  class VR_UN : public DicomValue {
  public:
    VR_UN(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_UN &un);
  };

  // Unsigned Short
  class VR_US : public DicomValue {
  public:
    VR_US(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    std::vector<wxUint16> values;
    friend std::istream &operator>>(std::istream &in, VR_US &us);
    friend std::ostream &operator<<(std::istream &out, VR_US &us);
  };
  
  // Unlimited Text
  class VR_UT : public DicomValue {
  public:
    VR_UT(wxUint32 vLength, wxUint8 vtransferSyntaxCode) : DicomValue(vLength, transferSyntaxCode) {}
    friend std::istream &operator>>(std::istream &in, VR_UT &ut);
  };
  

  std::istream &
  operator>> (std::istream &in, VR_AE &at);
  
  std::istream &
  operator>> (std::istream &in, VR_AS &as);
  
  std::istream &
  operator>> (std::istream &in, VR_AT &at);
  
  std::istream &
  operator>> (std::istream &in, VR_CS &at);
  
  std::istream &
  operator>> (std::istream &in, VR_DA &at);
  
  std::istream &
  operator>> (std::istream &in, VR_DS &at);
  
  std::istream &
  operator>> (std::istream &in, VR_DT &at);
  
  std::istream &
  operator>> (std::istream &in, VR_FL &fl);
  std::ostream &
  operator<< (std::ostream &out, VR_FL &fl);

  std::istream &
  operator>> (std::istream &in, VR_FD &fd);
  std::ostream &
  operator<< (std::ostream &out, VR_FD &fd);
  
  std::istream &
  operator>> (std::istream &in, VR_IS &at);
  
  std::istream &
  operator>> (std::istream &in, VR_LO &at);
  
  std::istream &
  operator>> (std::istream &in, VR_LT &at);
  
  std::istream &
  operator>> (std::istream &in, VR_OB &at);
  
  std::istream &
  operator>> (std::istream &in, VR_OF &of);
  std::ostream &
  operator<< (std::ostream &out, VR_OF &of);
  
  std::istream &
  operator>> (std::istream &in, VR_OW &ow);
  std::ostream &
  operator<< (std::ostream &out, VR_OW &ow);
  
  std::istream &
  operator>> (std::istream &in, VR_PN &at);
  
  std::istream &
  operator>> (std::istream &in, VR_SH &at);
  
  std::istream &
  operator>> (std::istream &in, VR_SQ &at);
  
  std::istream &
  operator>> (std::istream &in, VR_SL &sl);
  std::ostream &
  operator<< (std::ostream &out, VR_SL &sl);
  
  std::istream &
  operator>> (std::istream &in, VR_SS &ss);
  std::ostream &
  operator<< (std::ostream &out, VR_SS &ss);
  
  std::istream &
  operator>> (std::istream &in, VR_ST &at);
  
  std::istream &
  operator>> (std::istream &in, VR_TM &at);
  
  std::istream &
  operator>> (std::istream &in, VR_UI &at);
  
  std::istream &
  operator>> (std::istream &in, VR_UL &ul);
  std::ostream &
  operator<< (std::ostream &out, VR_UL &ul);
  
  std::istream &
  operator>> (std::istream &in, VR_UN &at);
  
  std::istream &
  operator>> (std::istream &in, VR_US &us);
  std::ostream &
  operator<< (std::ostream &out, VR_US &us);
  
  std::istream &
  operator>> (std::istream &in, VR_UT &at);
  
}

#endif
