/// HandlerFactory.cpp
/**
*/


#include "HandlerFactory.h"

#include <string>
#include "Dictionary.h"
#include "SyngoHandler.h"
#include "AchievaDtiHandler.h"
#include "EnhancedMrHandler.h"
#include "GeEpiHandler.h"
#include "GeDti2Handler.h"
#include "GeDtiRbHandler.h"
#include "NumarisMosaicHandler.h"
#include "SyngoMosaicHandler.h"

using namespace jcs;

enum { 
  STANDARD, 
  NUMARIS_VOLUME, 
  NUMARIS_SLICE, 
  NUMARIS_MOSAIC,
  SYNGO_VOLUME, 
  SYNGO_SLICE, 
  SYNGO_MOSAIC,
  GE_EPI,
  GE_DTI,
  GE_DTI2,
  ENHANCED_MR,
  ACHIEVA
};

const char* EnhancedMrSopClass = "1.2.840.10008.5.1.4.1.1.4.1";


///
/** Creates and returns a handler appropriate for the given file.
    \param filename The name of a DICOM file.
    \return A pointer to a SeriesHandler instance.
*/
SeriesHandler*
HandlerFactory::CreateHandler(const char* filename)
{
  std::string series_uid;
  DicomFile dfile(filename);
  dfile.Find("SeriesInstanceUID", series_uid);

  // Fix problems with termination
  std::string temp(series_uid.c_str());
  series_uid.clear();
  series_uid = temp;

  SeriesHandler* handler;

  int series_type = GetSeriesType(dfile);
  switch (series_type) {

  case SYNGO_VOLUME :
  case SYNGO_SLICE :
    handler = new SyngoHandler(series_uid);
    break;

  case NUMARIS_MOSAIC :
    handler = new NumarisMosaicHandler(series_uid);
    break;

  case SYNGO_MOSAIC :
    handler = new SyngoMosaicHandler(series_uid);
    break;

  case GE_EPI :
    handler = new GeEpiHandler(series_uid);
    break;

  case GE_DTI :
    handler = new GeDtiRbHandler(series_uid);
    break;

  case GE_DTI2 :
    handler = new GeDti2Handler(series_uid);
    break;

  case ENHANCED_MR :
    handler = new EnhancedMrHandler(series_uid);
    break;

  case ACHIEVA :
    handler = new AchievaDtiHandler(series_uid);
    break;

    default :
    handler = new SeriesHandler(series_uid);
  }

  return handler;
}


///
/** Analyzes DicomFile instance to determine type of series.
    \param dfile A reference to a DicomFile instance.
    \return Series type code.
*/
int
HandlerFactory::GetSeriesType(DicomFile& dfile)
{
  int retval = STANDARD;
  std::string s;

  // All manufacturers are presumably equivalent if Enhanced MR 
  // files are produced.
  dfile.Find("SOPClassUID", s);
  if (s.find(EnhancedMrSopClass) != std::string::npos) {
    retval = ENHANCED_MR;
    return retval;
  }

  // Otherwise, branch on manufacturer to account for the 
  // idiosyncracies of each.
  dfile.Find("Manufacturer", s);
  if (s.find("SIEMENS") != std::string::npos) {
    std::string software;
    dfile.Find("SoftwareVersions", software);

    if (software.find("VA13") != std::string::npos) {

      Dictionary* Numaris = Numaris_Dictionary::Instance();
      int x = 0;
      if (dfile.Find(Numaris->Lookup("BASE_RAW_MATRIX_SIZE"), x) && (x == 64)) {
        return NUMARIS_MOSAIC;
      }

      dfile.Find("MRAcquisitionType", s);
      if (s.find("3D") == std::string::npos) {
        return NUMARIS_SLICE;
      }
      else {
        return NUMARIS_VOLUME;
      }
    }
    else {
      if (software.find("syngo") != std::string::npos) {
        dfile.Find("ImageType", s);
        if ((s.find("MOSAIC") != std::string::npos) &&
            (s.find("DUMMY IMAGE") == std::string::npos)) {
          return SYNGO_MOSAIC;
        }
        dfile.Find("MRAcquisitionType", s);
        if (s.find("3D") == std::string::npos) {
          return SYNGO_SLICE;
        }
        else {
          return SYNGO_VOLUME;
        }
      }
      else {
        return STANDARD;
      }
    }
  }

  if (s.find("GE") != std::string::npos) {
    std::string sequence;
    Dictionary* Excite = Excite_Dictionary::Instance();
    dfile.Find(Excite->Lookup("Pulse_seq_Name"), sequence);
    if (sequence.find("dti_epi") != std::string::npos) {
      return GE_DTI;
    }
    if (sequence.find("epi2") != std::string::npos) {
      return GE_DTI2;
    }
    if (sequence.find("epi") != std::string::npos) {
      return GE_EPI;
    }
    std::string imageType;
    dfile.Find("ImageType", imageType);
    if (imageType.find("EPI") != std::string::npos) {
      return GE_EPI;
    }
    else {
      return STANDARD;
    }
  }

  if (s.find("Philips") != std::string::npos) {
    std::string description;
    dfile.Find("SeriesDescription", description);
    if (description.find("DTI") != std::string::npos) {
      return ACHIEVA;
    }
    dfile.Find("ProtocolName", description);
    if (description.find("DTI") != std::string::npos) {
      return ACHIEVA;
    }
  }
  return STANDARD;
}


//cdt ///
//cdt /** Wrapper for GetSeriesType(DicomFile& dfile).
//cdt     \param filename Name of DICOM file to analyze.
//cdt     \return Series type code.
//cdt */
//cdt int
//cdt HandlerFactory::GetSeriesType(const char* filename)
//cdt {
//cdt   DicomFile dfile(filename);
//cdt   return GetSeriesType(dfile);
//cdt }
 
