#ifndef MATCH3FIELD_H_INCLUDED
#define MATCH3FIELD_H_INCLUDED

#include "include/Engine.h"
#include <Eigen/src/Core/Matrix.h>



const size_t CONST_MAX_FIELD_WIDTH = 11;
const size_t CONST_MAX_FIELD_HEIGHT = 11;


const float CONST_MATCH3_CELL_WIDTH = 42.f;
const float CONST_MATCH3_CELL_HEIGHT = 42.f;
const float CONST_CHIP_LOWEST_SPEED = -0.5f;
const float CONST_CHIP_ACCELERATION = -0.0014f;

/*
const float CONST_MATCH3_CELL_WIDTH = 32.f;
const float CONST_MATCH3_CELL_HEIGHT = 32.f;
const float CONST_CHIP_LOWEST_SPEED = -0.3f;
const float CONST_CHIP_ACCELERATION = -0.001f;
*/
const size_t CONST_MATCH_TIME = 150;

const float CONST_CHIP_POSITION_EPSILON = 1.f;
const float CONST_CHIP_VELOCITY_EPSILON = 0.3f;


const float CONST_CHIP_K = 0.4f;

const size_t CONST_CHIP_TYPE_COUNT = 4;


struct TChipTemplateParams : public SE::TSerializeInterface
{
	SE::THalibutExternalAnimObject SelectedTemplateAnimObject;
	SE::THalibutExternalAnimObject FinishingTemplateAnimObject;
	SE::TRenderParams SelectedRenderParams;
	SE::TRenderParams FinishingRenderParams;

	virtual void Serialize(boost::property_tree::ptree& propertyTree);

};

struct TMatch3FieldParams : public SE::TSerializeInterface
{
	size_t FieldWidth;
	size_t FieldHeight;
	float CellWidth;
	float CellHeight;
	float ChipLowestSpeed;
	float ChipAcceleration;

	float ChipPositionEpsilon;
	float ChipVelocityEpsilon;
	float ChipK;
	size_t ChipMatchTime;

	size_t ChipTypeCount;

	std::vector<TChipTemplateParams> ChipTemplateParamsArr;

	TMatch3FieldParams()
		: FieldWidth(CONST_MAX_FIELD_WIDTH)
		, FieldHeight(CONST_MAX_FIELD_HEIGHT)
		, CellWidth(CONST_MATCH3_CELL_WIDTH)
		, CellHeight(CONST_MATCH3_CELL_HEIGHT)
		, ChipLowestSpeed(CONST_CHIP_LOWEST_SPEED)
		, ChipAcceleration(CONST_CHIP_ACCELERATION)
		, ChipPositionEpsilon(CONST_CHIP_POSITION_EPSILON)
		, ChipVelocityEpsilon(CONST_CHIP_VELOCITY_EPSILON)
		, ChipK(CONST_CHIP_K)
		, ChipMatchTime(CONST_MATCH_TIME)
		, ChipTypeCount(CONST_CHIP_TYPE_COUNT)
	{
		 
	}
	
	
	virtual void Serialize(boost::property_tree::ptree& propertyTree);

};

struct TChip
{
	int ChipType; // -1 means empty field
	std::string AnimName; //Generated automatically

	SE::TRenderPairList::iterator RenderPair;

	size_t VertexListShift;

	float Velocity;

	enum TChipState
	{
		CS_STANDBY,
		CS_SWAPPING,
		CS_FALLING,
		CS_LOCKED,
		CS_FINISHING,
		CS_X,
	} ChipState;

	TChip(int chipType, SE::TRenderPairList::iterator renderPair, size_t vertexListShift, TChipState chipState = CS_FALLING);

	~TChip();

	Eigen::Vector2f GetLeftBottomPos();
	void SetLeftBottomPos(Eigen::Vector2f newPos);
	void MoveLeftBottomPos(Eigen::Vector2f shift);

	static int StaticAnimationIndex;
	
};


struct TChipSwappingPair
{
	float T;
	Eigen::Vector2i Chip1;
	Eigen::Vector2i Chip2;

	Eigen::Vector2f Chip1RealPosFrom;
	Eigen::Vector2f Chip2RealPosFrom;

	bool IsReturning;


	TChipSwappingPair(Eigen::Vector2i chip1, Eigen::Vector2i chip2, Eigen::Vector2f chip1PosFrom, Eigen::Vector2f chip2PosFrom)
		: Chip1(chip1)
		, Chip2(chip2)
		, T(0)
		, Chip1RealPosFrom(chip1PosFrom)
		, Chip2RealPosFrom(chip2PosFrom)
		, IsReturning(false)
	{
	}

};

struct TChipDeletingData
{
	float T;
	Eigen::Vector2i Chip;
	Eigen::Vector2f Pos;

	TChipDeletingData(Eigen::Vector2i chip, Eigen::Vector2f pos)
		: T(0.f)
		, Chip(chip)
		, Pos(pos)
	{
	}
};



class TMatch3Logic
{
protected:

	size_t ChipTypeCount;

	std::vector<std::vector<TChip> > ChipMatrix;
	std::vector<TChipSwappingPair> ChipSwappingPairVector;
	std::vector<TChipDeletingData> ChipDeletingVector;

	std::vector<SE::TRenderPairList::iterator> RenderPairIteratorVector;

	Eigen::Vector2i selectedChip;

	Eigen::Vector2f LeftBottomPosField;

	TMatch3FieldParams Match3FieldParams;

	void FillRandomChipMatrix(std::vector<SE::TRenderPairList::iterator> renderPairIteratorVector, Eigen::Vector2f leftBottomPos);

	Eigen::Vector2f GetExpectedLeftBottomPos(size_t x, size_t y);

	void StartAnimateChip(size_t x, size_t y);
	void StopAnimateChip(size_t x, size_t y);

	bool ChipIsLocked(Eigen::Vector2i chip);
	bool ChipIsFinishing(Eigen::Vector2i chip);
	bool ChipIsStable(Eigen::Vector2i chip);
	bool ChipCanBeSelected(Eigen::Vector2i chip);
	bool ChipsCanBeSwapped(Eigen::Vector2i p1, Eigen::Vector2i p2);

	bool ChipCanBeMatchedUp(Eigen::Vector2i chip);
	bool ChipCanBeMatchedDown(Eigen::Vector2i chip);
	bool ChipCanBeMatchedLeft(Eigen::Vector2i chip);
	bool ChipCanBeMatchedRight(Eigen::Vector2i chip);

	void UnmatchChips(std::vector<Eigen::Vector2i> chipList);
	void UpdateChipPosition(size_t dt);
	void RemoveBubbles();

	void ReplaceAnimation(Eigen::Vector2i p);

	void MoveVertexListShiftBack(SE::TRenderPairList::iterator renderPairItr, size_t moveFrom);
	void MoveVertexListShiftBackWithoutAnimation(SE::TRenderPairList::iterator renderPairItr, size_t moveFrom);
	void MoveVertexCoordDown(SE::TRenderPairList::iterator renderPairItr, size_t moveFrom, float value);

	void AddChipToUp(size_t colNum, int chipType, Eigen::Vector2f spawnPos, TChip::TChipState chipState = TChip::CS_FALLING);
	void InnerAddChipToUp(size_t colNum, int chipType, Eigen::Vector2f spawnPos, TChip::TChipState chipState = TChip::CS_FALLING);

	void InsertEmptyChip(size_t colNum, size_t rowNum, int chipType);

	void UpdateChipSwapping(size_t dt);
	void TryMatchAllChips();

	void DestroyChip(Eigen::Vector2i p);

	void ChangeChipType(Eigen::Vector2i p);

	void innerUpdateAnimation(size_t dt);

public:

	TMatch3Logic();
	virtual ~TMatch3Logic();

	void SelectChip(Eigen::Vector2i pos);
	void UnselectChip();
	Eigen::Vector2i GetSelectedChip();

	std::vector<Eigen::Vector2i> GetAvailableMatchingChips();

	void SwapChips(Eigen::Vector2i p1, Eigen::Vector2i p2, bool isReturning = false);

	void ResetChipPos(Eigen::Vector2i p);

	void UpdateLogic(size_t dt);

	void HitFieldWithPattern(Eigen::Vector2i pos, std::vector<std::vector<char> > pattern, std::vector<std::vector<char> > jumpingPattern);


};



class TMatch3Controller;

class TMatch3Field : protected TMatch3Logic
{
protected:
	 void FillBasicChipMatrixAndTriangleList();
	 
	 //TMatch3Controller& Match3Controller;

	 Eigen::Vector2f LastTappedPos;
	 Eigen::Vector2f LastMovePos;

	 Eigen::Vector2i PosToChip(Eigen::Vector2f pos);


public:
	//should be in protected
	Eigen::Vector2f LeftBottomPos;
	SE::TRenderPairList TriangleListVector;


	TMatch3Field();
	TMatch3Field(const TMatch3Field& m);
	TMatch3Field& operator=(const TMatch3Field& m);
	
	TMatch3Field(TMatch3Controller& match3Controller);
	~TMatch3Field();

	virtual void Update(size_t dt);
	virtual void OnTapDown(Eigen::Vector2f pos);
	virtual void OnTapUp(Eigen::Vector2f pos);
	virtual void OnMove(Eigen::Vector2f shift);
	virtual bool CheckClick(Eigen::Vector2f mousePos);

	void HighlightMatch3();
	
};




#endif
