/// NewSpmVolume.cpp
/**
*/

#include "NewSpmVolume.h"

using namespace jcs;

///
/**
 */
NewSpmVolume::NewSpmVolume(const char* filename, 
const char* he, const char* re) 
: BasicVolumeFormat(filename, he, re), mByteOrder(aLITTLE_ENDIAN)
{
  // Need to fix things if we want to add reading files back to this class.
  //  if (!mReadHeaderFile()) mInitHeader();
  mInitHeader();
}


///
/**
 */
NewSpmVolume::~NewSpmVolume()
{
  if (mMatFile.is_open()) {
    mCloseMatFile();
  }
}


///
/**
 */
void
NewSpmVolume::WriteHeader(Basic3DHeader* header)
{ 
  NewSpmHeader* spm_header = dynamic_cast<NewSpmHeader*>(header);
  mHeader = *spm_header;
  if (mWriteHeaderFile() == 1) {
    if (verbose && !quiet) {
      std::cout << "Wrote " << mFileName.GetFullPath() << std::endl;  //.mb_str(wxConvLocal) << std::endl;
    }
  }
}


///
/**
 */
int
NewSpmVolume::mOpenMatFile(std::ios::openmode mode)
{
  //  if (!mFileName.IsOk()) return 0;
  //  if (mMatFile.is_open()) mMatFile.close();
  //  mMatFile.clear();
  //  std::string filename = mFileName = ".mat";
  //  mMatFile.open(filename.c_str(), mode);
  return mMatFile.good();
}


///
/**
 */
int
NewSpmVolume::mReadHeaderFile() 
{
  if (!mOpenHeaderFile(std::ios::in|std::ios::binary)) {
    return 0;
  }

  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hk.sizeof_hdr),
  sizeof(mHeader.hk.sizeof_hdr));

  // If the header size isn't 348, set the byte order to big endian
  if (mHeader.hk.sizeof_hdr != 348) {
    mByteOrder = aBIG_ENDIAN;
  }

  // Reset get pointer
  mHeaderFile.seekg(0);
  
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hk.sizeof_hdr),
  sizeof(mHeader.hk.sizeof_hdr));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hk.data_type),
  sizeof(mHeader.hk.data_type));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hk.db_name),
  sizeof(mHeader.hk.db_name));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hk.extents),
  sizeof(mHeader.hk.extents));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hk.session_error),
  sizeof(mHeader.hk.session_error));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hk.regular),
  sizeof(mHeader.hk.regular));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hk.hkey_un0),
  sizeof(mHeader.hk.hkey_un0));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.dim),
  sizeof(mHeader.dime.dim));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.unused8),
  sizeof(mHeader.dime.unused8));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.unused9),
  sizeof(mHeader.dime.unused9));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.unused10),
  sizeof(mHeader.dime.unused10));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.unused11),
  sizeof(mHeader.dime.unused11));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.unused12),
  sizeof(mHeader.dime.unused12));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.unused13),
  sizeof(mHeader.dime.unused13));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.unused14),
  sizeof(mHeader.dime.unused14));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.datatype),
  sizeof(mHeader.dime.datatype));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.bitpix),
  sizeof(mHeader.dime.bitpix));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.dim_un0),
  sizeof(mHeader.dime.dim_un0));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.pixdim),
  sizeof(mHeader.dime.pixdim));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.vox_offset),
  sizeof(mHeader.dime.vox_offset));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.scale),
  sizeof(mHeader.dime.scale));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.intercept),
  sizeof(mHeader.dime.intercept));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.funused3),
  sizeof(mHeader.dime.funused3));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.cal_max),
  sizeof(mHeader.dime.cal_max));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.cal_min),
  sizeof(mHeader.dime.cal_min));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.compressed),
  sizeof(mHeader.dime.compressed));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.verified),
  sizeof(mHeader.dime.verified));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.glmax),
  sizeof(mHeader.dime.glmax));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.dime.glmin),
  sizeof(mHeader.dime.glmin));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.descrip),
  sizeof(mHeader.hist.descrip));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.aux_file),
  sizeof(mHeader.hist.aux_file));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.orient),
  sizeof(mHeader.hist.orient));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.origin),
  sizeof(mHeader.hist.origin));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.generated),
  sizeof(mHeader.hist.generated));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.scannum),
  sizeof(mHeader.hist.scannum));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.patient_id),
  sizeof(mHeader.hist.patient_id));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.exp_date),
  sizeof(mHeader.hist.exp_date));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.exp_time),
  sizeof(mHeader.hist.exp_time));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.hist_un0),
  sizeof(mHeader.hist.hist_un0));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.views),
  sizeof(mHeader.hist.views));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.vols_added),
  sizeof(mHeader.hist.vols_added));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.start_field),
  sizeof(mHeader.hist.start_field));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.field_skip),
  sizeof(mHeader.hist.field_skip));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.omax),
  sizeof(mHeader.hist.omax));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.omin),
  sizeof(mHeader.hist.omin));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.smax),
  sizeof(mHeader.hist.smax));
  mHeaderFile.read(reinterpret_cast <char*> (&mHeader.hist.smin),
  sizeof(mHeader.hist.smin));
  
  if (mByteOrder != aLITTLE_ENDIAN) {

    ByteSwap(mHeader.hk.sizeof_hdr, sizeof(wxInt32));
    ByteSwap(mHeader.hk.extents, sizeof(wxInt32));
    ByteSwap(mHeader.hk.session_error, sizeof(wxInt16));
    ByteSwap(mHeader.dime.dim, sizeof(wxInt16));
    ByteSwap(mHeader.dime.unused8, sizeof(wxInt16));
    ByteSwap(mHeader.dime.unused9, sizeof(wxInt16));
    ByteSwap(mHeader.dime.unused10, sizeof(wxInt16));
    ByteSwap(mHeader.dime.unused11, sizeof(wxInt16));
    ByteSwap(mHeader.dime.unused12, sizeof(wxInt16));
    ByteSwap(mHeader.dime.unused13, sizeof(wxInt16));
    ByteSwap(mHeader.dime.unused14, sizeof(wxInt16));
    ByteSwap(mHeader.dime.datatype, sizeof(wxInt16));
    ByteSwap(mHeader.dime.bitpix, sizeof(wxInt16));
    ByteSwap(mHeader.dime.dim_un0, sizeof(wxInt16));
    ByteSwap(mHeader.dime.pixdim, sizeof(float));
    ByteSwap(mHeader.dime.vox_offset, sizeof(float));
    ByteSwap(mHeader.dime.scale, sizeof(float));
    ByteSwap(mHeader.dime.intercept, sizeof(float));
    ByteSwap(mHeader.dime.funused3, sizeof(float));
    ByteSwap(mHeader.dime.cal_max, sizeof(float));
    ByteSwap(mHeader.dime.cal_min, sizeof(float));
    ByteSwap(mHeader.dime.compressed, sizeof(float));
    ByteSwap(mHeader.dime.verified, sizeof(float));
    ByteSwap(mHeader.dime.glmax, sizeof(wxInt32));
    ByteSwap(mHeader.dime.glmin, sizeof(wxInt32));
    ByteSwap(mHeader.hist.origin, sizeof(wxInt16));
    ByteSwap(mHeader.hist.views, sizeof(wxInt32));
    ByteSwap(mHeader.hist.vols_added, sizeof(wxInt32));
    ByteSwap(mHeader.hist.start_field, sizeof(wxInt32));
    ByteSwap(mHeader.hist.field_skip, sizeof(wxInt32));
    ByteSwap(mHeader.hist.omax, sizeof(wxInt32));
    ByteSwap(mHeader.hist.omin, sizeof(wxInt32));
    ByteSwap(mHeader.hist.smax, sizeof(wxInt32));
    ByteSwap(mHeader.hist.smin, sizeof(wxInt32));
  }
  
  mCloseHeaderFile();

  return 1;
}


///
/**
 */
int
NewSpmVolume::mWriteHeaderFile() 
{

  if (!mOpenHeaderFile(std::ios::out|std::ios::binary)) {
    wxLogError(_T("Cannot create header file %s"),
    mFileName.GetFullName().c_str());
    return 0;
  }

  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hk.sizeof_hdr),
  sizeof(mHeader.hk.sizeof_hdr));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hk.data_type),
  sizeof(mHeader.hk.data_type));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hk.db_name),
  sizeof(mHeader.hk.db_name));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hk.extents),
  sizeof(mHeader.hk.extents));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hk.session_error),
  sizeof(mHeader.hk.session_error));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hk.regular),
  sizeof(mHeader.hk.regular));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hk.hkey_un0),
  sizeof(mHeader.hk.hkey_un0));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.dim),
  sizeof(mHeader.dime.dim));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.unused8),
  sizeof(mHeader.dime.unused8));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.unused9),
  sizeof(mHeader.dime.unused9));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.unused10),
  sizeof(mHeader.dime.unused10));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.unused11),
  sizeof(mHeader.dime.unused11));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.unused12),
  sizeof(mHeader.dime.unused12));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.unused13),
  sizeof(mHeader.dime.unused13));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.unused14),
  sizeof(mHeader.dime.unused14));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.datatype),
  sizeof(mHeader.dime.datatype));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.bitpix),
  sizeof(mHeader.dime.bitpix));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.dim_un0),
  sizeof(mHeader.dime.dim_un0));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.pixdim),
  sizeof(mHeader.dime.pixdim));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.vox_offset),
  sizeof(mHeader.dime.vox_offset));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.scale),
  sizeof(mHeader.dime.scale));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.intercept),
  sizeof(mHeader.dime.intercept));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.funused3),
  sizeof(mHeader.dime.funused3));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.cal_max),
  sizeof(mHeader.dime.cal_max));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.cal_min),
  sizeof(mHeader.dime.cal_min));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.compressed),
  sizeof(mHeader.dime.compressed));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.verified),
  sizeof(mHeader.dime.verified));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.glmax),
  sizeof(mHeader.dime.glmax));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.dime.glmin),
  sizeof(mHeader.dime.glmin));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.descrip),
  sizeof(mHeader.hist.descrip));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.aux_file),
  sizeof(mHeader.hist.aux_file));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.orient),
  sizeof(mHeader.hist.orient));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.origin),
  sizeof(mHeader.hist.origin));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.generated),
  sizeof(mHeader.hist.generated));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.scannum),
  sizeof(mHeader.hist.scannum));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.patient_id),
  sizeof(mHeader.hist.patient_id));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.exp_date),
  sizeof(mHeader.hist.exp_date));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.exp_time),
  sizeof(mHeader.hist.exp_time));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.hist_un0),
  sizeof(mHeader.hist.hist_un0));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.views),
  sizeof(mHeader.hist.views));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.vols_added),
  sizeof(mHeader.hist.vols_added));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.start_field),
  sizeof(mHeader.hist.start_field));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.field_skip),
  sizeof(mHeader.hist.field_skip));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.omax),
  sizeof(mHeader.hist.omax));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.omin),
  sizeof(mHeader.hist.omin));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.smax),
  sizeof(mHeader.hist.smax));
  mHeaderFile.write(reinterpret_cast <const char*> (&mHeader.hist.smin),
  sizeof(mHeader.hist.smin));
  
  mCloseHeaderFile();

  return 1;
}


///
/**
 */
void
NewSpmVolume::ViewHeader() 
{

  std::cout << "Scan number: ";
  std::cout.write(mHeader.hist.scannum, sizeof(mHeader.hist.scannum));
  std::cout << std::endl;
  std::cout << "Patient name: ";
  std::cout.write(mHeader.hist.patient_id, sizeof(mHeader.hist.patient_id));
  std::cout << std::endl;
  std::cout << "Study date: ";
  std::cout.write(mHeader.hist.exp_date, sizeof(mHeader.hist.exp_date));
  std::cout << std::endl;
  std::cout << "Study time: ";
  std::cout.write(mHeader.hist.exp_time, sizeof(mHeader.hist.exp_time));
  std::cout << std::endl;
  
  std::cout << "Repetition time: " << mHeader.dime.pixdim[4] << std::endl;
  std::cout << "Header size: " << mHeader.hk.sizeof_hdr << " bytes" << std::endl;
  std::cout << "Image Columns: " << mHeader.dime.dim[1] << " voxels" << std::endl;
  std::cout << "Image Rows: " << mHeader.dime.dim[2] << " voxels" << std::endl;
  std::cout << "Slices: " << mHeader.dime.dim[3] << std::endl;
  std::cout << "Voxel size (x): " << mHeader.dime.pixdim[1] << " mm" << std::endl;
  std::cout << "Voxel size (y): " << mHeader.dime.pixdim[2] << " mm" << std::endl;
  std::cout << "Slice size: " << mHeader.dime.pixdim[3] << " mm" << std::endl;
  std::cout << "Data type: " << mHeader.dime.datatype << std::endl;
  std::cout << "Scale: " << mHeader.dime.scale << std::endl;
  std::cout << "Voxel offset: " << mHeader.dime.vox_offset << " bytes" << std::endl;
  std::cout << "Origin (x): " << mHeader.hist.origin[0] << " voxels" << std::endl;
  std::cout << "Origin (y): " << mHeader.hist.origin[1] << " voxels" << std::endl;
  std::cout << "Origin (z): " << mHeader.hist.origin[2] << " voxels" << std::endl;

  std::cout << "Description: ";
  std::cout.write(mHeader.hist.descrip, sizeof(mHeader.hist.descrip));
  std::cout << std::endl << std::endl;


}


///
/**
 */
void
NewSpmHeader::InitHeader()
{ 
  memset(&hist, 0, sizeof(hist));
  memset(&dime, 0, sizeof(dime));
  memset(&hk, 0, sizeof(hk));
}
