/* Pathogen Warrior
 * Copyright 2004 Jetro Lauha - http://iki.fi/jetro/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * $Id: BuildState.h,v 1.13 2004/07/14 15:37:09 tonic Exp $
 * $Revision: 1.13 $
 */

#ifndef BUILDSTATE_H_INCL
#define BUILDSTATE_H_INCL


#include <math.h>


enum BUILDSTATE_ENUM
{
    MAX_PROBLEM_STRUCTURE_LEVELS    = 3,
    TIME_PER_COMPOUND               = 9000,
};

enum MAP_NODE_TYPE
{
    MHT_BALL = 0,
    MHT_LINK
};


struct Position
{
    Position() {}
    Position(INT x, INT y) : x(x), y(y) {}
    INT x, y;
    bool operator==(const Position &rhs) { return x == rhs.x && y == rhs.y; }
    bool operator!=(const Position &rhs) { return x != rhs.x || y != rhs.y; }
};

struct MapNode
{
    MapNode(MAP_NODE_TYPE type) : type(type) {}
    MAP_NODE_TYPE type;
    Position position;
};

struct Color
{
    Color() {}
    Color(FLOAT r, FLOAT g, FLOAT b) : red(r), green(g), blue(b) {}
    FLOAT red, green, blue;
};

struct Direction
{
    FLOAT angle;
    FLOAT x, y, z;  // axis
};

struct BallNode : public MapNode
{
    BallNode(MAP_NODE_TYPE type) : MapNode(type) {}
    typedef std::set<BallNode *> BallNodeSet;

    BOOL inMap;
    Color color, mapColor;
    Direction direction;
    BallNodeSet children;
    BallNode *parent;
};

struct LinkNode : public MapNode
{
    LinkNode(MAP_NODE_TYPE type) : MapNode(type), link(0) {}
    UINT link;
};

struct TextRow
{
    typedef std::string String;
    TextRow(String str, UINT32 startTime, UINT32 age) :
        str(str), startTime(startTime), age(age)
        { color.red = color.green = color.blue = 1; }
    String str;
    UINT32 startTime, age;
    Color color;
};

struct ProblemConfiguration
{
    UINT8 levels;
    UINT8 branches[MAX_PROBLEM_STRUCTURE_LEVELS - 1];
    FLOAT rotation;
};


class BuildState : public State
{
public:

    BuildState();
    virtual ~BuildState();

    virtual BOOL init();
    virtual void deinit();

    virtual BOOL update(UINT32 time, App::KeyEventList &keyEvents);
    virtual void render(SDL_Surface *screen);

    virtual void onActivate(UINT32 /*tick*/);
    virtual void onDeactivate();

    virtual void onKeyDown(const SDLKey &key);
    virtual void onKeyUp(const SDLKey &key);
    virtual void onMouseDown(const SDL_MouseButtonEvent &event);
    virtual void onMouseUp(const SDL_MouseButtonEvent &event);
    virtual void onMouseMotion(const SDL_MouseMotionEvent &event);

    UINT32 getScore() { return mScore; }
    UINT32 getPathogenCount() { return mPathogenCount; }

protected:

    struct HexagonMapLessOp : public std::binary_function<Position, Position, bool>
    {
        bool operator() (const Position &p1, const Position &p2) const
        {
            INT32 p1ref = (p1.y << 16) | (p1.x & 0xffff);
            INT32 p2ref = (p2.y << 16) | (p2.x & 0xffff);
            return p1ref < p2ref;
        }
    };
    typedef std::map<Position, MapNode *, HexagonMapLessOp> HexagonMap;
    typedef std::vector<Color> ColorList;
    typedef std::list<TextRow> TextList;

    void createProblem();
    void clearProblem();
    BOOL verifyProblem();
    void mutateProblem();

    void mutateNodes(BallNode *node);
    INT buildNodes(BallNode *node, BallNode *parent, INT level, INT depth);
    void clearNode(BallNode *node);
    INT verifyNode(BallNode *node);
    void renderNode(BallNode *node, INT level);

    void renderModel();
    void render2D();
    void renderHexagonMap();

    UINT32 mTime;
    UINT32 mScore;
    UINT32 mPathogenCount;

    HexagonMap mMap;
    ColorList mColors;
    TextList mInfoText;

    BallNode mProblemRoot;

    UINT32 mProblemTime, mProblemStartTime;
    FLOAT mNormalizedProblemTime; // [0..1] is valid solving time
    UINT32 mGameOverTime;
    BOOL mGameOver;

    INT mMouseX, mMouseY;
    BOOL mHighlight;
    Position mHighlightNode;
    Position mDragStartNode;
    Position mMouseDownNode;
    BOOL mDragging;

    UINT32 mMutationTriggerTime;
    BOOL mMutationTriggerMutated;
    BOOL mMutationTriggerNewProblem;

    FLOAT mScrollX, mScrollY;
    FLOAT mScrollXDest, mScrollYDest;

    Position mMapImagePosition;
    BOOL mHighLightMapCircle;

    IMAGE mHexImage;
    IMAGE mBallImage;
    IMAGE mShineImage;
    IMAGE mLinkImages[3];
    IMAGE mMapImage;
    IMAGE mCircleImage;
    IMAGE mBlockImage;
    IMAGE mSquareImage;
    SDL_Surface *mMapMask;
};


#endif // !BUILDSTATE_H_INCL
