/** \file
 *
 *  Contains the LzmaEncoder class implementation
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 *
 */

#include "LzmaEncoder.h"
#include "utils/Lzma.h"
#include "utils/Str.h"

#include <stdio.h>

LzmaEncoder::LzmaEncoder()
{}

LzmaEncoder::~LzmaEncoder()
{}

void* sz_alloc( void *p, size_t size )
{
    p = ( char* )p + 0;
    void* ptr = MyAlloc( size );
    if( ptr )
    {
        memset( ptr, 0, size );
    }
    return ptr;
}
void sz_free( void *p, void *address )
{
    p = ( char* )p + 0;
    MyFree( address );
}
ISzAlloc alloc_g = { sz_alloc, sz_free };

int en_code( ISeqOutStream *outStream, ISeqInStream *inStream, UInt64 fileSize )
{
    CLzmaEncHandle enc;
    int res;
    CLzmaEncProps props;

    enc = LzmaEnc_Create( &alloc_g );
    if( enc == 0 )
        return SZ_ERROR_MEM;

    LzmaEncProps_Init( &props );
    props.dictSize = 1 << 18; // Reduce memory usage from 64MB to 256KB
    res = LzmaEnc_SetProps( enc, &props );

    if( res == SZ_OK )
    {
        Byte header[LZMA_PROPS_SIZE + 8];
        size_t headerSize = LZMA_PROPS_SIZE;
        int i;

        res = LzmaEnc_WriteProperties( enc, header, &headerSize );
        for( i = 0; i < 8; i++ )
            header[headerSize++] = ( Byte )( fileSize >> ( 8 * i ) );
        if( outStream->Write( outStream, header, headerSize ) != headerSize )
            res = SZ_ERROR_WRITE;
        else
        {
            if( res == SZ_OK )
                res = LzmaEnc_Encode( enc, outStream, inStream, NULL, &alloc_g, &alloc_g );
        }
    }
    LzmaEnc_Destroy( enc, &alloc_g, &alloc_g );
    return res;
}

bool LzmaEncoder::encode( const char* inFilename, const char* outFilename, const char* renameFilename )
{
    CFileSeqInStream inStream;
    CFileOutStream outStream;
    int res;

    FileSeqInStream_CreateVTable( &inStream );
    File_Construct( &inStream.file );

    FileOutStream_CreateVTable( &outStream );
    File_Construct( &outStream.file );

    if( InFile_Open( &inStream.file, inFilename ) != 0 )
        return false;

    Str outFilenameStr( outFilename == 0 ? Str( inFilename ) + ".lzma" : outFilename );
    if( OutFile_Open( &outStream.file, outFilenameStr.cStr() ) != 0 )
        return false;

    UInt64 fileSize;
    File_GetLength( &inStream.file, &fileSize );
    res = en_code( &outStream.s, &inStream.s, fileSize );

    File_Close( &outStream.file );
    File_Close( &inStream.file );

    if( res == SZ_OK )
    {
        Str renameFilenameStr( renameFilename == 0 ? Str( inFilename ) + ".bak" : renameFilename );
        rename( inFilename, renameFilenameStr.cStr() );
    }
    else
    {
        remove( outFilenameStr.cStr() );
    }

    return res != SZ_OK;
}

