/** SGX

The   sss    gggg x   x   
     s      g      x x    Engine
      sss   g  gg   x
         s  g   g  x x          Copyright 1995-2009.
     ssss    gggg x   x         Steven Goodwin. All Rights Reserved.
    
This version has been released under the GNU Public License v2.0.

Please see the license files for details.

File: sgx/src/sgx/filesystem/file.cpp

*/

#include "sgx/core/core.hpp"
#include "sgx/filesystem/filesystem.hpp"

CSGXFile::CSGXFile(CSGXFileEntry *pFileEntry, const sgxString &access)
{
    m_pFileEntry = pFileEntry;
    m_pPlatform = CHardwarePlatform::get();
	m_bValid = false;
    m_bSwapEndian = FALSE;
	m_pDevState = NULL;

    if (access == "rw") { 
        m_bSaving = TRUE;
    } else {
        m_bSaving = FALSE;
    }

}

CSGXFile::CSGXFile(const sgxString &filename, const sgxString &access)
{
    m_pPlatform = CHardwarePlatform::get();
	m_bValid = false;
    m_bSwapEndian = FALSE;
    m_Filename = filename;
	m_pDevState = NULL;

    if (access == "rw") { 
        m_bSaving = TRUE;
    } else {
        m_bSaving = FALSE;
    }
	//
	if (!m_bSaving && sgxStrchr(filename, '/') == NULL) {
		// No path give, use the search paths
		m_pFileEntry = CSGXFileSystem::get()->getSearchPathFileEntry(filename);
	} else {
		m_pFileEntry = CSGXFileSystem::get()->getFileEntry(filename);
	}

}

CSGXFile::~CSGXFile()
{
	close();
}


tBOOL CSGXFile::create(const tBOOL bCreateDirectories)
{
	if (!m_bSaving) { 
		return FALSE;
	}

	m_pFileEntry = CSGXFileSystem::get()->createNewFile(m_Filename);

	if (bCreateDirectories && !m_pFileEntry) {
		sgxString parent;
		CSGXFileSystem::get()->getParent(parent, m_Filename);
		CSGXFileSystem::get()->createNewDirectory(parent, TRUE);
		//
		m_pFileEntry = CSGXFileSystem::get()->createNewFile(m_Filename);
	}

	if (!m_pFileEntry) {
		sgxTrace("Could not create file '%s'", m_Filename.c_str());
		return FALSE;
	}
	
	m_pDevState = m_pFileEntry->m_pFSDevice->open(m_pFileEntry->m_pBlock, "rw");

	return m_bValid = (m_pDevState ? TRUE : FALSE);
}

tBOOL CSGXFile::open()
{
	if (m_pDevState) {
		return TRUE;	// already open!
	}

	if (m_bSaving) {
		create();
	} else if (m_pFileEntry) {	// this must loading
		m_pDevState = m_pFileEntry->m_pFSDevice->open(m_pFileEntry->m_pBlock, "r");
		if (m_pDevState) {
			m_bValid = TRUE;
		}
	}

	return m_bValid;
}

tBOOL   CSGXFile::exists() {
    return m_pFileEntry ? TRUE : FALSE;
}

tBOOL   CSGXFile::isEOF() {
    return m_bValid ? m_pDevState->isEOF() : TRUE;
}

void CSGXFile::close()
{
	if (m_bValid) {
		m_pFileEntry->m_pFSDevice->close(m_pDevState);
	}
	m_bValid = false;
}

tDISC_SIZE CSGXFile::getFileSize() const
{
    return m_pFileEntry ? m_pFileEntry->getFileSize() : 0;
}

tBOOL				
CSGXFile::getFileModifiedDate(UTCDate &date) const {
    return m_pFileEntry ? m_pFileEntry->getFileModifiedDate(date) : FALSE;
}


tMEM_SIZE CSGXFile::read(tBYTE *pDest, tMEM_SIZE size)
{
    return m_bValid ? m_pDevState->read(pDest, size) : 0;
}

tBOOL CSGXFile::readLine(sgxString &str)
{
    return m_bValid ? m_pDevState->readLine(str) : TRUE;
}

tMEM_SIZE CSGXFile::write(const tBYTE *pDest, tMEM_SIZE size)
{
    return m_bValid ? m_pDevState->write(pDest, size) : 0; 
}

tBOOL CSGXFile::seek(tINT32 offset, CSGXDeviceBlockState::tSeekFrom from)
{
    return m_bValid ? m_pDevState->seek(offset, from) : false; 
}

tDISC_SIZE CSGXFile::getSeekPosition()
{
    return m_bValid ? m_pDevState->getSeekPos() : 0; 
}

void CSGXFile::writeAsciiString(const sgxString &str)
{
    sgxAssert(m_bValid); 
    sgxAssert(isSaving()); 
    write((tBYTE *)str.c_str(), str.length());
}

void CSGXFile::writeAsciiStringCR(const sgxString &str)
{
	tBYTE crlf[4];

    sgxAssert(m_bValid); 
    sgxAssert(isSaving()); 
    write((tBYTE *)str.c_str(), str.length());

	CHardwarePlatform::get()->getCRLF(crlf);
    write((tBYTE *)crlf, sgxStrlen((tCHAR *)crlf));
}

void CSGXFile::writeString(const sgxString &str)
{
    sgxAssert(m_bValid); 
    *this << str;
}

void CSGXFile::readString(sgxString &str)
{
    sgxAssert(m_bValid); 
    *this >> str;
}


tBOOL CSGXFile::slerp(sgxString &str)
{
	if (!open()) {
		return FALSE;
	}

	sgxString s;
	while(!isEOF()) {
	    *this >> s;
		str += s;
		str += "\n";
	}

	close();
	return TRUE;
}

tBOOL CSGXFile::slerp(sgxVector<sgxString> &list)
{
	if (!open()) {
		return FALSE;
	}

	sgxString s;
	while(!readLine(s)) {	    
		list.push_back(s);
	}

	close();
	return TRUE;
}



tMEM_SIZE CSGXFile::readConstant()
{
    sgxAssert(m_bValid); 
    tUINT32 val;
    *this >> val;
    return val;
}

void CSGXFile::setTargetPlatform(CHardwarePlatform *pPlatform)
{
    CHardwarePlatform *pCurrent = CHardwarePlatform::get();

    if (pCurrent->getEndian() != pPlatform->getEndian()) {
        m_bSwapEndian = TRUE;
    } else {
        m_bSwapEndian = FALSE;
    }

    m_pPlatform = pPlatform;
}

