#pragma once

#include "EventListener.h"
#include "BlockType.h"
#include "ReferenceCounter.h"
#include "EventThrower.h"
#include "Item.h"
#include "Inventory.h"

#include <Trie.h>
#include <Vec3.h>

class BlockType;
class ItemType;
class Chunk;
class BasicBlockItemType;

class TickQueue;

class Block : public Inventory
{
private:
    int ticksLeftCounter;
    int currentTickTimeout;
    bool wasTicked;
    bool onTickCalled;

protected:
    bool transparent;
    bool passable;
    float hp;
    float maxHP;
    float hardness;
    const BlockType *zType;
    ItemType *zTool;
    float speedModifier;
    Block *neighbours[ 6 ];

    int minTickTimeout;
    int maxTickTimeout;
    bool tickSource;

    /// <summary>
    /// executes block specific things
    /// </summary>
    /// <param name="zqueue">a queue to add neighbor blocks that should be ticked after this block</param>
    /// <param name="numTicks">the number of ticks passed since the last call (only for tickSources)</param>
    /// <param name="blocked">can be set to one to tell that this block needs to be tickt again later in the queue of this tick</param>
    /// <returns>true, iff the block needs to be ticked more often</returns>
    virtual bool onTick( TickQueue *zQueue, int numTicks, bool &blocked ) = 0;
    /// <summary>
    /// gets called after each block was tickt.
    /// the order of blocks called will be exactly the same as onTick
    /// </summary>
    virtual void onPostTick() = 0;

public:
    Block( const BlockType *zType, ItemType *zTool, Framework::Vec3<int> pos );

    void tick( TickQueue *zQueue );
    void postTick();

    bool isTickSource() const;
    const BlockType *zBlockType() const;
    bool isTransparent() const;
    bool isPassable() const;
    float getHP() const;
    float getMaxHP() const;
    float getHardness() const;
    ItemType *zEffectiveTool() const;
    float getSpeedModifier() const;
    const Framework::Vec3<int> getPos() const;

    friend Chunk;
    friend BlockType;
};

class BasicBlockItem : public Item
{
protected:
    bool transparent;
    bool passable;
    float hp;
    float maxHP;
    float hardness;
    int toolId;
    float speedModifier;

public:
    BasicBlockItem( const ItemType *zType, const char *name );
    virtual bool canBeStackedWith( Item *zItem ) const override;

    friend BasicBlockItemType;
    friend BlockType;
};

class BasicBlockItemType : public ItemType
{
protected:
    BasicBlockItemType( int id, ItemSkillLevelUpRule *levelUpRule, const ItemType *zBrokenType );
    virtual void loadSuperItem( Item *zItem, Framework::StreamReader *zReader ) const override;
    virtual void saveSuperItem( const Item *zItem, Framework::StreamWriter *zWriter ) const override;
    void initializeItem( BasicBlockItem *zItem, bool transparent, bool passable, float hp, float maxHP, float hardness, int toolId, float speedModifier ) const;
};