#ifndef _CCB_CCBREADER_H_
#define _CCB_CCBREADER_H_

#include "cocos2d.h"
#include "ExtensionMacros.h"
#include <string>
#include <vector>

#define CCB_STATIC_NEW_AUTORELEASE_OBJECT_METHOD(T, METHOD) static T * METHOD() { \
    T * ptr = new T(); \
    if(ptr != NULL) { \
        ptr->autorelease(); \
        return ptr; \
    } \
    CC_SAFE_DELETE(ptr); \
    return NULL; \
}

#define CCB_STATIC_NEW_AUTORELEASE_OBJECT_WITH_INIT_METHOD(T, METHOD) static T * METHOD() { \
    T * ptr = new T(); \
    if(ptr != NULL && ptr->init()) { \
        ptr->autorelease(); \
        return ptr; \
    } \
    CC_SAFE_DELETE(ptr); \
    return NULL; \
}

#define kCCBVersion 3

enum {
    kCCBPropTypePosition = 0,
    kCCBPropTypeSize,
    kCCBPropTypePoint,
    kCCBPropTypePointLock,
    kCCBPropTypeScaleLock,
    kCCBPropTypeDegrees,
    kCCBPropTypeInteger,
    kCCBPropTypeFloat,
    kCCBPropTypeFloatVar,
    kCCBPropTypeCheck,
    kCCBPropTypeSpriteFrame,
    kCCBPropTypeTexture,
    kCCBPropTypeByte,
    kCCBPropTypeColor3,
    kCCBPropTypeColor4FVar,
    kCCBPropTypeFlip,
    kCCBPropTypeBlendmode,
    kCCBPropTypeFntFile,
    kCCBPropTypeText,
    kCCBPropTypeFontTTF,
    kCCBPropTypeIntegerLabeled,
    kCCBPropTypeBlock,
	kCCBPropTypeAnimation,
    kCCBPropTypeCCBFile,
    kCCBPropTypeString,
    kCCBPropTypeBlockCCControl,
    kCCBPropTypeFloatScale
};

enum {
    kCCBFloat0 = 0,
    kCCBFloat1,
    kCCBFloatMinus1,
    kCCBFloat05,
    kCCBFloatInteger,
    kCCBFloatFull
};

enum {
    kCCBPlatformAll = 0,
    kCCBPlatformIOS,
    kCCBPlatformMac
};

enum {
    kCCBTargetTypeNone = 0,
    kCCBTargetTypeDocumentRoot = 1,
    kCCBTargetTypeOwner = 2,
};

enum
{
    kCCBKeyframeEasingInstant,
    
    kCCBKeyframeEasingLinear,
    
    kCCBKeyframeEasingCubicIn,
    kCCBKeyframeEasingCubicOut,
    kCCBKeyframeEasingCubicInOut,
    
    kCCBKeyframeEasingElasticIn,
    kCCBKeyframeEasingElasticOut,
    kCCBKeyframeEasingElasticInOut,
    
    kCCBKeyframeEasingBounceIn,
    kCCBKeyframeEasingBounceOut,
    kCCBKeyframeEasingBounceInOut,
    
    kCCBKeyframeEasingBackIn,
    kCCBKeyframeEasingBackOut,
    kCCBKeyframeEasingBackInOut,
};

enum
{
    kCCBPositionTypeRelativeBottomLeft,
    kCCBPositionTypeRelativeTopLeft,
    kCCBPositionTypeRelativeTopRight,
    kCCBPositionTypeRelativeBottomRight,
    kCCBPositionTypePercent,
    kCCBPositionTypeMultiplyResolution,
};

enum
{
    kCCBSizeTypeAbsolute,
    kCCBSizeTypePercent,
    kCCBSizeTypeRelativeContainer,
    kCCBSizeTypeHorizontalPercent,
    kCCBSizeTypeVerticalPercent,
    kCCBSizeTypeMultiplyResolution,
};

enum
{
    kCCBScaleTypeAbsolute,
    kCCBScaleTypeMultiplyResolution
};


NS_CC_EXT_BEGIN

/**
 * @addtogroup cocosbuilder
 * @{
 */

class CCBFile : public CCNode
{
private:
    CCNode *mCCBFileNode;
    
public:
    CCBFile();
    
    static CCBFile* create();
    
    CCNode* getCCBFileNode();
    void setCCBFileNode(CCNode *pNode); // retain
};

/* Forward declaration. */
class CCNodeLoader;
class CCNodeLoaderLibrary;
class CCNodeLoaderListener;
class CCBMemberVariableAssigner;
class CCBSelectorResolver;
class CCBAnimationManager;
class CCData;
class CCBKeyframe;

/**
 * @brief Parse CCBI file which is generated by CocosBuilder
 */
class CCBReader : public CCObject 
{
private:
    CCData *mData;
    unsigned char *mBytes;
    int mCurrentByte;
    int mCurrentBit;
    
    std::vector<CCString *> mStringCache;
    std::set<std::string> mLoadedSpriteSheets;
    
    CCObject *mOwner;
    
    CCBAnimationManager *mActionManager;
    std::set<std::string> *mAnimatedProps;

    CCNodeLoaderLibrary *mCCNodeLoaderLibrary;
    CCNodeLoaderListener *mCCNodeLoaderListener;
    CCBMemberVariableAssigner *mCCBMemberVariableAssigner;
    CCBSelectorResolver *mCCBSelectorResolver; 

public:
    CCBReader(CCNodeLoaderLibrary *pCCNodeLoaderLibrary, CCBMemberVariableAssigner *pCCBMemberVariableAssigner = NULL, CCBSelectorResolver *pCCBSelectorResolver = NULL, CCNodeLoaderListener *pCCNodeLoaderListener = NULL);
    CCBReader(CCBReader *pCCBReader);
    virtual ~CCBReader();
    CCBReader();
    
    bool initWithData(CCData *pData, CCObject *pOwner);
    
    CCNode* readNodeGraphFromFile(const char *pCCBFileName);
    CCNode* readNodeGraphFromFile(const char *pCCBFileName, CCObject *pOwner);
    CCNode* readNodeGraphFromFile(const char *pCCBFileName, CCObject *pOwner, const CCSize &parentSize);
    CCNode* readNodeGraphFromFile(const char *pCCBFileName, CCObject *pOwner, CCBAnimationManager **ppAnimationManager);
    CCNode* readNodeGraphFromFile(const char *pCCBFileName, CCObject *pOwner, const CCSize &parentSize, CCBAnimationManager **ppAnimationManager);
    
    CCNode* readNodeGraphFromData(CCData *pData, CCObject *pOwner, const CCSize &parentSize, CCBAnimationManager **ppAnimationManager);
    CCNode* readNodeGraphFromData(CCData *pData, CCObject *pOwner, const CCSize &parentSize);
    
    CCScene* createSceneWithNodeGraphFromFile(const char *pCCBFileName);
    CCScene* createSceneWithNodeGraphFromFile(const char *pCCBFileName, CCObject *pOwner);
    CCScene* createSceneWithNodeGraphFromFile(const char *pCCBFileName, CCObject *pOwner, const CCSize &parentSize);
    CCScene* createSceneWithNodeGraphFromFile(const char *pCCBFileName, CCObject *pOwner, CCBAnimationManager **ppAnimationManager);
    CCScene* createSceneWithNodeGraphFromFile(const char *pCCBFileName, CCObject *pOwner, const CCSize &parentSize, CCBAnimationManager **ppAnimationManager);

    CCBMemberVariableAssigner* getCCBMemberVariableAssigner();
    CCBSelectorResolver* getCCBSelectorResolver();
    
    CCBAnimationManager* getAnimationManager();
    void setAnimationManager(CCBAnimationManager *pAnimationManager);
    
    // Used in CCNodeLoader::parseProperties()
    std::set<std::string>* getAnimatedProperties();
    std::set<std::string>& getLoadedSpriteSheet();
    CCObject* getOwner();

    /* Utility methods. */
    static CCString* lastPathComponent(CCString * pString);
    static CCString* deletePathExtension(CCString * pString);
    static CCString* toLowerCase(CCString * pCCString);
    static bool endsWith(CCString * pString, CCString * pEnding);
    static CCString* concat(CCString * pStringA, CCString * pStringB);

    /* Parse methods. */
    int readInt(bool pSigned);
    unsigned char readByte();
    bool readBool();
    float readFloat();
    CCString* readCachedString();
    
    static float getResolutionScale();
    
    CCNode* readFileWithCleanUp(bool bCleanUp);
    bool hasScriptingOwner;    

private:
    void cleanUpNodeGraph(CCNode *pNode);
    bool readSequences();
    CCBKeyframe* readKeyframe(int type);
    
    bool readHeader();
    bool readStringCache();
    void readStringCacheEntry();
    CCNode* readNodeGraph();
    CCNode* readNodeGraph(CCNode * pParent);

    bool getBit();
    void alignBits();
    CCString* readUTF8();

};

// end of effects group
/// @}

NS_CC_EXT_END

#endif