/***
  * TensorField - decompose a tensor to different structures: prolate, oblate, sphere, FA, and ADC.
  * Required: Field.h, GSL library
  * Author: Jinzhong Yang
  * Date: Nov. 26, 2007
  *
  * =================================
  * Add PD related computation
  * Date: Feb. 25, 2008
  *
***/

#ifndef _TENSORFIELD_H
#define _TENSORFIELD_H

#include <iostream>
#include <string>

#include <gsl/gsl_linalg.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_eigen.h>
#include <gsl/gsl_blas.h>

#include "FieldDRTG.h"

typedef Field<unsigned char, 1>     ByteScalarField;
typedef Field<unsigned char, 3>     ByteVectorField;
typedef Field<float,1>              FloatScalarField;
typedef Field<float,3>              FloatVectorField;

static int PROLATE_STRUCT     =      1;
static int OBLATE_STRUCT      =      2;
static int SPHERE_STRUCT      =      4;
static int FA_STRUCT          =      8;
static int TRACE_STRUCT       =      16;

static int PD_FIRST           =      1;
static int PD_SECOND          =      2;
static int PD_THIRD           =      4;

class TensorField: public Field<float,6>
{
public:
  /// constructor
  TensorField(): _nStructInitialized(0), _nPDInitialized(0) {}
  
  ///@{
  /// initialize the tensor structure data
  void initStruct(int nInitStruct = 8);
  
  /// clean the tensor structure data
  void cleanStruct(int nSelectStruct = 31);
  
  /// decompose the tensor field for those structures that have been initialized
  void decomposeStructure();
  
  /// smoothing the structure field
  void smoothTensorStructField(int nSelectedStruct, float sigma = 1.0f);
  
  /// normalize the structure field
  void normalizeTensorStructField(int nSelectedStruct);
  
  /// save the Structure Field
  void saveTensorStructField(int nSelectedStruct, const std::string& prefix);
  ///@}
  
  ///@{
  /// initialize the PD maps
  void initColorPD(int nInitPD = 1);
  
  /// clean the PD maps
  void cleanColorPD(int nSelectedPD = 7);
  
  ///compute PD maps
  void computeColorPD(bool bFAWeighted = true);
  
  ///smooth the color PD maps
  void smoothColorPDField(int nSelectedPD, float sigma = 1.0f);
  
  /// save the color PD maps
  void saveColorPDField(int nSelectedPD, const std::string& prefix);
  ///@}
  
  /// access the structure data
  const ByteScalarField & getProlateStructure() const { return _structProlate;}
  
  const ByteScalarField & getOblateStructure() const { return _structOblate;}
  
  const ByteScalarField & getSphereStructure() const { return _structSphere;}
  
  const ByteScalarField & getFAStructure() const { return _structFA;}
  
  const ByteScalarField & getTraceStructure() const { return _structTrace;}
  
  /// access the PD maps
  const ByteVectorField & getColorPD1() const { return _colorPD_1; }
  
  const ByteVectorField & getColorPD2() const { return _colorPD_2; }
  
  const ByteVectorField & getColorPD3() const { return _colorPD_3; }
private:
  /// prolate structure
  ByteScalarField _structProlate;
  /// oblate structure
  ByteScalarField _structOblate;
  /// sphere structure
  ByteScalarField _structSphere;  
  /// FA map
  ByteScalarField _structFA;  
  /// ADC map (normalized)
  ByteScalarField _structTrace;
  
  ///PD map (color map in RGB format)
  ByteVectorField _colorPD_1;
  ByteVectorField _colorPD_2;
  ByteVectorField _colorPD_3;
  
  /// flag
  int _nStructInitialized;
  int _nPDInitialized;
  
  /// smooth structure by Gaussian
  void smoothTensorStruct2D(ByteScalarField& tensorStruct, float sigma);
  void smoothTensorStruct3D(ByteScalarField& tensorStruct, float sigma);
  
  void normalizeTensorStruct(ByteScalarField& tensorStruct);
};

#endif // _TENSORFIELD_H

