#ifndef GAME_H
#define GAME_H

#include <SFML/Window.hpp>
#include <Box2D/Box2D.h>

#include "poly2tri/poly2tri.h"

#include "DebugDraw.h"
#include "userdata.h"
class b2dJson;

enum _mouseState {
    MS_LEFT     = 0x1,
    MS_RIGHT    = 0x2
};

enum _keyState {
    KS_LEFT     = 0x01,
    KS_RIGHT    = 0x02,
    KS_UP       = 0x04,
    KS_DOWN     = 0x08,
    KS_JUMP     = 0x10
};

struct scheduledEvent {
    int m_eventId;
    float m_scheduledTime;
};

struct speechBubble {
    string m_message;
    float m_expiryTime;
};

struct kitten {
    b2Body* m_body;
    int numFeetOnGround;
    float nextJumpTime;

    kitten() {
        m_body = NULL;
        numFeetOnGround = 0;
        nextJumpTime = 0;
    }
};

struct myTriangle {
    b2Body* m_body;
    b2Vec2 m_points[3];
};

struct imageLocation {
    b2Body* m_body;
    sf::Texture m_texture;
    b2Vec2 m_points[4];
};

class Game : public b2ContactListener {
public:
    b2World* m_world;
    DebugDraw m_debugDraw;

    b2Vec2 m_viewCenter;
    float m_viewVerticalSpan;

    bool m_started;
    bool m_paused;

    vector<class Entity*> m_entities;

    //any better way to track using SFML features??
    int m_keyState;
    int m_mouseState;
    sf::Vector2i m_currentMousePos;

    sf::Clock m_clock;

    b2Body* m_playerUpper;
    b2Body* m_playerLower;
    b2WheelJoint* m_playerWheel;

    b2Body* m_buddyUpper;
    b2Body* m_buddyLower;
    b2WheelJoint* m_buddyWheel;

    b2Fixture* m_playerUpperFixture;
    b2Fixture* m_playerJumpableFixture;
    b2Fixture* m_buddyUpperFixture;
    b2Fixture* m_buddyJumpableFixture;
    b2Fixture* m_carLowerFixture;
    int m_jumpableFixtureContactCount;
    float m_playerJumpableTimeout;
    b2Vec2 m_cameraTrailPoint;

    map<string, b2Joint*> m_namedJointsMap;
    map<string, b2Fixture*> m_namedFixturesMap;
    vector<b2Fixture*> m_fixturesToDeleteAfterStep;
    vector<b2Joint*> m_jointsToDeleteAfterStep;

    vector<scheduledEvent> m_scheduledEvents;

    speechBubble m_playerSpeechBubble;
    speechBubble m_buddySpeechBubble;

    vector<kitten*> m_kittens;

    vector<myTriangle> m_earthTriangles;
    vector<myTriangle> m_woodTriangles;
    vector<myTriangle> m_stoneTriangles;

    sf::Texture m_earthImage;
    sf::Texture m_woodImage;
    sf::Texture m_stoneImage;

    vector<imageLocation*> m_imageLocations0;//background
    vector<imageLocation*> m_imageLocations1;//trees etc
    vector<imageLocation*> m_imageLocations2;//players etc

public:
    Game();
    ~Game();

    void clearWorld();
    bool setup();
    void step();

    void setPause(bool p);
    void togglePause();

    void loadImages();
    void clearImages();
    void loadEvents(b2dJson& json);
    void loadNamedJoints(b2dJson& json);
    void loadNamedFixtures(b2dJson& json);
    void loadKittens(b2dJson& json);
    void loadImageLocations(b2dJson& json);
    void buildTriangles(b2dJson& json);
    void destroyJoint(string name);
    void destroyFixture(string name);
    void clearReferencesToJoint(b2Joint* j);
    void clearReferencesToFixture(b2Fixture* f);
    void scheduleEvent(int eventId, float timeAheadSeconds);
    void setSpeech(int actorId, string msg, float timeoutSeconds);

    void setViewCenter(b2Vec2 center) { m_viewCenter = center; }
    void setViewVerticalSpan(float worldUnits) { m_viewVerticalSpan = worldUnits; }
    void applyView(sf::RenderWindow& window);
    b2Vec2 pixelToWorld(sf::RenderWindow& window, sf::Vector2f pixelLocation);
    sf::Vector2f worldToPixel(sf::RenderWindow& window, b2Vec2 worldLocation);

    b2Vec2 pixelToWorld_vector(sf::RenderWindow& window, sf::Vector2f pixelVector);

    void keyDown(sf::RenderWindow& window, sf::Event::KeyEvent keyEvent);
    void keyUp(sf::RenderWindow& window, sf::Event::KeyEvent keyEvent);
    void mouseDown(sf::RenderWindow& window, sf::Event::MouseButtonEvent mouseButtonEvent);
    void mouseUp(sf::RenderWindow& window, sf::Event::MouseButtonEvent mouseButtonEvent);
    void mouseMove(sf::RenderWindow& window, sf::Event::MouseMoveEvent mouseMoveEvent);
    void mouseWheel(sf::RenderWindow& window, sf::Event::MouseWheelEvent mouseWheelEvent);

    void renderWorld(sf::RenderWindow& window);
    void renderOverlay(sf::RenderWindow& window, sf::Text& sftext);

    void BeginContact(b2Contact* contact);
    void EndContact(b2Contact* contact);

    void checkEventSensor( b2Fixture* fixtureA, b2Fixture* fixtureB );
};

extern Game* g_game;

#endif

