/// DicomElementInstance.cpp
/**
*/

#include "DicomElementInstance.h"

using namespace jcs;

///
/** Streams to a DicomElementInstance according to rules in
    DICOM Standard PS 3.5-2011
*/
std::istream &
jcs::operator>> (std::istream &in, DicomElementInstance &de)
{
  de.tag.transferSyntaxCode = de.transferSyntaxCode;
  // Read DICOM Tag, determine VR, read Value Length.
  in >> de.tag;
  if (de.IsExplicitVR()) {
    // This form of in.get gets 2 chars and adds
    // the NULL terminator.
    in.get(de.vr_buff, 3);
    de.vr.assign(de.vr_buff);
    if (de.vr == "OB" ||
        de.vr == "OW" ||
        de.vr == "OF" ||
        de.vr == "UT" ||
        de.vr == "SQ" ||
        de.vr == "UN" ) {
      in.ignore(2);
      in.read((char *)&(de.value_length), sizeof(de.value_length));
      de.value_length = de.EndianSwapUint32(de.value_length);
    }
    else {
      wxUint16 vl;
      in.read((char *)&(vl), sizeof(vl));
      de.value_length = vl;
      de.value_length = de.EndianSwapUint32(de.value_length);
    }
  }
  else { // implicit VR
    de.vr = de.GetVR();
    in.read((char *)&(de.value_length), sizeof(de.value_length));
    de.value_length = de.EndianSwapUint32(de.value_length);
  }

  // Now we can read the actual value(s).
  // First, load data into a string.
  wxUint32 n_to_read = de.value_length;
  std::string value;
  while (n_to_read > 0) {
    in.read(de.value_buff, std::min((long unsigned)sizeof(de.value_buff), (long unsigned)n_to_read));
    n_to_read -= in.gcount();
    value.append(de.value_buff, in.gcount());
  }

  // Stream from string into the data handler.
  // NOTE: Should free this when done streaming to de.myValue.
  std::stringstream ss(value);

  // Create the data handler. This should really be implemented with a map to functions.
  // de.ReadStream[de.vr](ss);
  if (de.vr.compare("AE") == 0) { de.myValue = new VR_AE(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_AE*>(de.myValue)); }
  if (de.vr.compare("AS") == 0) { de.myValue = new VR_AS(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_AS*>(de.myValue)); }
  if (de.vr.compare("AT") == 0) { de.myValue = new VR_AT(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_AT*>(de.myValue)); }
  if (de.vr.compare("CS") == 0) { de.myValue = new VR_CS(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_CS*>(de.myValue)); }
  if (de.vr.compare("DA") == 0) { de.myValue = new VR_DA(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_DA*>(de.myValue)); }
  if (de.vr.compare("DS") == 0) { de.myValue = new VR_DS(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_DS*>(de.myValue)); }
  if (de.vr.compare("DT") == 0) { de.myValue = new VR_DT(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_DT*>(de.myValue)); }
  if (de.vr.compare("FL") == 0) { de.myValue = new VR_FL(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_FL*>(de.myValue)); }
  if (de.vr.compare("FD") == 0) { de.myValue = new VR_FD(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_FD*>(de.myValue)); }
  if (de.vr.compare("IS") == 0) { de.myValue = new VR_IS(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_IS*>(de.myValue)); }
  if (de.vr.compare("LO") == 0) { de.myValue = new VR_LO(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_LO*>(de.myValue)); }
  if (de.vr.compare("LT") == 0) { de.myValue = new VR_LT(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_LT*>(de.myValue)); }
  if (de.vr.compare("OB") == 0) { de.myValue = new VR_OB(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_OB*>(de.myValue)); }
  if (de.vr.compare("OF") == 0) { de.myValue = new VR_OF(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_OF*>(de.myValue)); }
  if (de.vr.compare("OW") == 0) { de.myValue = new VR_OW(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_OW*>(de.myValue)); }
  if (de.vr.compare("PN") == 0) { de.myValue = new VR_PN(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_PN*>(de.myValue)); }
  if (de.vr.compare("SH") == 0) { de.myValue = new VR_SH(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_SH*>(de.myValue)); }
  if (de.vr.compare("SL") == 0) { de.myValue = new VR_SL(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_SL*>(de.myValue)); }
  if (de.vr.compare("SQ") == 0) { de.myValue = new VR_SQ(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_SQ*>(de.myValue)); }
  if (de.vr.compare("SS") == 0) { de.myValue = new VR_SS(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_SS*>(de.myValue)); }
  if (de.vr.compare("ST") == 0) { de.myValue = new VR_ST(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_ST*>(de.myValue)); }
  if (de.vr.compare("TM") == 0) { de.myValue = new VR_TM(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_TM*>(de.myValue)); }
  if (de.vr.compare("UI") == 0) { de.myValue = new VR_UI(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_UI*>(de.myValue)); }
  if (de.vr.compare("UL") == 0) { de.myValue = new VR_UL(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_UL*>(de.myValue)); }
  if (de.vr.compare("UN") == 0) { de.myValue = new VR_UN(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_UN*>(de.myValue)); }
  if (de.vr.compare("US") == 0) { de.myValue = new VR_US(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_US*>(de.myValue)); }
  if (de.vr.compare("UT") == 0) { de.myValue = new VR_UT(de.value_length, de.transferSyntaxCode); ss >> *(dynamic_cast<VR_UT*>(de.myValue)); }

  return in;
}    


///
/** Our canonical output streamer for DicomElementInstance.
*/
std::ostream &
jcs::operator<< (std::ostream &out, DicomElementInstance &de)
{
  out << de.tag << " ";
  out << de.vr << " ";
  out << de.value_length << " ";
  if (de.vr.compare("FL") == 0) { out << *(dynamic_cast<VR_FL*>(de.myValue)); }
  else if (de.vr.compare("FD") == 0) { out << *(dynamic_cast<VR_FD*>(de.myValue)); }
  else if (de.vr.compare("OF") == 0) { out << *(dynamic_cast<VR_OF*>(de.myValue)); }
  else if (de.vr.compare("OW") == 0) { out << *(dynamic_cast<VR_OW*>(de.myValue)); }
  else if (de.vr.compare("SL") == 0) { out << *(dynamic_cast<VR_SL*>(de.myValue)); }
  else if (de.vr.compare("SS") == 0) { out << *(dynamic_cast<VR_SS*>(de.myValue)); }
  else if (de.vr.compare("UL") == 0) { out << *(dynamic_cast<VR_UL*>(de.myValue)); }
  else if (de.vr.compare("US") == 0) { out << *(dynamic_cast<VR_US*>(de.myValue)); }
  else out << *(de.myValue);
  return out;
}


/**
DicomElementInstance::DicomElementInstance(Dictionary *dictionary) :
      mDicomDictionary(dictionary)
{
  ReadStream[std::string("AE")] = { myValue = new VR_AE(value_length, transferSyntaxCode); ss >> *(dynamic_cast<VR_AE*>(myValue)); }
}
**/


///
/** Tests whether transferSyntaxCode suggests
    an Explicit Value Representation.
*/
bool
DicomElementInstance::IsExplicitVR() {
  bool retval = false;
  if (transferSyntaxCode == LEE_CODE || 
      transferSyntaxCode == BEE_CODE) {
    retval = true;
  }
  return retval;
}


std::string
DicomElementInstance::GetVR() {
  return mDicomDictionary->Lookup(tag).vr;
}


wxUint32
DicomElementInstance::EndianSwapUint32(wxUint32 value) {
  if (transferSyntaxCode == BEE_CODE) {
    wxUINT32_SWAP_ON_LE(value);
  }
  else {
    wxUINT32_SWAP_ON_BE(value);
  }
  return value;
}
