/***************************************************************************
 *   Copyright (C) 2004, 2005 by Johnathan Burchill                              *
 *   jkerrb@users.sourceforge.net                                          *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

#include "archiveHandle.h"

#include "kdar.h"
#include "kdarConfig.h"
#include "kdardeclarations.h"

#include <kdebug.h>
#include <kurl.h>

#include <qdatetime.h>
#include <qdir.h>
#include <qfile.h>
#include <qregexp.h>
#include <qstring.h>

#include <string>

#include <dar/libdar.hpp>

//For getting the hostname:
#include <unistd.h>

#include <netinet/in.h>

archiveHandle::archiveHandle( KURL archiveURL ) :
    m_archivePath(archiveURL.directory( true, false )),
    m_archiveFilename( archiveURL.fileName() )
{
    //Check that the archiveHandle is valid
    trimFilename();
    kdDebug() << "archiveHandle::archiveHandle(): archiveURL is " << archiveURL.path() << endl;
    kdDebug() << "archiveHandle::archiveHandle(): m_archivePath is " << m_archivePath << endl;
    kdDebug() << "archiveHandle::archiveHandle(): m_archiveFilename is " << m_archiveFilename << endl;
}

archiveHandle::~archiveHandle()
{
}

void archiveHandle::trimFilename()
{
    m_archiveBasename = m_archiveFilename;
    int pos = m_archiveFilename.find(QRegExp("\\.[1-9][0-9]*\\.dar$"));
    if (pos >= 1)
    {
        kdDebug() << "archiveHandle::checkFilename(): I think it's a .dar file!" << endl;
        m_archiveBasename.truncate(pos);
        kdDebug() << "archiveHandle::checkFilename(): the archiveBasename is " << m_archiveBasename << endl;
    }
}

QString archiveHandle::getArchivePath() const
{
    return m_archivePath;
}

QString archiveHandle::getArchiveFilename() const
{
    return m_archiveFilename;
}

QString archiveHandle::getArchiveBasename() const
{
    return m_archiveBasename;
}

libdar::path archiveHandle::getArchiveLibdarPath() const
{
    return libdar::path( kdar::toStdString( m_archivePath ) );
}

std::string archiveHandle::getArchiveBasenameString() const
{
    return kdar::toStdString( m_archiveBasename );
}

long archiveHandle::lastArchiveSliceNumber() const
{
    //This returns the largest slice number.
    long lastSliceNumber = 0;
    QString filterName( getArchiveBasename() + QString( ".*." ) + EXTENSION );
    QDir currentArchiveDirectory( getArchivePath(), filterName );
    QStringList currentArchiveFiles( currentArchiveDirectory.entryList() );
    long num = 0;
    for ( QStringList::Iterator it = currentArchiveFiles.begin(); it != currentArchiveFiles.end(); ++it )
    {
        (*it).replace( QRegExp( "^.*\\.([1-9][0-9]*)\\.dar$" ), "\\1" );
        bool ok;
        num = (*it).toLong( &ok );
        if ( ok )
        {
            if ( lastSliceNumber < num )
            {
                lastSliceNumber = num;
            }
        }
    }
    return lastSliceNumber;
}

QString archiveHandle::parseStringSubstitutions( const QString & rawString, KDarConfig * kdarconfig )
{
    QString parsedString( rawString );
    QRegExp host( "\\%hostname" );
    QRegExp date( "\\%date" );
    QRegExp time( "\\%time" );
    QRegExp year( "\\%year" );
    QRegExp month( "\\%month" );
    QRegExp day( "\\%day" );
    QRegExp hour( "\\%hour" );
    QRegExp minute( "\\%minute" );
    QRegExp second( "\\%second" );
    QRegExp full( "\\%full" );
    QRegExp diff( "\\%diff" );
    QRegExp refName( "\\%refname" );
    QDateTime dateTime = QDateTime::currentDateTime();
    char hostname[1024];
    if ( gethostname( hostname, sizeof( hostname ) ) == 0 )
    {
        QString hostName( hostname );
        parsedString.replace( host, hostName );
    }
    else
    {
        parsedString.replace( host, "localhost" );
    }
    parsedString.replace( date, dateTime.toString( "yyyyMMdd" ) );
    parsedString.replace( time, dateTime.toString( "hh:mm:ss" ) );
    parsedString.replace( year, dateTime.toString( "yyyy" ) );
    parsedString.replace( month, dateTime.toString( "MM" ) );
    parsedString.replace( day, dateTime.toString( "dd" ) );
    parsedString.replace( hour, dateTime.toString( "hh" ) );
    parsedString.replace( minute, dateTime.toString( "mm" ) );
    parsedString.replace( second, dateTime.toString( "ss" ) );
    parsedString.replace( full, "full" );
    parsedString.replace( diff, "diff" );
    QString refArchiveName( "" );
    if ( kdarconfig ) refArchiveName = kdarconfig->differentialBackupArchiveName();
    if ( !refArchiveName.isEmpty() )
    {
        //We just need the basename, not the entire path:
        archiveHandle refArchiveHandle( refArchiveName );
        parsedString.replace( refName, refArchiveHandle.getArchiveBasename() );
    }
    else
    {
        parsedString.replace( refName, "NO-REF-ARCHIVE" );
    }
    return parsedString;
}

libdar::crypto_algo archiveHandle::queryCryptoAlgorithm()
{
    //Open the file, and read the header to ascertain whether
    //the archive is encrypted:
    QFile archiveFile( getArchivePath() + "/" + getArchiveFilename() );
    libdar::crypto_algo algorithm = libdar::crypto_none;
    //If the file doesn't exist, return libdar::crypto_none and let libdar
    //deal with it:
    if ( !archiveFile.exists() )
    {
        return libdar::crypto_none;
    }
    //Read the header:
    //Note, this will probably only work with libdar API 3.0.0!
    if ( !archiveFile.open( IO_ReadOnly ) )
    {
        //Could not open the file! Let libdar deal with it.
        return libdar::crypto_none;
    }
    else
    {
        //From include/dar/header_version.hpp:
        libdar::U_32 tmp;
        libdar::U_32 magic;
        char label[10];
        char flag0;
        char extension;
        libdar::dar_version edition;
        char algo_zip;
        unsigned char flag;
        int numChars;
        numChars = archiveFile.readBlock( (char *) &tmp, sizeof( libdar::U_32 ) );
        magic = ntohl( tmp );
        numChars = archiveFile.readBlock( label, 10 );
        numChars = archiveFile.readBlock( &flag0, 1 );
        numChars = archiveFile.readBlock( &extension, 1);

        numChars = archiveFile.readBlock( (char *) &edition, sizeof( libdar::dar_version ) );
//        std::cout << "edition is " << edition << std::endl;
        numChars = archiveFile.readBlock( (char *) &algo_zip, sizeof( algo_zip ) );
//        std::cout << "archiveHandle::queryCryptoAlgorithm():  is " << algo_zip << std::endl;
        //From <dar/tools.cpp>:
        char a[2] = { 0, 0 };
        libdar::S_I lu;
        std::string s = "";
        do
        {
            lu = archiveFile.readBlock(a, 1);
            if(lu == 1  && a[0] != '\0')
                s += a;
        }
        while(lu == 1 && a[0] != '\0');
//        std::cout << "string cmd line is \"" << s << "\"." << std::endl;
        if ( QString( edition ) > QString( "01" ) )
        {
            numChars = (unsigned char) archiveFile.readBlock( (char *) &flag, sizeof( unsigned char ) );
  //          std::cout << "archiveHandle::queryCryptoAlgorithm(): flag is " << flag  << std::endl;
            //set crypto type to blowfish if flag is encrypted:
            if ( flag && (int) 0x20 )
            {
                algorithm = libdar::crypto_blowfish;
            }
        }
//(get_header().flag & VERSION_FLAG_SCRAMBLED)
        //If the header indicates an encrypted file, set the algo to blowfish
        //Note, this prevents users from opening "scrambled" archives.
        archiveFile.close();
    }
    kdDebug() << "archiveHandle::queryCryptoAlgorithm(): encryption algorithm is " << algorithm << endl;
    return algorithm;
}

