/* ==========================================================================
* 작 성 자 : 이순규
* 작 성 일 : 2008.04.28
* 내    용 : 
* 주의사항 : 
*===========================================================================*/
#pragma once

/// 스트림
class cStream : public NiStream
{
public:
	cStream( const cString& pathName, NiTexturePalette* texPalette );
	const cString& GetPathName() const;
	const cString& GetPath() const;

protected:
	cString mPathName;
	cString mPath;
};

inline
cStream::cStream( const cString& pathName, NiTexturePalette* texPalette )
{
	mPathName = pathName;
	mPath = pathName;
	::GetFilePath( &mPath, pathName );

	SetTexturePalette( texPalette );
}

inline
const cString& cStream::GetPathName() const
{
	return mPathName;
}

inline
const cString& cStream::GetPath() const
{
	return mPath;
}

/// 외부 텍스처 전용 스트림
class cTextureStream : public cStream
{
public:
	cTextureStream( const cString& pathName )
		: cStream( pathName, 0 )
		, mPixelData( 0 )
	{
	}

protected:
	bool LoadStream()
	{
		if (!LoadHeader())
			return false;

		// Initialize m_uiLoad, m_uiLink, and m_uiPostLink so that progress of
		// background loading thread can be estimated. This has to be postponed
		// until after the header has been read because 
		// m_kObjects.GetAllocatedSize is used in progress estimation.
		m_uiLoad = m_uiLink = m_uiPostLink = 0;

		//Removing all objects can release shared resources.  We must lock this
		//with the stream cleanup critical section.
		RemoveAllObjects();

		bool bNew = (GetFileVersion() >= GetVersion(5, 0, 0, 1));
		if (bNew)
		{
			if (!LoadRTTI())
				return false;
		}

		if (GetFileVersion() >= GetVersion(20, 2, 0, 5))
		{
			if (!LoadObjectSizeTable())
				return false;
		}

		if (GetFileVersion() >= GetVersion(20, 1, 0, 1))
		{
			if (!LoadFixedStringTable())
				return false;
		}

		// read object groups
		if (GetFileVersion() >= GetVersion(5, 0, 0, 6))
		{
			LoadObjectGroups();
		}

		// read list of objects
		unsigned int uiObjects = m_kObjects.GetAllocatedSize();

		for ( ; m_uiLoad < uiObjects; m_uiLoad++)
		{
			if (m_eBackgroundLoadStatus == CANCELLING)
			{
				FreeLoadData();
				return false;
			}
			else if (m_eBackgroundLoadStatus == PAUSING)
			{
				DoThreadPause();
			}

			if (bNew)
			{
				NiObject* pkObject = m_kObjects.GetAt(m_uiLoad);
				if (pkObject)
				{
					pkObject->LoadBinary(*this);

					if( NiIsKindOf( NiPixelData, pkObject ) )
					{
						mPixelData = (NiPixelData*)pkObject;
					}
				}
				else 
				{
//					unsigned int uiCurrentPosition = m_pkIstr->GetPosition();
					assert(m_kObjectSizes.GetSize() != 0);
					unsigned int uiStreamedSizeInBytes = 
						m_kObjectSizes.GetAt(m_uiLoad);
					assert(uiStreamedSizeInBytes != 0);
					m_pkIstr->Seek(uiStreamedSizeInBytes);
//					assert(m_pkIstr->GetPosition() == uiCurrentPosition + uiStreamedSizeInBytes);
				}
			}
			else
			{
				if (!LoadObject())
				{
					FreeLoadData();
					return false;
				}
			}
		}

		LoadTopLevelObjects();

		// linking phase
		for ( ; m_uiLink < uiObjects; m_uiLink++)
		{
			if (m_eBackgroundLoadStatus == PAUSING)
			{
				DoThreadPause();
			}
			NiObject* pkObject = m_kObjects.GetAt(m_uiLink);
			if (pkObject)
				pkObject->LinkObject(*this);
		}

		// post-link phase
		for ( ; m_uiPostLink < uiObjects; m_uiPostLink++)
		{
			if (m_eBackgroundLoadStatus == PAUSING)
			{
				DoThreadPause();
			}
			NiObject* pkObject = m_kObjects.GetAt(m_uiPostLink);
			if (pkObject)
				pkObject->PostLinkObject(*this);
		}

		if (m_eBackgroundLoadStatus == CANCELLING)
		{
			FreeLoadData();
			return false;
		}
		else if (m_eBackgroundLoadStatus == PAUSING)
		{
			DoThreadPause();
		}

		// Post-processing phase.
		if (ms_pkPostProcessFunctions->GetEffectiveSize() > 0)
		{
			for (unsigned int ui = 0; ui < m_kTopObjects.GetSize(); ui++)
			{
				NiObject* pkTopObject = m_kTopObjects.GetAt(ui);
				if (pkTopObject)
				{
					for (unsigned int uj = 0;
						uj < ms_pkPostProcessFunctions->GetSize(); uj++)
					{
						PostProcessFunction pfnFunc = ms_pkPostProcessFunctions
							->GetAt(uj);
						if (pfnFunc)
						{
							pfnFunc(*this, pkTopObject);
						}
					}
				}
			}
		}

		if (m_eBackgroundLoadStatus == CANCELLING)
		{
			FreeLoadData();
			return false;
		}
		else if (m_eBackgroundLoadStatus == PAUSING)
		{
			DoThreadPause();
		}

		SetSelectiveUpdateFlagsForOldVersions();

		FreeLoadData();

		if( mPixelData == 0 )
			return false;
		else
			return true;
	}

public:
	NiPixelDataPtr mPixelData;
};
