/*
todo standards
*/

#include "maple.h"
#include <zlib/zlib.h>

int8_t MAPLE::cMapleModule::Status(bool bClearError)
{	
   	if (m_bInitialised == false)
   	{
       	return Uninitialised;
   	}

   	if (bClearError)
   	{        
       	m_bError = false;
   	}
   	else if (m_bError)
   	{        
        return Error;
    }
	
	if (m_bConnected && maple_dev_valid(m_pController->m_cControllerId, m_cControllerUnit))    
	{        
        m_ulDisconnectedCycles = 0;
   	    return Connected;        		
	}	
	else
   	{				    
		// Try and re-initialise ready for the next cycle.
		Init();      
        m_ulDisconnectedCycles++;
		return Disconnected;
   	}
}

/// <summary>
///	todo
/// </summary>
void MAPLE::cMapleVmu::Init()
{	
    m_bConnected = false;
    m_bHasLcd = false;
	maple_device_t* pDevice = maple_enum_dev(m_pController->m_cControllerId, m_cControllerUnit);
	if (pDevice && (pDevice->info.functions & MAPLE_FUNC_MEMCARD))
	{		
		m_pDevice = pDevice;
		m_bConnected = true;	
        m_bInitialised = true;     

        if (pDevice->info.functions & MAPLE_FUNC_LCD)
        {
            m_bHasLcd = true;
            if (m_bHasImg)
            {
                vmu_draw_lcd(m_pDevice, m_pImgBuffer);
            }            
        }
	}        
}

/// <summary>
///	todo
/// </summary>
int8_t MAPLE::cMapleVmu::GetSaveFileCount()
{
	return 0;
}

/// <summary>
///	todo
/// </summary>
int16_t MAPLE::cMapleVmu::GetFreeBlocks()
{	
	return ((m_bConnected) ? vmufs_free_blocks(m_pDevice) : 0);		
}

/// <summary>
///	todo
/// </summary>
bool MAPLE::cMapleVmu::FileExists(const char *szFileName)
{	    
    file_t f;
	int32_t total = 0;
	char szFilePath[100];
	sprintf(szFilePath, "/vmu/%c%d/%s", m_pController->Port(), m_cControllerUnit, szFileName);	
    f = fs_open(szFilePath, O_RDONLY);

    if(!f) {
        return false;
    }
    	            
	total = fs_total(f);    	
    fs_close(f);

	return ((total > 0) ? true : false);
}

/// <summary>
///	todo
/// </summary>
bool MAPLE::cMapleVmu::ReadData(const char *szFileName, uint8_t *pData, int16_t sSize)
{	        
    vmu_pkg_t package;        
    int32_t lFileSize = 0;
    uint32_t lUncompressedSize = 65536;
    uint8_t *pPackageData = NULL;
    uint8_t* pUncompressedData = NULL;    
    file_t f;
    
    char szFilePath[100];
    sprintf(szFilePath, "/vmu/%c%d/%s", m_pController->Port(), m_cControllerUnit, szFileName);	
    f = fs_open(szFilePath, O_RDONLY);
    
    if(!f) 
    {
        m_bError = true;
        return false;
    }
    
    lFileSize = fs_total(f);

    pPackageData = (uint8_t*)malloc(lFileSize);     
    if (pPackageData == NULL)
    {        
        fs_close(f);
        m_bError = true;
        return false;
    }
    
    pUncompressedData = (uint8_t*)malloc(65536);   
    if (pUncompressedData == NULL)
    {        
        fs_close(f);        
        free(pPackageData);
        m_bError = true;
        return false;
    }

    fs_read(f, pPackageData, lFileSize);
        
    if (vmu_pkg_parse(pPackageData, &package) == -1)
    {          
        fs_close(f);
        free(pPackageData);        
        free(pUncompressedData);
        m_bError = true;
        return false;
    }
     
    uncompress(pUncompressedData, &lUncompressedSize, (uint8_t *)package.data, package.data_len);
    memcpy(pData, pUncompressedData, sSize);
    free(pUncompressedData);
    free(pPackageData);
    fs_close(f);    
    
	return true;
}

/// <summary>
///	todo
/// </summary>
bool MAPLE::cMapleVmu::WriteData(const char *szFileName, uint8_t *pData, int16_t sSize)
{
	vmu_pkg_t package;    
    uint8_t *pPackageData;
    uint8_t *pCompressedData = NULL;
    int lPackageSize;    
    uint32_t lCompressedSize = sSize * 2;
    file_t f;                

    pCompressedData = (uint8_t*)malloc(lCompressedSize);

    if (pCompressedData == NULL)
    {
        m_bError = true;
        return false;
    }

	// todo: Localisation?
    
    strcpy(package.desc_short, m_pszSaveDescS);
    strcpy(package.desc_long, m_pszSaveDescL);
    strcpy(package.app_id, m_pszSaveAppName);
    compress(pCompressedData, &lCompressedSize, pData, sSize);

    if (m_pIconImgBuffer && m_pIconPalBuffer)
    {
        memcpy(&package.icon_pal[0], m_pIconPalBuffer, 32);
        package.icon_cnt = 1;
        package.icon_data = m_pIconImgBuffer;        
    }
    else
    {
        package.icon_cnt = 0;
    }
    
    package.icon_anim_speed = 0;
    package.eyecatch_type = VMUPKG_EC_NONE;
    package.data_len = lCompressedSize;
    package.data = pCompressedData;
        
    vmu_pkg_build(&package, &pPackageData, &lPackageSize);

    char szFilePath[100];
	sprintf(szFilePath, "/vmu/%c%d/%s", m_pController->Port(), m_cControllerUnit, szFileName);

    fs_unlink(szFilePath);
    f = fs_open(szFilePath, O_WRONLY);

    if(!f)
    {        
        free(pPackageData);
        free(pCompressedData);
        m_bError = true;
        return false;
    }

    fs_write(f, pPackageData, lPackageSize);
    fs_close(f);

    free(pPackageData);
    free(pCompressedData);

	return true;
}

void MAPLE::cMapleVmu::SetLCDImage(uint8_t *pImgData)
{
    m_pImgBuffer = pImgData;
    m_bHasImg = true;
    if (m_bHasLcd)
    {
        vmu_draw_lcd(m_pDevice, m_pImgBuffer);
    }
}

void MAPLE::cMapleVmu::SetSaveIcon(uint8_t* pSaveIconImgData, uint16_t* pSaveIconPalData)
{
    m_pIconImgBuffer = pSaveIconImgData;
    m_pIconPalBuffer = pSaveIconPalData;
}