#ifndef ___STEGER_HPP__
#define ___STEGER_HPP__
#include <math.h>
#define MAX_SIZE_MASK_0  3.09023230616781    /* Size for Gaussian mask */
#define MAX_SIZE_MASK_1  3.46087178201605    /* Size for 1st derivative mask */
#define MAX_SIZE_MASK_2  3.82922419517181    /* Size for 2nd derivative mask */

#define MASK_SIZE(MAX,sigma) ceil(MAX*sigma) /* Maximum mask index */
#include "opencv/highgui.h"
#include "opencv2/opencv.hpp"


#define LINCOOR(row,col,width) (long)((row)*(width)+(col))

#define BR(row) ((row) < 0 ? -(row) : \
                 (row) >= height ? height - (row) + height - 2 : (row))

/* Mirror the column coordinate at the borders of the image; width must be a
defined variable in the calling function containing the image width. */
#define BC(col) ((col) < 0 ? -(col) : \
                 (col) >= width ? width - (col) + width - 2 : (col))

/* Absolute value of x */
#ifndef ABS
#define ABS(x) ((x) >= 0 ? (x) : -(x))
#endif

/* Sign of x */
#ifndef SGN
#define SGN(x) ((x) == 0 ? 0 : ((x) > 0 ? 1 : -1))
#endif

#define MODE_LIGHT 1  /* Extract bright lines */
#define MODE_DARK  2  /* Extract dark lines */
#define PIXEL_BOUNDARY 0.6

typedef enum {
	cont_no_junc,    /* no end point is a junction */
	cont_start_junc, /* only the start point of the line is a junction */
	cont_end_junc,   /* only the end point of the line is a junction */
	cont_both_junc,  /* both end points of the line are junctions */
	cont_closed      /* the contour is closed */
} contour_class;

typedef struct {
	long  num;                /* number of points */
	float *row;               /* row coordinates of the line points */
	float *col;               /* column coordinates of the line points */
	float *angle;             /* angle of normal (measured from the row axis) */
	float *response;          /* response of line point (second derivative) */
	float *width_l;           /* width to the left of the line */
	float *width_r;           /* width to the right of the line */
	float *asymmetry;         /* asymmetry of the line point */
	float *contrast;          /* contrast of the line point */
	contour_class cont_class; /* contour class (e.g., closed, no_junc) */
} contour;


class Steger
{
private:
	Steger();
public:
	Steger(double sigma,double low,double high);
	~Steger();
	bool detect(cv::Mat src, cv::Mat& out);
	bool detect(cv::Mat src, std::vector<cv::Point2f>& points);
protected:
	void   run_gpu();
	float* compute_gauss_mask_0(long* num,double sigma);
	float* compute_gauss_mask_1(long   *num, double sigma);
	float* compute_gauss_mask_2(long   *num, double sigma);
	float  phi0(float x, float sigma);
	float  phi1(float x, float sigma);
	float  phi2(float x, float sigma);
	float normal(float x);
public:
	static bool initCuda();
private:
	double		m_sigma;
	double		m_low;
	double		m_high;

	float*		m_k[5];

	float*		m_mask_0_r;
	float*		m_mask_0_c;
	float*		m_mask_1_r;
	float*		m_mask_1_c;
	float*		m_mask_2_r;
	float*		m_mask_2_c;
	
	long		m_l_0r;
	long		m_l_0c;
	long		m_l_1r;
	long		m_l_1c;
	long		m_l_2r;
	long		m_l_2c;


	float*		m_image;
	float*		m_mid_data;
	int			m_width;
	int			m_height;
};


#endif