//Copyright 2007 Asim Siddiqui
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//
//
//
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <SRF_util.hh>
#include <SRF_Container.hh>
#include <SRF_ReadSet.hh>

#define HEADERBLOCKTYPE "SSRF"
#define CONTAINERTYPE 'Z'
#define FORMATVERSION "1.3"

SRF_Container::SRF_Container( void )
{
        formatVersion = FORMATVERSION;
        headerBlockType = HEADERBLOCKTYPE;
        containerType = CONTAINERTYPE;
        sizeContainerHeader = 0;
}

SRF_Container::~SRF_Container( void )
{
   // null
}    

bool
SRF_Container::populate( std::fstream& file )
{
    containerPositionInFile = file.tellg();

//read blockType, blockSize, version, containerType, baseCaller, baseCallerVersion
    char tmp[4];
    file.read(tmp, 4);
    headerBlockType = std::string(tmp, 4);;
    if ( headerBlockType.compare( HEADERBLOCKTYPE ) != 0 )
    {
        SRF_ReportError( "incorrect block type header" );
        return FALSE;
    }

    sizeContainerHeader = 0;
    file.read( reinterpret_cast<char *>(&sizeContainerHeader), 4 );
    sizeContainerHeader = be_int4(sizeContainerHeader);

    formatVersion = SRF_readString( file );
    if ( formatVersion.compare( FORMATVERSION ) != 0 )
    {
        SRF_ReportError( "incorrect format version" );
        return FALSE;
    }
  
    file.read ( &containerType, 1);
    if ( containerType != CONTAINERTYPE )
    {
        SRF_ReportError( "unsupported container type" );
        return FALSE;
    }
    
    baseCaller = SRF_readString( file );
    baseCallerVersion = SRF_readString( file );

    return TRUE;
}

bool
SRF_Container::setup( const std::string& baseCallerIn,
                      const std::string& baseCallerVersionIn )
{
    baseCaller = baseCallerIn;
    baseCallerVersion = baseCallerVersionIn;

    return TRUE;
}

char
SRF_Container::getContainerType( void )
{
    return containerType;
}

const std::string&
SRF_Container::getBaseCaller( void )
{
    return baseCaller;
}

const std::string&
SRF_Container::getBaseCallerVersion( void )
{
    return baseCallerVersion;
}

const std::string&
SRF_Container::getHeaderBlockType( void )
{
    return headerBlockType;
}

const std::string&
SRF_Container::getFormatVersion( void )
{
    return formatVersion;
}

bool
SRF_Container::filePtrToContainerStart( std::fstream& file )
{
    file.seekg( containerPositionInFile  );

    return TRUE;
}

bool
SRF_Container::nextReadSet( std::fstream& file )
{
    SRF_ReportError( "Not implemented" );
    return FALSE;
}

bool
SRF_Container::previousReadSet( std::fstream& file )
{
    SRF_ReportError( "Not implemented" );
    return FALSE;
}

bool
SRF_Container::write( std::fstream& file )
{
    sizeContainerHeader = 0;
//write blockType, blockSize, version, containerType, baseCaller, baseCallerVersion
    sizeContainerHeader += headerBlockType.length();
    sizeContainerHeader += 4;

    char* formatVersionStr = ADOPT SRF_cStrToPascalStr( formatVersion.c_str() );
    sizeContainerHeader += strlen( formatVersionStr );

    sizeContainerHeader += 1;

    char* baseCallerStr = ADOPT SRF_cStrToPascalStr( baseCaller.c_str() );
    sizeContainerHeader += strlen( baseCallerStr );

    char* baseCallerVersionStr = ADOPT SRF_cStrToPascalStr( baseCallerVersion.c_str() );
    sizeContainerHeader += strlen( baseCallerVersionStr );

    file << headerBlockType;
    int32_t be_sizeContainerHeader = be_int4(sizeContainerHeader);
    file.write(reinterpret_cast<const char*>(&be_sizeContainerHeader),4);
    file << formatVersionStr;
    file << containerType;
    file << baseCallerStr;
    file << baseCallerVersionStr;

    delete [] formatVersionStr;
    delete [] baseCallerStr;
    delete [] baseCallerVersionStr;

}

void
SRF_Container::dump( void )
{
    std::cout << "Container Block Type:" << headerBlockType <<std::endl;
    std::cout << "Format Version:" << formatVersion  <<std::endl;
    std::cout << "Container Type:" << containerType <<std::endl;
    std::cout << "Base Caller:" << baseCaller  <<std::endl;
    std::cout << "Base Caller Version:" << baseCallerVersion  <<std::endl;
}

bool
SRF_Container::writeReadSet( std::fstream& file,
			     const std::string& ztrHeader,
                             const std::vector<ztr_t>& ztrBlobs,
                             const std::vector<std::string>& readIds,
                             const std::string& uniqueIdPrefix )
{
    SRF_ReadSet newReadSet;
    if ( !newReadSet.setup( uniqueIdPrefix, ztrHeader ) )
    {
        SRF_ReportError( "can't initialize readSet" );
        return FALSE;
    }

    if ( !newReadSet.write( file, ztrBlobs, readIds ) )
    {
        SRF_ReportError( "can't write  readSet" );
        return FALSE;
    }

    return TRUE;
}

ADOPT SRF_ReadSet*
SRF_Container::firstReadSet( std::fstream& file )
{
    file.seekg( ((off_t) containerPositionInFile + sizeContainerHeader) ); // TO DO fix to work with XML files

    SRF_ReadSet* readSet = new SRF_ReadSet;
    if ( !readSet->populate( file ) )
    {
        SRF_ReportError( "can't populate first read set" );
        delete readSet;
        return NULL;
    }

    return readSet;
}

