/***************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A.  All Rights Reserved.                         *
*                                                                          *
***************************************************************************/

#pragma once

#include "glmPathDefinitions.h"
#include "glmSpawningCellData.h"

//golaem core includes
#include <glmCircle2.h>
#include <glmBox2.h>


namespace glm
{
	class LooseQuadtreeRootNode;

	/**
	* \brief 2D quad tree definition.
	*
	* \ingroup ...
	*
	* \author Golaem <dev@golaem.com>
	*
	* \tparam Data The data contained in each cell of the grid.
	*/
	class LooseQuadtreeNode 
	{
	public:

		friend class LooseQuadtreeRootNode;

		GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation)

		/** 
		* \brief Destructor.
		*/
		virtual ~LooseQuadtreeNode() ;

		/**
		* \brief Retrieve the depth of the current node.
		*/
		void setDepth( unsigned int depth ) ;
		unsigned int getDepth() const;

		/**
		* \brief Retrieve the resolution of the current node.
		*/
		void setResolution( Vector2 resolution ) ;
		Vector2 getResolution() const;

		/**
		* \brief Check if the current node is a leaf (ie has no children).
		*/
		virtual bool isLeaf() const;

		/**
		* \brief Check if the current node is a root (ie has no parent).
		*/
		virtual bool isRoot() const;

		const Vector2& getCenter() const ;

		const Vector2& getNodeSize() const ;

		/**
		* \brief Create children of the current node.
		* \pre The current node must be a leaf.
		*/
		virtual void createChildren( const SpawningCellData& defaultData = SpawningCellData() ) ;

		LooseQuadtreeNode* getRandomNodeAtDepth( RandomNumberGenerator& rng, unsigned int depth ) ;

		LooseQuadtreeNode* locate( Vector2& position, unsigned int depth ) ;

		void updateParentCellWeight() ;

		void initCellStatusHierarchy(RandomNumberGenerator& rng, RandomNumberGenerator& secondaryRng, bool quincunxPlacing = false ) ;

		/**
		*
		*/
		LooseQuadtreeNode* getParent() const ;

		/**
		*
		*/
		LooseQuadtreeRootNode* getRoot() ;

		/**
		* \name Children
		*/
		//@{
		LooseQuadtreeNode* getChild( const Quadrant::Value& quadrant ) const ;
		//@}

		/**
		* \name Data
		*/
		//@{
		const SpawningCellData& getData() const;
		SpawningCellData& touchData();
		void setData(const SpawningCellData& data);
		//@}

		/**
		* \name validate an slot position of this cell against LooseQuadTree geometry
		*/
        bool validatePositionAgainstRootGeometry(const Vector2& positionToTestInGeometry, float lateralClearance = 0) const;

        /**
		* \brief find neighbor positions for grouped placement
		*/
		void findNearestFreeNodes( unsigned int nbSlotsToPlace, glm::PODArray<LooseQuadtreeNode*>& freeZonesAroundPicked );

		/**
		* \brief returns true if the given slot does not collide with any slot this Spawning Zone
		*/
        bool isColliding(const PopulationSlot* slot, const Vector3& relativeSlotPosition, float maxClearance) const;

    protected:
        /**
		* default constructor
		*/
		LooseQuadtreeNode( );

		/**
		* constructor, private, for spawningZone use only
		*/
        LooseQuadtreeNode(LooseQuadtreeNode* parent,
                          Vector2& min,
                          Vector2& max,
                          unsigned int depth,
                          Vector2 resolution,
                          LooseQuadtreeRootNode* rootNode);

        /// Corners
        Vector2 _min;
        Vector2 _max;

    private:
        void computeSize() ;

		void computeCenter() ;

		void updateCellStatus() ;
		void computeCellWeight() ;
		
		LooseQuadtreeNode* getRandomChild( float randomCoef0To1 ) ;

		/// Parent
		LooseQuadtreeNode * _parent ;

		/// Current node size
		Vector2 _nodeSize ;



		/// Center
		Vector2 _center ;

		/// Children
		//glm::PODArray< LooseQuadtreeNode * > _children ;
		LooseQuadtreeNode* _children[4];

		// Data
		SpawningCellData _data ;

		/// Depth
		unsigned int _depth ;

		/// Depth
		Vector2 _resolution ;

		/// generated from this geometry
		LooseQuadtreeRootNode*	_rootNode;
	};
}
