//-----------------------------------------------------------------------------
// Purpose: 
// Input  : pszFilename - 
//			bIndexOnly - 
// Output : int
//-----------------------------------------------------------------------------
int CPrefabLibraryRMF::Save(LPCTSTR pszFilename, BOOL bIndexOnly)
{
	// temp storage
	static char szFile[MAX_PATH];

	// if only saving index, special code -
	if(bIndexOnly && m_file.is_open())
	{
		// close file, reopen in binary write
		m_file.close();
		if(Prefabs.GetCount())
		{
			// change size of file first
			int iHandle = _open(m_strOpenFileName, _O_BINARY | _O_WRONLY);
			_chsize(iHandle, m_dwDirOffset);
			_close(iHandle);
		}

		fstream file(m_strOpenFileName, ios::binary | ios::out);

		// write string header
		file << pLibHeader;
		// write binary header (in case notes have changed)
		PrefabLibraryHeader plh;
		plh.dwNumEntries = Prefabs.GetCount();
		plh.fVersion = fLibVersion;
		plh.dwDirOffset = m_dwDirOffset;
		strcpy(plh.szNotes, szNotes);
		file.write((char*)&plh, sizeof plh);

		// recreate a directory and write it
		PrefabHeader *ph = new PrefabHeader[Prefabs.GetCount()];
		int iCur = 0;

		POSITION p = Prefabs.GetHeadPosition();
		while(p)
		{
			CPrefab *pPrefab = Prefabs.GetNext(p);

			// setup this dir entry
			ph[iCur].dwOffset = pPrefab->dwFileOffset;
			ph[iCur].dwSize = pPrefab->dwFileSize;
			strcpy(ph[iCur].szName, pPrefab->GetName());
			strcpy(ph[iCur].szNotes, pPrefab->GetNotes());
			ph[iCur].iType = pPrefab->GetType();

			++iCur;	// increase current directory entry
		}

		// write directory
		file.seekp(m_dwDirOffset);
		file.write((char*)ph, sizeof(*ph) * Prefabs.GetCount());
		file.close();

		// re-open
		m_file.open(m_strOpenFileName, ios::in | ios::binary | ios::nocreate);
		return 1;
	}

	if(pszFilename == NULL)
	{
		pszFilename = szFile;

		if(m_strOpenFileName.IsEmpty())
		{
			char szNewFilename[MAX_PATH];
			CWorldcraft *pApp = (CWorldcraft*) AfxGetApp();
			pApp->GetDirectory(DIR_PREFABS, szNewFilename);

			sprintf(szNewFilename + strlen(szNewFilename), "\\%s.ol", m_szName);

			// make a name
			m_strOpenFileName = szNewFilename;
		}

		strcpy(szFile, m_strOpenFileName);
	}
	else
	{
		strcpy(szFile, pszFilename);
		SetNameFromFilename(pszFilename);
	}

	// open temp file to save to.. then delete & rename old one.
	CString strTempFileName = "Temporary Prefab Library.$$$";
	fstream file;
	file.open(strTempFileName, ios::binary | ios::out);

	// write string header
	file << pLibHeader;

	// write binary header
	// save current position so we can seek back and rewrite it
	DWORD dwBinaryHeaderOffset = file.tellp();
	PrefabLibraryHeader plh;
	plh.dwNumEntries = Prefabs.GetCount();
	plh.fVersion = fLibVersion;
	strcpy(plh.szNotes, szNotes);
	file.write((char*)&plh, sizeof plh);

	// allocate memory for directory
	PrefabHeader *ph = new PrefabHeader[plh.dwNumEntries];
	int iCur = 0;

	char *pCopyBuf = new char[64000];

	// write each prefab
	POSITION p = Prefabs.GetHeadPosition();
	while (p)
	{
		CPrefabRMF *pPrefab = (CPrefabRMF *)Prefabs.GetNext(p);

		// setup this dir entry
		ph[iCur].dwOffset = file.tellp();
		strcpy(ph[iCur].szName, pPrefab->GetName());
		strcpy(ph[iCur].szNotes, pPrefab->GetNotes());
		ph[iCur].iType = pPrefab->GetType();

		if(pPrefab->IsLoaded())
		{
			// it's loaded - save in native method
			pPrefab->Save(file, CPrefab::lsUpdateFilePos);
		}
		else
		{
			// it's not loaded - save with quick method by copying
			// bytes directly from the existing file
			ASSERT(m_file.is_open());
			m_file.seekg(pPrefab->dwFileOffset);
			DWORD dwToRead = 64000, dwCopied = 0;
			while(dwToRead == 64000)
			{
				if(dwCopied + dwToRead > pPrefab->dwFileSize)
					dwToRead = pPrefab->dwFileSize - dwCopied;
				m_file.read(pCopyBuf, dwToRead);
				file.write(pCopyBuf, dwToRead);
				dwCopied += dwToRead;
			}
		}

		// set offset info HERE because we might use it above
		pPrefab->dwFileOffset = ph[iCur].dwOffset;

		// set size info
		ph[iCur].dwSize = pPrefab->dwFileSize = 
			file.tellp() - ph[iCur].dwOffset;

		++iCur;	// increase current directory entry
	}

	// delete copy buf
	delete[] pCopyBuf;

	// rewrite binary header
	plh.dwDirOffset = m_dwDirOffset = file.tellp();
	file.seekp(dwBinaryHeaderOffset);
	file.write((char*)&plh, sizeof(plh));
	file.seekp(0, ios::end);

	// write directory
	file.write((char*)ph, sizeof(*ph) * plh.dwNumEntries);
	file.close();	// close temp file
	
	// delete original and rename
	m_file.close();	// might already be open.. might not.
	remove(m_strOpenFileName);

	m_strOpenFileName = szFile;
	int iRvl = rename(strTempFileName, m_strOpenFileName);
	
	// reopen original
	m_file.open(m_strOpenFileName, ios::in | ios::binary | ios::nocreate);

	return 1;
}
void CPrefabsDlg::OnAddobject() 
{
	CPrefabLibrary *pLibrary = GetCurrentLibrary();
	if(!pLibrary)
		return;	// no lib, no add

	CFileDialog dlg(TRUE, NULL, NULL, OFN_ALLOWMULTISELECT | OFN_FILEMUSTEXIST |
		OFN_HIDEREADONLY | OFN_LONGNAMES | OFN_NOCHANGEDIR, 
		"Prefab files (*.map;*.rmf;*.os)|*.map; *.rmf; *.os|"
		"Game MAP files (*.map)|*.map|"
		"Worldcraft RMF files (*.rmf)|*.rmf||", this);

	if(dlg.DoModal() == IDCANCEL)
		return;	// aborted

	// add all these files .. 
	char szDir[MAX_PATH], szFiles[2048];
	memcpy(szFiles, dlg.m_ofn.lpstrFile, dlg.m_ofn.nMaxFile);
	strcpy(szDir, dlg.m_ofn.lpstrFile);

	BOOL bOneFile = FALSE;
	char *p = szFiles + strlen(szDir) + 1;
	if(!p[0])
	{
		bOneFile = TRUE;
		p = szDir;	// just one file
	}

	// disable caching of prefabs
	CPrefab::EnableCaching(FALSE);

	// get files
	char szFile[MAX_PATH];
	CString strFullPath;
	int iItem = m_Objects.GetItemCount();
	while(1)
	{
		strcpy(szFile, p);
		if(!szFile[0])
			break;
		p += strlen(szFile) + 1;

		if(!bOneFile)
			strFullPath.Format("%s\\%s", szDir, szFile);
		else
			strFullPath = szFile;

		// check file type
		CPrefab *pPrefab = NULL;

		switch(CPrefab::CheckFileType(strFullPath))
		{
			case CPrefab::pftUnknown:
			{
				continue;	// no.
			}

			case CPrefab::pftRMF:
			{
				CPrefabRMF *pNew = new CPrefabRMF;
				pNew->Init(strFullPath, TRUE, CPrefab::lsRMF);
				pPrefab = (CPrefab *)pNew;
				break;
			}

			case CPrefab::pftMAP:
			{
				CPrefabRMF *pNew = new CPrefabRMF;
				pNew->Init(strFullPath, TRUE, CPrefab::lsMAP);
				pPrefab = (CPrefab *)pNew;
				break;
			}

			case CPrefab::pftScript:
			{
				Assert(0);	// not supported yet
				break;
			}
		}

		if (!pPrefab)
		{
			continue;
		}

		// add to current library
		pLibrary->Add(pPrefab);
		// add to objects list
		AddToObjectList(pPrefab, iItem++);

		if(bOneFile)
			break;
	}

	// now rewrite library
	pLibrary->Sort();
	pLibrary->Save();

	CPrefab::FreeAllData();	// free memory
	// re-enable prefab caching
	CPrefab::EnableCaching(TRUE);

	bCurLibraryModified = FALSE;
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : pszFilename - 
// Output : int
//-----------------------------------------------------------------------------
int CPrefabLibraryRMF::Load(LPCTSTR pszFilename)
{
	m_eType = LibType_HalfLife;

	// open file
	m_file.open(pszFilename, ios::in | ios::binary | ios::nocreate);
	m_strOpenFileName = pszFilename;
	
	if(!m_file.is_open())
		return -1;

	char szBuf[128];

	// read string header
	m_file.read(szBuf, strlen(pLibHeader));
	if(strncmp(szBuf, pLibHeader, strlen(pLibHeader)))
	{
		// return
		return -1;
	}

	// read binary header
	PrefabLibraryHeader plh;
	m_file.read((char*)&plh, sizeof(plh));
	strcpy(szNotes, plh.szNotes);

	// set name from filename
	SetNameFromFilename(pszFilename);

	// read directory
	PrefabHeader *ph = new PrefabHeader[plh.dwNumEntries];
	m_dwDirOffset = plh.dwDirOffset;
	m_file.seekg(plh.dwDirOffset);
	m_file.read((char*)ph, plh.dwNumEntries * sizeof(PrefabHeader));

	//
	// Read each prefab.
	//
	for(DWORD i = 0; i < plh.dwNumEntries; i++)
	{
		ASSERT(ph[i].iType == pt3D);
		CPrefabRMF *pPrefab = new CPrefabRMF;

		// seek to prefab
		m_file.seekg(ph[i].dwOffset);
		pPrefab->Init(m_file);

		// set its other info frm the dir entry
		pPrefab->SetName(ph[i].szName);
		pPrefab->SetNotes(ph[i].szNotes);
		pPrefab->dwFileSize = ph[i].dwSize;
		pPrefab->dwFileOffset = ph[i].dwOffset;
		
		Add(pPrefab);
	}

	// delete directory
	delete[] ph;

	return 1;
}