#pragma once
#include <iostream>
#include <vector>
#include <math.h>
#include <string>
#include "EdgeDetection.h"
using namespace std;

//////////////////////////////////////////////////////////////////////////
#ifndef INOUT
#define INOUT
#endif

#ifndef Loop_Image
#define Loop_Image(x,y,width,height) for(int y=0;y<height;y++)for(int x=0;x<width;x++)
#endif

#ifndef isZero
#define isZero(x) (abs(x)<0.0000000001f)
#endif

#ifndef isEqual
#define isEqual(x,y) isZero(x-y)
#endif

#ifndef maxABC
#define maxABC(a,b,c) (max(max(a,b),c))
#endif

#ifndef minABC
#define minABC(a,b,c) (min(min(a,b),c))
#endif

#ifndef OutOfImage
#define OutOfImage(x,y,width,height) ((x<0)||(x>width-1)||(y<0)||(y>height-1))
#endif

#define LargeNum 1000000000

#ifndef SwapAB
#define SwapAB(a,b,tmp) tmp=a;a=b;b=tmp;
#endif
//////////////////////////////////////////////////////////////////////////
struct CumEnergyElement;
struct TranspotElement;
typedef vector< pair<int,int> > Seam;
typedef Seam VertSeam;
typedef Seam HorizonSeam;
typedef vector<Seam> SeamSet;
typedef vector< vector<CumEnergyElement> > CumEnMatrix; 
typedef vector< vector<TranspotElement> > TransMap;
//////////////////////////////////////////////////////////////////////////
enum SeamType
{
	Vertical,
	Horizontal,
};

enum ZoomType
{
	Enlarge,
	Shrink,
};

struct CumEnergyElement 
{
	float cumEnergy;
	int xPrevious;
	int yPrevious;
};

struct TranspotElement 
{
	float cumValue;
	Seam seam;
	SeamType seamType;
	ZoomType zoomType;
};

//////////////////////////////////////////////////////////////////////////
class CContentImResize
{
public:
	CContentImResize(void);
	~CContentImResize(void);
	
	//src and dst are supposed to have the same number of channels
	void ContentAwareImResize(CFloatImage& src, CFloatImage& dst);
	
private:
	void EnlargeImage(CFloatImage& src, CFloatImage& dst, int r, int c);
	void AddSeams(CFloatImage& src, CFloatImage& dst, const vector<Seam>& seamSet, SeamType seamType);
	void TransPath(CFloatImage& gray, CFloatImage& dst, vector<TranspotElement>& transPath);
	void TranspotMap(CFloatImage& gray, CFloatImage& dst, TransMap& transMap);
	void ShiftOneVertSeam(CFloatImage& src, CFloatImage& dst, VertSeam& Vseam, ZoomType zoomType);
	void ShiftOneHoriSeam(CFloatImage& src, CFloatImage& dst, HorizonSeam& Hseam, ZoomType zoomType);
	float FindHoriSeam(CShape& sh, vector< HorizonSeam >& Hseams, int seamNum);
	float FindVertSeam(CShape& sh, vector< VertSeam >& Vseams, int seamNum);
	
	void Initialization(CFloatImage& src);
	void SetLabelImage(CShape& sh, int label);
	void SetLabelImage(const SeamSet& seamSet, int label);
	void ComputeHoriCumEnMap();
	void ComputeVertCumEnMap();
	void EnergyGradient(CFloatImage& Hsrc, CFloatImage& Vsrc);
	void Convert2GrayFloat(CFloatImage& image, CFloatImage& grayFloatImage); 
	void MaskProcessing(CFloatImage& src, CFloatImage& dst, float *mask, int mkW, int mkH);
	
	//for test
	void SaveFloatImage(CFloatImage& image, const string& name, bool needNorm = false);
	void SaveImageWithSeams(CFloatImage& src, const string& name, const SeamSet& seamSet);
	//void SaveC

private:
	static float m_enlargeFraction;
	CFloatImage m_originImage;
	CFloatImage m_enMap;
	CIntImage m_labelImg;
	CumEnMatrix m_HCumEnMap;
	CumEnMatrix m_VCumEnMap;
	vector< pair<float,int> > m_lastRow;
	vector< pair<float,int> > m_lastColum;
};
