/// @file RenderManager.h
#ifndef RENDERMANAGER_H
#define RENDERMANAGER_H
#include "../../object/RenderEffector.h"
#include "Actor.h"

class RenderResource {
	public:
		RenderResource(){
			pModel = NULL;
		}
		~RenderResource(){
			if(pModel != NULL){delete pModel;}
		}
		Model* pModel;

		vector<Actor *> actorPocket;
};
/**
	@brief GameCore 렌더링 프로세스 클래스

	렌더링을 효율적으로 하기위한 클래스입니다.\n
	렌더링은 각각의 RenderResource에 맞게 구분되어 렌더링 됩니다.
*/
class RenderManager {
public:
	enum { PRIMARY = 0, SECONDARY };
	TimePocket aFadeTime;

	vector<int> textureOnlyPolygonIndex;
	vector<int> spriteIndex;
	vector<int> colorOnlyPolygonIndex;
	vector<RenderResource*> *pCurrentRenderPocket;

public:
	~RenderManager(){
		setCurrentRenderPocket(RenderManager::SECONDARY);
		clearCurrentRenderPocket();
		setCurrentRenderPocket(RenderManager::PRIMARY);
		clearCurrentRenderPocket();
	}
	
	//for making Resource, pD3DDevice_ is needed
	LPDIRECT3DDEVICE9 getD3DDevice(){return pD3DDevice_;}
	void initRenderPocket(CoreGraphic* _pCoreGraphic, ControlTable* _pControlTable){
		pControlTable_ = _pControlTable;
		pCoreGraphic_ = _pCoreGraphic;
		pD3DDevice_ = _pCoreGraphic->getD3DDevice();
		pSprite_ = _pCoreGraphic->getSprite();
		/* 스프라이트가 세계공간속에서 잘 있을수 있게 Sprite렌더링에 적용해주는
		 * Identity행렬 - 모델(버텍스)와 렌더링시에 구분해준다.
		 * 스프라이트의 각각에 적용하는 행렬은 SetTransform을 이용해준다.*/
		D3DXMatrixIdentity(&matSprite_);
		aRenderEffecotr_.initRenderEffector(pD3DDevice_);
	}

	void process(){ ///< Batching rendering Process
		pD3DDevice_->SetRenderState( D3DRS_LIGHTING, false);
		pCoreGraphic_->camera(0,0,0);
		pD3DDevice_->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,0x00000000, 1.0f, 0);
		pD3DDevice_->BeginScene();
		//render textureOnlyPolygonPocket, set FVF
		pD3DDevice_->SetFVF(ModelVertex::FVF_FLAG);
		for(itrRenderPocket_  = textureOnlyPolygonPocket_.begin();
			itrRenderPocket_ != textureOnlyPolygonPocket_.end(); itrRenderPocket_++){

			pRenderResource_ = *itrRenderPocket_;
			pModel_ = pRenderResource_->pModel;
			if(pModel_->pTexture){
				pD3DDevice_->SetTexture(0,pModel_->pTexture);
			}
			//todo : need to refactoring setstreamsource
			pD3DDevice_->SetStreamSource(0, pRenderResource_->pModel->pVB,0,sizeof(ModelVertex));
			if(pModel_->pIB){
				pD3DDevice_->SetIndices(pModel_->pIB);
			}
			for(itrActor_  = pRenderResource_->actorPocket.begin();
				itrActor_ != pRenderResource_->actorPocket.end(); itrActor_++){
				pActor_ = *itrActor_;
				pActor_->draw(pModel_);
			}
		}

		//render spritePocket
		pD3DDevice_->SetTransform( D3DTS_WORLD, &matSprite_);
		pSprite_->Begin( D3DXSPRITE_ALPHABLEND | D3DXSPRITE_OBJECTSPACE );
		for(itrRenderPocket_  = spritePocket_.begin();
			itrRenderPocket_ != spritePocket_.end(); itrRenderPocket_++){

			pRenderResource_ = *itrRenderPocket_;
			pModel_ = pRenderResource_->pModel;
			for(itrActor_=pRenderResource_->actorPocket.begin();
				itrActor_ != pRenderResource_->actorPocket.end(); itrActor_++){
				pActor_ = *itrActor_;
				pActor_->draw(pModel_);
			}
		}
		pSprite_->End();

		//fade in-out effect
		if(pControlTable_->bFade){
			if(pControlTable_->fadeType == ControlTable::FADE_OUT){
				pControlTable_->aTimeController.applyElpasedTime(aFadeTime.rt);
				fMaskOpacity_ = aFadeTime.rt / aFadeTime.dt;
				if(fMaskOpacity_ > 1.0f){
					fMaskOpacity_ = 1.0f;
				}
			}else if(pControlTable_->fadeType == ControlTable::FADE_IN){
				pControlTable_->aTimeController.applyElpasedTime(aFadeTime.rt);
				fMaskOpacity_ = 1.0f - aFadeTime.rt / aFadeTime.dt;
				if(fMaskOpacity_ < 0.0f){
					fMaskOpacity_ = 0.0f;
				}
			}
			if(aFadeTime.rt > aFadeTime.dt + 0.1f){
				pControlTable_->runMode = ControlTable::SCRIPT;
				pControlTable_->bFade = false;
				aFadeTime.rt = 0.0f;
			}
			pD3DDevice_->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);
			pD3DDevice_->SetRenderState(D3DRS_ALPHABLENDENABLE,true);
			pD3DDevice_->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
			pD3DDevice_->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
			pD3DDevice_->SetTexture(0, NULL);
			//pD3DDevice_->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_DIFFUSE);
			aRenderEffecotr_.drawFadeMask(fMaskOpacity_);
		}
		pControlTable_->aTimeController.showFPS(pCoreGraphic_->getFont(1), 10, 140, 10, 50);
		pD3DDevice_->EndScene();
		pD3DDevice_->Present(NULL,NULL,NULL,NULL);
	}

	void setCurrentRenderPocket(int _type){ ///< set current RenderPocket
		if( _type == PRIMARY ){
			pCurrentRenderPocket = &prmRenderPocket_;
		}else{
			pCurrentRenderPocket = &sndRenderPocket_;
		}
	}

	void sortRenderPocket(){ ///< sort RenderPocket for Batching Rendering
		vector<int>::iterator itrInt;
		for(itrInt  = textureOnlyPolygonIndex.begin();
			itrInt != textureOnlyPolygonIndex.end(); itrInt++){
			textureOnlyPolygonPocket_.push_back( (*pCurrentRenderPocket)[*itrInt] );
		}
		for(itrInt  = spriteIndex.begin();
			itrInt != spriteIndex.end(); itrInt++){
			spritePocket_.push_back( (*pCurrentRenderPocket)[*itrInt] );
		}
		for(itrInt  = colorOnlyPolygonIndex.begin();
			itrInt != colorOnlyPolygonIndex.end(); itrInt++){
			colorOnlyPolygonPocket_.push_back( (*pCurrentRenderPocket)[*itrInt] );
		}
	}

	void clearCurrentRenderPocket(){ ///< clear Current RenderPocket
		for(itrRenderPocket_  = pCurrentRenderPocket->begin();
			itrRenderPocket_ != pCurrentRenderPocket->end(); itrRenderPocket_++){
			delete *itrRenderPocket_;
		}
		pCurrentRenderPocket->clear();
	}

	void clearSortedRenderPocket(){
		textureOnlyPolygonPocket_.clear();
		textureOnlyPolygonIndex.clear();
		spritePocket_.clear();
		spriteIndex.clear();
		colorOnlyPolygonPocket_.clear();
		colorOnlyPolygonIndex.clear();
	}

private:
	//RenderResourcePocket(=RenderPocket)
	//실제 렌더포켓
	vector<RenderResource*> prmRenderPocket_;
	vector<RenderResource*> sndRenderPocket_;
	//정렬된 렌더링 포켓 : 포인터만을 가진다.
	vector<RenderResource*> textureOnlyPolygonPocket_;
	vector<RenderResource*> spritePocket_;
	vector<RenderResource*> colorOnlyPolygonPocket_;
	//RenderPocket Iterator
	vector<RenderResource*>::iterator itrRenderPocket_;

	//RenderResource Element
	RenderResource*          pRenderResource_;
	vector<Actor*>::iterator itrActor_;
	Actor*                   pActor_;

	//for Rendering Element
	LPDIRECT3DDEVICE9 pD3DDevice_;
	//for Camera, and It is needed to Refactoring
	CoreGraphic* pCoreGraphic_;
	LPD3DXSPRITE      pSprite_;
	Model*            pModel_;
	D3DXMATRIXA16     matSprite_;

	//for Effect
	RenderEffector aRenderEffecotr_;
	ControlTable*  pControlTable_;
	float          fMaskOpacity_;
};
#endif