#include "PajaTypes.h"
#include "Vector2C.h"
#include "Matrix2C.h"
#include <vector>
#include "SWFChar.h"
#include "SWFDispList.h"
#include "SWFFont.h"
#include "SWFShape.h"
#include "SWFText.h"
#include "SWFSpriteC.h"
#include "SWFDictionaryC.h"

using namespace PajaTypes;


SWFSpriteC::SWFSpriteC()
{
	// empty
}

SWFSpriteC::~SWFSpriteC()
{
	for( uint32 i = 0; i < m_rFrames.size(); i++ )
		delete m_rFrames[i];
	m_rFrames.clear();
}

uint32
SWFSpriteC::get_type() const
{
	return SWF_CHAR_SPRITE; 
}

void
SWFSpriteC::add_displaylist( SWFDisplayListC* pList )
{
	m_rFrames.push_back( pList );
}

uint32
SWFSpriteC::get_displaylist_count() const
{
	return m_rFrames.size();
}

SWFDisplayListC*
SWFSpriteC::get_displaylist( uint32 ui32Idx )
{
	if( ui32Idx < m_rFrames.size() )
		return m_rFrames[ui32Idx];
	return 0;
}

void
SWFSpriteC::update_frames()
{
	std::vector<SpriteFrameS>	rSpriteFrames;
	uint32			i, j, k;
	bool						bFound;

	for( i = 0; i < m_rFrames.size(); i++ ) {
		SWFDisplayListC*	pDisp = m_rFrames[i];

		// mark all frames as not updated
		for( k = 0; k < rSpriteFrames.size(); k++ )
			rSpriteFrames[k].m_bUpdated = false;

		for( j = 0; j < pDisp->get_object_count(); j++ ) {
			SWFObjectRefC*	pRef = pDisp->get_object( j );

			// check for new frames
			bFound = false;
			for( k = 0; k < rSpriteFrames.size(); k++ ) {
				if( rSpriteFrames[k].m_ui32Depth == pRef->get_depth() &&
					rSpriteFrames[k].m_ui32CharId == pRef->get_char_id() ) {
					// update old entry
					rSpriteFrames[k].m_ui32Frame++;
					pRef->set_frame( rSpriteFrames[k].m_ui32Frame );
					rSpriteFrames[k].m_bUpdated = true;
					bFound = true;
				}
			}

			// add new entry
			if( !bFound ) {
				SpriteFrameS	rFrame;
				rFrame.m_bUpdated = true;
				rFrame.m_ui32CharId = pRef->get_char_id();
				rFrame.m_ui32Depth = pRef->get_depth();
				rFrame.m_ui32Frame = 0;
				rSpriteFrames.push_back( rFrame );
			}

		}

		// delete unused
		for( int32 ir = (int32)rSpriteFrames.size() - 1; ir >= 0; ir-- ) {
			if( !rSpriteFrames[ir].m_bUpdated )
				rSpriteFrames.erase( rSpriteFrames.begin() + ir );
		}
	}
}

void
SWFSpriteC::update_shape_scalerange( SWFDictionaryC* pDict )
{
	uint32	i, j, k, m;

	for( i = 0; i < m_rFrames.size(); i++ ) {
		SWFDisplayListC*	pDisp = m_rFrames[i];

		for( j = 0; j < pDisp->get_object_count(); j++ ) {
			SWFObjectRefC*	pRef = pDisp->get_object( j );

			SWFCharC*	pChar = pDict->get_char_by_id( pRef->get_char_id() );

			if( pChar ) {
				if( pChar->get_type() == SWF_CHAR_SHAPE ) {

					SWFShapeC*			pShape = (SWFShapeC*)pChar;
					SWFShapeRecordC*	pRec = pShape->get_shape();

					const Matrix2C&	rTM = pRef->get_tm();
					float32	f32MinScale = __min( rTM[0].length(), rTM[1].length() );
					float32	f32MaxScale = __max( rTM[0].length(), rTM[1].length() );

					if( f32MinScale < pRec->get_min_scale() )
						pRec->set_min_scale( f32MinScale );

					if( f32MaxScale > pRec->get_max_scale() )
						pRec->set_max_scale( f32MaxScale );
				}
				else if( pChar->get_type() == SWF_CHAR_TEXT ) {

					SWFTextC*	pText = (SWFTextC*)pChar;
					SWFFontC*	pFont = 0;

					Matrix2C	rTextTM = pText->get_tm() * pRef->get_tm();
					Matrix2C	rRecTM;
					Matrix2C	rScaleTM;
					float32	f32Scale;

					for( k = 0; k < pText->get_text_count(); k++ ) {
						SWFTextRecordC*	pRec = pText->get_text( k );

						if( !pRec )
							continue;

						if( pRec->is_format() ) {
							pFont = (SWFFontC*)pDict->get_char_by_id( pRec->get_font_id() );
							f32Scale = pRec->get_font_height() / (1024.0f / 20.0f);
							rScaleTM.set_scale( Vector2C( f32Scale, f32Scale ) );
							rRecTM = rScaleTM * rTextTM;
							continue;
						}

						if( !pFont )
							continue;

						float32	f32MinScale = __min( rRecTM[0].length(), rRecTM[1].length() );
						float32	f32MaxScale = __max( rRecTM[0].length(), rRecTM[1].length() );

						SWFGlyphC*	pGlyph;

						for( m = 0; m < pRec->get_glyph_count(); m++ ) {
							pGlyph = pFont->get_glyph( pRec->get_glyph_index( m ) );
							if( pGlyph ) {
								SWFShapeRecordC*	pRec = pGlyph->get_shape();
								if( f32MinScale < pRec->get_min_scale() )
									pRec->set_min_scale( f32MinScale );
								if( f32MaxScale > pRec->get_max_scale() )
									pRec->set_max_scale( f32MaxScale );
							}
						}
					}
				}
			}
		}
	}
}
