#ifndef __FLASHSCRIPTC_H__
#define __FLASHSCRIPTC_H__


#include "PajaTypes.h"
#include "Vector2C.h"
#include "Matrix2C.h"
#include "ColorC.h"
#include "BBox2C.h"
#include <vector>

#include "SWFChar.h"
#include "SWFDispList.h"
#include "SWFFont.h"
#include "SWFShape.h"
#include "SWFText.h"
#include "SWFDictionaryC.h"
#include "SWFSpriteC.h"
#include "SWFBitmapC.h"

//
// Parsed flags
//

enum FillE {
	FILL_GRADIENT			=   0x10,
	FILL_LINEARGRADIENT		=   0x10,
	FILL_RADIALGRADIENT		=   0x12,
	FILL_BITS				=   0x40    // Texture/bitmap fills, if this bit is set, must be a bitmap pattern
};

enum ShapeE {
	SHAPE_MOVETO		= 0x01,
	SHAPE_FILL0			= 0x02,
	SHAPE_FILL1			= 0x04,
	SHAPE_LINE			= 0x08,
	SHAPE_NEWSTYLES		= 0x10,
	SHAPE_END			= 0x80  // a state change with no change marks the end
};

enum Font2E {
	FONT2_BOLD			= 0x01,
	FONT2_ITALIC		= 0x02,
	FONT2_WIDECODES		= 0x04,
	FONT2_WIDEOFFSETS	= 0x08,
	FONT2_ANSI			= 0x10,
	FONT2_UNICODE		= 0x20,
	FONT2_SHIFTJIS		= 0x40,
	FONT2_HASLAYOUT		= 0x80
};

enum FontInfoE {
	FONTINFO_UNICODE	= 0x20,
	FONTINFO_SHIFTJIS	= 0x10,
	FONTINFO_ANSI		= 0x08,
	FONTINFO_ITALIC		= 0x04,
	FONTINFO_BOLD		= 0x02,
	FONTINFO_WIDECODES	= 0x01
};

enum TextE {
	TEXT_ISCONTROL	= 0x80,
	TEXT_HASFONT	= 0x08,
	TEXT_HASCOLOR	= 0x04,
	TEXT_HASYOFFSET	= 0x02,
	TEXT_HASXOFFSET	= 0x01
};


//
// Tag values that represent actions or data in a Flash script.
//

enum { 
	TAG_END 				= 0,
	TAG_SHOWFRAME			= 1,
	TAG_DEFINESHAPE 		= 2,
	TAG_FREECHARACTER		= 3,
	TAG_PLACEOBJECT 		= 4,
	TAG_REMOVEOBJECT		= 5,
	TAG_DEFINEBITS			= 6,
	TAG_DEFINEBUTTON		= 7,
	TAG_JPEGTABLES			= 8,
	TAG_SETBACKGROUNDCOLOR	= 9,
	TAG_DEFINEFONT			= 10,
	TAG_DEFINETEXT			= 11,
	TAG_DOACTION			= 12,
	TAG_DEFINEFONTINFO		= 13,
	TAG_DEFINESOUND 		= 14,	// Event sound tags.
	TAG_STARTSOUND			= 15,
	TAG_DEFINEBUTTONSOUND	= 17,
	TAG_SOUNDSTREAMHEAD 	= 18,
	TAG_SOUNDSTREAMBLOCK	= 19,
	TAG_DEFINEBITSLOSSLESS	= 20,	// A bitmap using lossless zlib compression.
	TAG_DEFINEBITSJPEG2 	= 21,	// A bitmap using an internal JPEG compression table.
	TAG_DEFINESHAPE2		= 22,
	TAG_DEFINEBUTTONCXFORM	= 23,
	TAG_PROTECT 			= 24,	// This file should not be importable for editing.

	// These are the new tags for Flash 3.
	TAG_PLACEOBJECT2		= 26,	// The new style place w/ alpha color transform and name.
	TAG_REMOVEOBJECT2		= 28,	// A more compact remove object that omits the character tag (just depth).
	TAG_DEFINESHAPE3		= 32,	// A shape V3 includes alpha values.
	TAG_DEFINETEXT2 		= 33,	// A text V2 includes alpha values.
	TAG_DEFINEBUTTON2		= 34,	// A button V2 includes color transform, alpha and multiple actions
	TAG_DEFINEBITSJPEG3 	= 35,	// A JPEG bitmap with alpha info.
	TAG_DEFINEBITSLOSSLESS2 = 36,	// A lossless bitmap with alpha info.
	TAG_DEFINEEDITTEXT		= 37,	// An editable Text Field
	TAG_DEFINESPRITE		= 39,	// Define a sequence of tags that describe the behavior of a sprite.
	TAG_NAMECHARACTER		= 40,	// Name a character definition, character id and a string, (used for buttons, bitmaps, sprites and sounds).
	TAG_FRAMELABEL			= 43,	// A string label for the current frame.
	TAG_SOUNDSTREAMHEAD2	= 45,	// For lossless streaming sound, should not have needed this...
	TAG_DEFINEMORPHSHAPE	= 46,	// A morph shape definition
	TAG_DEFINEFONT2 		= 48,	// 
};

// PlaceObject2 Flags
enum PlaceObject2E {
	PLACE2_MOVE				= 0x01, // this place moves an exisiting object
	PLACE2_CHARACTER		= 0x02, // there is a character tag (if no tag, must be a move)
	PLACE2_MATRIX			= 0x04, // there is a matrix (matrix)
	PLACE2_COLORTRANSFORM	= 0x08, // there is a color transform (cxform with alpha)
	PLACE2_RATIO			= 0x10, // there is a blend ratio (word)
	PLACE2_NAME				= 0x20, // there is an object name (string)
	PLACE2_DEFINECLIP		= 0x40  // this shape should open or close a clipping bracket (character != 0 to open, character == 0 to close)
};


// An input script object.  This object represents a script created from 
// an external file that is meant to be inserted into an output script.
class FlashScriptC
{
public:
	// Constructor/destructor.
	FlashScriptC();
	virtual ~FlashScriptC();

	bool						parse_file( PajaTypes::uint8* pInput, PajaTypes::uint32 ui32InputSize );

	PajaTypes::int32			get_width();
	PajaTypes::int32			get_height();
	PajaTypes::int32			get_frame_rate();
	PajaTypes::int32			get_frame_count();
	const PajaTypes::ColorC&	get_bg_color();

	PajaTypes::uint32			get_dict_size();
	SWFCharC*					get_dict_char( PajaTypes::uint32 ui32Idx );
	SWFCharC*					get_dict_char_by_id( PajaTypes::uint32 ui32Id );
	SWFDictionaryC*				get_dictionary();

	SWFDisplayListC*			get_frame( PajaTypes::uint32 ui32Frame );

	void						prepare();
	void						unprepare();
	bool						get_prepared() const;

private:

	// Tag scanning methods.
	PajaTypes::uint16	get_tag();
	void				skip_bytes( PajaTypes::int32 n );
	PajaTypes::uint8	get_byte();
	PajaTypes::uint16	get_word();
	PajaTypes::uint32	get_dword();
	PajaTypes::BBox2C	get_rect();
	PajaTypes::Matrix2C	get_matrix();
	SWFCXFormC			get_cxform( bool hasAlpha );
	char*				get_string();
	PajaTypes::ColorC	get_color( bool fWithAlpha = false );

	// Routines for reading arbitrary sized bit fields from the stream.
	// Always call start bits before gettings bits and do not intermix 
	// these calls with GetByte, etc... 
	void				init_bits();
	PajaTypes::int32	get_sbits( PajaTypes::int32 n );
	PajaTypes::uint32	get_bits( PajaTypes::int32 n );
	void				where();

	// Tag subcomponent parsing methods
	// For shapes
	void parse_shape_style( char *str, SWFShapeRecordC* pShape, bool fWithAlpha = false );
	bool parse_shape_record( char *str, SWFShapeRecordC* pShape, PajaTypes::int32& xLast, PajaTypes::int32& yLast, bool fWithAlpha = false );
	bool parse_text_record( char* str, SWFTextRecordC* pText, int nGlyphBits, int nAdvanceBits );

	// Parsing methods.
	void parse_end( char *str );									//  00: End
	void parse_show_frame( char *str, PajaTypes::uint32 frame, PajaTypes::uint32 offset );	// 01: ShowFrame
	void parse_define_shape( char *str, bool fWithAlpha = false );	//  02: DefineShape
	void parse_free_character( char *str );							//  03: FreeCharacter
	void parse_place_object( char *str );							//  04: PlaceObject
	void parse_remove_object(char *str);							//  05: RemoveObject
	void parse_set_background_color( char *str );					//  09: SetBackgroundColor
	void parse_define_font( char *str );							//x 10: DefineFont
	void parse_define_text( char *str );							//x 11: DefineText
	void parse_do_action( char *str, bool fPrintTag = true );		//  12: DoAction    
	void parse_define_font_info( char *str );						//x 13: DefineFontInfo
	void parse_define_shape2( char *str );							//x 22: DefineShape2
	void parse_place_object2( char *str );							//  26: PlaceObject2
	void parse_remove_object2( char *str );							//  28: RemoveObject2
	void parse_define_shape3( char *str );							//x 32: DefineShape3
	void parse_define_text2( char *str );							//x 33: DefineText2
	void parse_define_sprite(char *str );							//x 39: DefineSprite
	void parse_name_character( char *str );							//  40: NameCharacter
	void parse_frame_label( char *str );							//  43: FrameLabel
	void parse_define_font2( char *str );							//x 48: DefineFont2
	void parse_define_bits();										//  06: DefineBits
	void parse_define_bits_jpeg2();									//  21: DefineBitsJPEG2
	void parse_define_bits_jpeg3();									//  35: DefineBitsJPEG3
	void parse_define_bits_lossless( bool bWithAlpha = false );		//  20: DefineBitsLossless
	void parse_define_bits_lossless2();								//  36: DefineBitsLossless2
	void parse_jpeg_tables();										//  08: JPEGTables
	void parse_unknown( char *str, PajaTypes::uint16 code );
	void parse_tags( bool sprite, PajaTypes::uint32 tabs );


	PajaTypes::int32	m_i32Width;
	PajaTypes::int32	m_i32Height;
	PajaTypes::int32	m_i32FrameRate;
	PajaTypes::int32	m_i32FrameCount;
	PajaTypes::ColorC	m_rBgColor;
	SWFDictionaryC		m_rDict;

	SWFSpriteC			m_rSprite;
	SWFDisplayListC		m_rDispList;
	SWFSpriteC*			m_pCurSprite;
	SWFDisplayListC*	m_pCurDispList;

	PajaTypes::int32	m_i32CharCount;

	//
	// Parse temp vars.
	//

	// Pointer to file contents buffer.
	PajaTypes::uint8 *m_fileBuf;

	// File state information.
	PajaTypes::uint32 m_filePos;
	PajaTypes::uint32 m_fileSize;
	PajaTypes::uint32 m_fileStart;
	PajaTypes::uint16 m_fileVersion;

	// Bit Handling
	PajaTypes::int32 m_bitPos;
	PajaTypes::uint32 m_bitBuf;

	// Tag parsing information.
	PajaTypes::uint32 m_tagStart;
	PajaTypes::uint32 m_tagZero;
	PajaTypes::uint32 m_tagEnd;
	PajaTypes::uint32 m_tagLen;

	// Parsing information.
	PajaTypes::int32 m_nFillBits;
	PajaTypes::int32 m_nLineBits;

	PajaTypes::uint16	m_ui16LineStyle;
	PajaTypes::uint16	m_ui16FillStyle0;
	PajaTypes::uint16	m_ui16FillStyle1;
	PajaTypes::int32	m_i32FillStyleBase;
	PajaTypes::int32	m_i32LineStyleBase;

	// Font glyph counts (gotta save it somewhere!)
	int m_iGlyphCounts[256];

	bool				m_bPrepared;
};


//
// Inlines to parse a Flash file.
//

inline
void
FlashScriptC::skip_bytes( PajaTypes::int32 n )
{
    m_filePos += n;
}

inline
PajaTypes::uint8
FlashScriptC::get_byte() 
{
    //printf("GetByte: filePos: %02x [%02x]\n", m_filePos, m_fileBuf[m_filePos]);
    init_bits();
    return m_fileBuf[m_filePos++];
}

inline
PajaTypes::uint16
FlashScriptC::get_word()
{
    //printf("GetWord: filePos: %02x\n", m_filePos);
    PajaTypes::uint8* s = m_fileBuf + m_filePos;
    m_filePos += 2;
    init_bits();
    return (PajaTypes::uint16) s[0] | ((PajaTypes::uint16) s[1] << 8);
}

inline
PajaTypes::uint32
FlashScriptC::get_dword()
{
    //printf("GetDWord: filePos: %02x\n", m_filePos);
    PajaTypes::uint8 * s = m_fileBuf + m_filePos;
    m_filePos += 4;
    init_bits();
    return (PajaTypes::uint32) s[0] | ((PajaTypes::uint32) s[1] << 8) | ((PajaTypes::uint32) s[2] << 16) | ((PajaTypes::uint32) s [3] << 24);
}


#endif //__FLASHSCRIPTC_H__
