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

#pragma once

#include "glmSDKAPI.h"
#include "glmMemory.h"
#include "glmSimuEntityHandle.h"
#include "glmPODArray.h"
#include "glmEntity.h"

namespace glm
{
	class PerceptionContext;
	class Sensor;

    struct PerceivedObjectsArrays
    {
        PODArray<int64_t>* perceivedObjectsIndexes = NULL; // when a filter is applied, only the perceivedObjectsIndexes is changed
        PODArray<int>* perceivedObjects = NULL;
        PODArray<float>* perceivedObjectsDist = NULL;
        PODArray<int>* closestVoxelToPerceivedObject = NULL;
        PODArray<int>* closestPerceivedObjectVoxel = NULL;
        inline bool isValid() const;
    };

    class GLM_SDK_API SensorFilter
    {
    public:
        GLM_CLASS_STAT_ID(glm::MemoryStatIds::Simulation);

        virtual ~SensorFilter();

        virtual void filter(
            PerceptionContext* perceptionContext,
            const glm::SimuEntityHandle& handle,
            const Sensor& sensor,
            PerceivedObjectsArrays& perceivedObjectsData,
            int spatialEnvIndex) const;
    };

    class GLM_SDK_API MaxCountFilter : public SensorFilter
    {
    public:
        GLM_CLASS_STAT_ID(glm::MemoryStatIds::Simulation);

        size_t _maxCount;

        MaxCountFilter();
        virtual ~MaxCountFilter();

        void filter(
            PerceptionContext* perceptionContext,
            const glm::SimuEntityHandle& handle,
            const Sensor& sensor,
            PerceivedObjectsArrays& perceivedObjectsData,
            int spatialEnvIndex) const override;
    };

    class GLM_SDK_API NavMeshVisibilityFilter : public SensorFilter
    {
    public:
        GLM_CLASS_STAT_ID(glm::MemoryStatIds::Simulation);

        virtual ~NavMeshVisibilityFilter();

        void filter(
            PerceptionContext* perceptionContext,
            const glm::SimuEntityHandle& handle,
            const Sensor& sensor,
            PerceivedObjectsArrays& perceivedObjectsData,
            int spatialEnvIndex) const override;
    };

    class GLM_SDK_API SensorFilterOperator : public SensorFilter
    {
    public:
        GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation);
    };

    class GLM_SDK_API SensorFilterNotOperator : public SensorFilterOperator
    {
	public:
		GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation);

		SensorFilter* _operand;

		SensorFilterNotOperator();
		virtual ~SensorFilterNotOperator();

        void filter(
            PerceptionContext* perceptionContext,
            const glm::SimuEntityHandle& handle,
            const Sensor& sensor,
            PerceivedObjectsArrays& perceivedObjectsData,
            int spatialEnvIndex) const override;
    };

	class GLM_SDK_API SensorFilterAndOperator : public SensorFilterOperator
	{
	public:
		GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation);

		SensorFilter* _operand1;
		SensorFilter* _operand2;

		SensorFilterAndOperator();
		virtual ~SensorFilterAndOperator();

        void filter(
            PerceptionContext* perceptionContext,
            const glm::SimuEntityHandle& handle,
            const Sensor& sensor,
            PerceivedObjectsArrays& perceivedObjectsData,
            int spatialEnvIndex) const override;
    };

	class GLM_SDK_API SensorFilterOrOperator : public SensorFilterOperator
	{
	public:
		GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation);

		SensorFilter* _operand1;
		SensorFilter* _operand2;

		SensorFilterOrOperator();
		virtual ~SensorFilterOrOperator();

        void filter(
            PerceptionContext* perceptionContext,
            const glm::SimuEntityHandle& handle,
            const Sensor& sensor,
            PerceivedObjectsArrays& perceivedObjectsData,
            int spatialEnvIndex) const override;
    };

	class GLM_SDK_API SortDistFilter : public SensorFilter
	{
	public:
		GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation);

		bool _reverseOrder;

		SortDistFilter();
		virtual ~SortDistFilter();

        void filter(
            PerceptionContext* perceptionContext,
            const glm::SimuEntityHandle& handle,
            const Sensor& sensor,
            PerceivedObjectsArrays& perceivedObjectsData,
            int spatialEnvIndex) const override;
    };

	class GLM_SDK_API EntityTypeFilter : public SensorFilter
	{
	public:
		GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation);

		EntityTypeFilter();
		virtual ~EntityTypeFilter();

		glm::Array<glm::GlmString> _entityTypeNames;

        void filter(
            PerceptionContext* perceptionContext,
            const glm::SimuEntityHandle& handle,
            const Sensor& sensor,
            PerceivedObjectsArrays& perceivedObjectsData,
            int spatialEnvIndex) const override;
    };

	class GLM_SDK_API AttributeFilter : public SensorFilter
	{
	public:
		GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation);

		AttributeFilter();
		virtual ~AttributeFilter();

		glm::GlmString _attributeName;
		ComparisonOperator::Value _comparisonOperator;
		float _value;
		bool _useEntityIdAsValue;

        void filter(
            PerceptionContext* perceptionContext,
            const glm::SimuEntityHandle& handle,
            const Sensor& sensor,
            PerceivedObjectsArrays& perceivedObjectsData,
            int spatialEnvIndex) const override;
    };

    //-------------------------------------------------------------------------
    inline bool PerceivedObjectsArrays::isValid() const
    {
        return perceivedObjectsIndexes != NULL && perceivedObjects != NULL && perceivedObjectsDist != NULL && closestVoxelToPerceivedObject != NULL && closestPerceivedObjectVoxel != NULL;
    }
}
