#ifndef _HPP_KUNGFLOW_STAGE
#define _HPP_KUNGFLOW_STAGE

#include "gaia/gaia.hpp"
using namespace gaia;

//#include "stageentity.hpp"
#include "enemies/enemy.hpp"
#include "stadium.hpp"
#include <boost/signals2.hpp>

class KungFlowGame;
class PlayState;
//class Stage;
class StageEntity;
class HumanGamer;
class Character;
class CharacterModelView;
class CharacterController;
//class CharacterAIController;
//class HumanCharacterController;
//class Stadium;
//class Enemy;


//
// the Stage is the metaphorical platform on which the various entities/elements of the game live (characters, weather systems, storylines..)
// todo: make a choreography class for the storyline parts ? (triggers, attack patterns/cycles, env based timey stuff and such)
//

enum e_AIControllerType {
  e_AIControllerType_CoopBuddy,
  e_AIControllerType_Karateka,
  e_AIControllerType_Thrower,
  e_AIControllerType_Grunt
};

struct TacticalCouple {
  //int p1UniqueID;
  Character *p1;
  //int p2UniqueID;
  Character *p2;
};

struct MasterSlaveConnection {
  const Character *master;
  StageEntity *slave;
};

class Stage {

  public:

    Stage(const KungFlowGame *game, const PlayState *playState);//, int id);
    virtual ~Stage();

    void InitLevel(int levelID);

    void OnStepPhysicsTime();
    void Draw(const Viewport &viewport, const Camera &camera) const;
    void DrawLight(const Vector2 &worldPosition, float worldZPosition, const Vector2 &radius, float r, float g, float b) const;
    void DrawLight(const Vector2 &worldPosition, float worldZPosition, float radius, float r, float g, float b) const {
      DrawLight(worldPosition, worldZPosition, Vector2(radius), r, g, b);
    }
    void DrawShadow(const Vector2 &position, float zPosition, float scale, float intensity) const;

    //unsigned int GetID() const { return id; }

    void SpawnHumanCharacter(e_Team team, const Vector2 &position, const HumanGamer *humanGamer);
    void SpawnAICharacter(e_Team team, const Vector2 &position, e_AIControllerType aiControllerType);
    Enemy *SpawnEnemy(e_EnemyType enemyType, e_Team team, const Vector2 &position = _DEFAULTVECTOR, float zPosition = 0, const Vector2 &momentum = _DEFAULTVECTOR, float zMomentum = 0);
    //void AddStageEntityOwnership(Enemy *enemy);
    void AddEntityOwnership(StageEntity *entity); // makes entity part of the world of this stage
    void DeleteCharacters();
    void DeleteCharacter(Character *character);
    //void DeleteBadGuys();
    void DeleteEntities();

    void CheckCollisions();

    //void MoveStageEntity(StageEntity *entity, const Vector2 &newPosition) const;
    Vector2 CollideNewPosition(const StageEntity *entity, const Vector2 &currentPosition, const Vector2 &desiredPosition, float desiredZPosition) const;

    // utility functions
    void GetAllStageEntities(std::vector<StageEntity*> &targetContainer) const;
    Character *GetClosestCharacter(e_Team team, const Vector2 &focus, const Character *ignore = nullptr) const;
    std::vector<Character*> GetClosestCharacters(e_Team team, const Vector2 &focus, unsigned int num, const Character *ignore = nullptr) const;
    std::vector<Character*> GetCharacters(e_Team team, const Character *ignore = nullptr) const;
    const std::vector<Character*> &GetAllCharactersRef() const;
    const std::vector<Character*> &GetHumanCharactersRef() const;
    const std::vector<StageEntity*> &GetAllEntitiesRef() const;

    mutable boost::signals2::signal<void()> sig_PersonnelChange; // called when characters are added or deleted

    Vector2 GetAverageHumanCharacterPosition(float movementFactor, float flowDirectionFactor, float flowMovementFactor, float &averageHumanZPos_ret) const;
    Vector2 GetCameraFocusPositionProj() const;

    const Stadium *GetStadium() const { return stadium; }

    void AddMasterSlaveConnection(const Character *master, StageEntity *slave);
    void RemoveMasterSlaveConnection(const Character *master, const StageEntity *slave);
    const Character *GetMaster(const StageEntity *slave) const;
    StageEntity *GetSlave(const Character *master) const;

    void SetFlag(StageEntity *flag);
    StageEntity *GetFlag() const;

    void GetAssignedOpponentCharacters(const Character *character, std::vector<Character*> &opponents_ret) const;
    bool AreCharactersAssigned(const Character *p1, const Character *p2) const;

  private:

    const KungFlowGame *game;
    const PlayState *playState;

    //unsigned int id;

    Stadium *stadium;

    Object *shadowObject;
    Sprite *shadowSprite;

    std::vector<Character*> characters;
    std::vector<Character*> _humanCharacters;
    std::vector<StageEntity*> entities; // anything else than characters
    //std::vector<Enemy*> enemies;

    // tmp, for choreo
    //int triggeredEnemyCount;

    // cache
    void UpdateAssignmentMatrix();
    unsigned int timeSinceLastAssignmentMatrixUpdate_ms;
    unsigned int assignmentMatrixUpdateInterval_ms;
    // cached stuff:
    std::vector<TacticalCouple> tacticalCouples;

    std::vector<MasterSlaveConnection> masterSlaveConnections;

    StageEntity *flag;

    boost::signals2::connection personnelChangeConnection; // listens in on signal sig_PersonnelChange from this class itself :) so cute

};


//
// todo: a class for the 'choreography' of the world/level, maybe name it a 'Script' to stay in theater terminology ?
//


#endif
