/**
 * @file  SalientRegionFeature.h
 * @brief Management of a circular region with the saliency value.
 *
 * Copyright (c) 2008, 2009, 2012, 2013 University of Pennsylvania.
 *
 * This file is part of DTI-DROID.
 *
 * DTI-DROID is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * DTI-DROID is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with DTI-DROID.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contact: SBIA Group <sbia-software at uphs.upenn.edu>
 */

#ifndef _DTIDROID_SALIENTREGIONFEATURE_H
#define _DTIDROID_SALIENTREGIONFEATURE_H

#include <vector>
#include "RegionFeature.h"

/***
  * class - CircularRegionFeature (2D, 3D)
  * typename T - the data type of the circular region
  * int n - the voxel dimension (scalar, vector, tensor, etc.)
***/
template< typename T, int n >
class CircularRegionFeature2D: public virtual RegionFeature<T,n>
{
public:
  /// constructor
  CircularRegionFeature2D() : _scale(0) { _center[0]=0; _center[1]=0;}
  
  /// initialize the circular region
  void init(const Field<T,n>& data, int z = 0);
  
  /// set center
  void setCircularCenter(int x, int y) { _center[0]=x; _center[1]=y; }
  
  /// set scale
  void setCircularScale(int scale) {_scale = scale;}
  
  /// get center
  void getCircularCenter(int* x, int* y) { *x=_center[0]; *y=_center[1];}
  
  /// get scale
  int getCircularScale() {return _scale;}
  
private:
  // coor circular center
  int _center[2];
  // scalar of the circular region
  int _scale;
};

template< typename T, int n >
class CircularRegionFeature3D: public virtual RegionFeature<T,n>
{
public:
  /// constructor
  CircularRegionFeature3D() : _scale(0) { _center[0]=0; _center[1]=0; _center[2]=0;}
  
  /// initialize the circular region
  void init(const Field<T,n>& data);
  
  /// set center
  void setCircularCenter(int x, int y, int z) 
  { 
    _center[0]=x; _center[1]=y; _center[2]=z;
  }    
  
  /// set scale
  void setCircularScale(int scale) {_scale = scale;}
  
  /// get center
  void getCircularCenter(int* x, int* y, int* z) 
  { 
    *x=_center[0]; *y=_center[1]; *z=_center[2];
  }
  
  /// get scale
  int getCircularScale() {return _scale;}
  
private:
  // coor circular center
  int _center[3];
  // scalar of the circular region
  int _scale;
};

/*** some circular region declarations ***/
//typedef CircularRegionFeature2D<float,1>            ScalarCircularRegionFeature2D;
typedef CircularRegionFeature2D<unsigned char,1>            ScalarCircularRegionFeature2D;

//typedef CircularRegionFeature3D<float,1>            ScalarCircularRegionFeature3D;
typedef CircularRegionFeature3D<unsigned char,1>            ScalarCircularRegionFeature3D;

class VectorCircularRegionFeature2D: public VectorRegionFeature<unsigned char>, public CircularRegionFeature2D<unsigned char,3> 
{};

class VectorCircularRegionFeature3D: public VectorRegionFeature<unsigned char>, public CircularRegionFeature3D<unsigned char,3>
{};


/***
  * class - SalientRegionFeature (2D & 3D)
  * note: to be implemented
***/
template< typename T, int n >
class SalientRegionFeature2D: public std::vector< CircularRegionFeature2D<T,n> >
{

};

template< typename T, int n >
class SalientRegionFeature3D: public std::vector< CircularRegionFeature3D<T,n> >
{

};

//==================I am a separator:)=============================//

/***
  * Implementation
***/

/***
  * implementation: class - CircularRegionFeature2D&3D
***/
template< typename T, int n >
void CircularRegionFeature2D<T,n>::init(const Field<T,n>& data, int z)
{
  for (int y=_center[1]-_scale; y<=_center[1]+_scale; y++)
    for (int x=_center[0]-_scale; x<=_center[0]+_scale; x++)
    {
      int xdim = data.getSize(0);
      int ydim = data.getSize(1);
      
      if (x < 0 || x > xdim-1 || y<0 || y>ydim-1) continue;
      
      double d = sqrt( (double)((x-_center[0])*(x-_center[0]) +
                 (y-_center[1])*(y-_center[1])) );
      if (d <= _scale)
      {
        ImageFeature<T,n> imageFeature;
        
        T* datP = data.getAt(x, y, z);
        for (int i=0; i<n; i++)
          imageFeature.set(datP[i],i);
        
        this->push_back(imageFeature);
      }
    }
}

template< typename T, int n >
void CircularRegionFeature3D<T,n>::init(const Field<T,n>& data)
{
  for (int z=_center[2]-_scale; z<=_center[2]+_scale; z++)
    for (int y=_center[1]-_scale; y<=_center[1]+_scale; y++)
      for (int x=_center[0]-_scale; x<=_center[0]+_scale; x++)
      {
        int xdim = data.getSize(0);
        int ydim = data.getSize(1);
        int zdim = data.getSize(2);
        
        if (x < 0 || x > xdim-1 || y<0 || y>ydim-1 || z<0 ||z>zdim-1) continue;
        
        double d = sqrt( (double)((x-_center[0])*(x-_center[0]) +
                 (y-_center[1])*(y-_center[1]) + (z-_center[2])*(z-_center[2])) );
        if (d <= _scale)
        {
          ImageFeature<T,n> imageFeature;
        
          T* datP = data.getAt(x, y, z);
          for (int i=0; i<n; i++)
            imageFeature.set(datP[i],i);
        
          this->push_back(imageFeature);
        }
      }
}


#endif // _DTIDROID_SALIENTREGIONFEATURE_H
