#ifndef __LSGRM_GRAPH_OPERATIONS_H
#define __LSGRM_GRAPH_OPERATIONS_H
#include "lsgrmHeader.h"
#include "lsrmGraphOperations.h"
#include "otbImageFileReader.h"

namespace lsgrm
{
	struct ProcessingTile
	{
		long int rows[2]; // lower and upper rows (-1 means that the row has not be considered)
		long int columns[2]; // lower and upper columns (-1 means that the row has not be considered)
		long int tileNeighbors[8]; // tile Neighbors at (top, top right, right, bottom right, bottom, bottom left, left, top left)
		bool margin[4]; // Is there a margin at top, left, bottom or right
	};


	template<class TSegmenter>
	void MergeAllGraphsAndAchieveSegmentation(const typename TSegmenter::ParameterType& params,
											  const float& threshold,
											  std::vector<ProcessingTile>& tiles,
											  const std::string& tmpDir,
											  const unsigned int nbTilesX,
											  const unsigned int nbTilesY,
											  const unsigned int tileWidth,
											  const unsigned int tileHeight,
											  const unsigned int imageWidth,
											  const unsigned int imageHeight,
											  const unsigned int imageBands,
											  bool& isFusion,
											  const std::string& outputGraphDirectory);
	
	template<class TSegmenter>
		long long unsigned int RunFirstPartialSegmentation(const typename TSegmenter::ParameterType& params,
														   const float& threshold,
														   const unsigned int niter,
														   std::vector<ProcessingTile>& tiles,
														   const std::string& tileDir,
														   const unsigned int nbTilesX,
														   const unsigned int nbTilesY,
														   const unsigned int margin,
														   const unsigned int tileWidth,
														   const unsigned int tileHeight,
														   const unsigned int imageWidth,
														   const unsigned int imageHeight,
														   const std::string& tmpDir,
														   bool& isFusion);

	template<class TSegmenter>
		long long unsigned int RunPartialSegmentation(const typename TSegmenter::ParameterType& params,
													  const float& threshold,
													  const unsigned int niter,
													  const unsigned int niter2,
													  std::vector<ProcessingTile>& tiles,
													  const std::string& tmpDir,
													  const unsigned int nbTilesX,
													  const unsigned int nbTilesY,
													  const unsigned int tileWidth,
													  const unsigned int tileHeight,
													  const unsigned int imageWidth,
													  const unsigned int imageHeight,
													  const unsigned int imageBands,
													  bool& isFusion);

	template<class TSegmenter>
	void RemoveUselessNodes(ProcessingTile& tile,
							typename TSegmenter::GraphType& graph,
							const unsigned int rowTile,
							const unsigned int colTile,
							const unsigned int nbTilesX,
							const unsigned int nbTilesY,
							const unsigned int imageWidth,
							const unsigned int numberOfLayers);


	template<class TSegmenter>
	void UpdateNeighborsOfNoneDuplicatedNodes(std::unordered_map<long unsigned int,
											  std::vector<typename TSegmenter::NodePointerType> >& borderPixelMap,
											  const unsigned int imageWidth,
											  const unsigned int imageHeight);

	template<class TSegmenter>
	void RemoveDuplicatedNodes(std::unordered_map<long unsigned int,
							   std::vector<typename TSegmenter::NodePointerType> >& borderPixelMap,
							   typename TSegmenter::GraphType& graph,
							   const unsigned int imageWidth);

	template<class TSegmenter>
	void BuildBorderPixelMap(typename TSegmenter::GraphType& graph,
							 ProcessingTile& tile,
							 const unsigned int rowTile,
							 const unsigned int colTile,
							 const unsigned int nbTilesX,
							 const unsigned int nbTilesY,
							 std::unordered_map<long unsigned int,
							 std::vector<typename TSegmenter::NodePointerType> >& borderPixelMap,
							 const unsigned int imageWidth);

	template<class TSegmenter>
	void AddStabilityMargin(typename TSegmenter::GraphType& graph,
							ProcessingTile& tile,
							const std::string& tmpDir,
							const unsigned int row,
							const unsigned int col,
							const unsigned int nbTilesX,
							const unsigned int nbTilesY,
							const unsigned int tileWidth,
							const unsigned int tileHeight);

	template<class TSegmenter>
		void WriteStabilityMargin(std::unordered_map<
								  typename TSegmenter::NodePointerType,
								  unsigned int>& stabilityMargin,
								  const std::string& nodesPath,
								  const std::string& edgesPath);

	template<class TSegmenter>
		void ExtractStabilityMargin(std::unordered_map<typename TSegmenter::NodePointerType, unsigned int>& nodeMap,
									const unsigned int pmax);

	template<class TSegmenter>
		void ExploreDFS(typename TSegmenter::NodePointerType s,
						const unsigned int p,
						std::unordered_map<typename TSegmenter::NodePointerType, unsigned int>& Cb,
						const unsigned int pmax);

	template<class TSegmenter>
		void DetectBorderNodes(typename TSegmenter::GraphType& graph,
							   ProcessingTile& tile,
							   std::unordered_map<typename TSegmenter::NodePointerType, unsigned int>& borderNodeMaps,
							   const unsigned int imageWidth,
							   const unsigned int imageHeight);

	template<class TSegmenter>
		void ReadGraph(typename TSegmenter::GraphType& graph,
					   const std::string& nodesPath,
					   const std::string& edgesPath);

	template<class TSegmenter>
		void WriteGraph(typename TSegmenter::GraphType& graph,
						const std::string& tmpDir,
						const unsigned int row,
						const unsigned int col);

	template<class TSegmenter>
		long long unsigned int GetGraphMemory(typename TSegmenter::GraphType& graph);
	
	template<class TSegmenter>
		void RemoveUnstableSegments(typename TSegmenter::GraphType& graph,
									ProcessingTile& tile,
									const unsigned int imageWidth);

	template<class TSegmenter>
		void RemoveEdgeToUnstableNode(typename TSegmenter::NodePointerType nodePtr);

	template<class TSegmenter>
		void RescaleGraph(typename TSegmenter::GraphType& graph,
						  ProcessingTile& tile,
						  const unsigned int rowTile,
						  const unsigned int colTile,
						  const unsigned int margin,
						  const unsigned int tileWidth,
						  const unsigned int tileHeight,
						  const unsigned int imageWidth);
}

#include "lsgrmGraphOperations.txx"
#endif