/***************************************************************************
    dcfilelistdecompressor.cpp  -  Valknut Filelist Processing Thread
                             -------------------
    begin                : Thu Jul 3 2008
    copyright            : (C) 2008 by Edward Sheldrake
    email                : ejs1920@yahoo.co.uk
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "dcfilelistdecompressor.h"

// dclib classes not QT classes are used to decompress the filelist...
#include <dclib/core/cbytearray.h>
#include <dclib/core/che3.h>
#include <dclib/core/cbz.h>
#include <dclib/core/ciconv.h>

// ...except processing and old valknut filelist uses QT classes
#include <QByteArray>
#include <QString>
#include <QFile>

#include "dcconfig.h"

/** */
DCFilelistDecompressor::DCFilelistDecompressor( QObject * parent, CString file ) : QThread( parent )
{
	filename = file;
	data = 0;
	compressed = 0;
	recompressed = 0;
}

/** */
DCFilelistDecompressor::DCFilelistDecompressor( QObject * parent, CByteArray * memory ) : QThread( parent )
{
	data = 0;
	compressed = memory;
	recompressed = 0;
}

/** */
DCFilelistDecompressor::~DCFilelistDecompressor()
{
	/* It is DCFileBrowsers's responsibility to delete things */
	if ( isRunning() )
	{
		printf("~DCFilelistDecompressor: waiting for thread to finish\n");
		wait();
	}
}

/** */
CString * DCFilelistDecompressor::getData()
{
	return data;
}

/** */
void DCFilelistDecompressor::run()
{
	bool ok = false;
	CByteArray out;
	
	if ( filename.NotEmpty() )
	{
		compressed = new CByteArray();
		if ( compressed->LoadFromFile(filename) == false )
		{
			delete compressed;
			compressed = 0;
			emit finished( false );
			return;
		}
		
		// enable saving of lists...
		recompressed = compressed;
	}
	
	CString test;
	
	// check for uncompressed xml
	test.Set( (const char*)compressed->Data(), 9 );
	if ( test.Find("<?xml") != -1 )
	{
		data = new CString();
		data->Set( (const char*)compressed->Data(), compressed->Size() );
		
		// create compressed data to save
		recompressed = new CByteArray();
		CBZ::Compress(compressed,recompressed);
		
		if ( filename.NotEmpty() )
		{
			delete compressed;
			compressed = 0;
		}
		
		ok = true;
		
		emit finished( ok );
		
		return;
	}
	
	test.Set( (const char*)compressed->Data(), 2 );
	if ( test == "BZ" )
	{
		if ( CBZ::Decompress( compressed, &out ) )
		{
			ok = true;
		}
	}
	else
	{
		test.Set( (const char*)compressed->Data(), 3 );
		if ( test == "HE3" )
		{
			CHE3 * he3 = new CHE3();
			
			CString * s = he3->decode_he3_data( compressed );
			
			if ( s != 0 )
			{
				out.Append( s->Data(), s->Length() );
				delete s;
				ok = true;
			}
			
			delete he3;
		}
		else
		{
			test.Set( (const char*)compressed->Data(), 18 );
			if ( test == "---HEADER START---" )
			{
				CString * s = LoadOldValknutList();
				if ( s != 0 )
				{
					out.Append( s->Data(), s->Length() );
					delete s;
					ok = true;
					
					recompressed = new CByteArray();
					
					CBZ::Compress(&out,recompressed);
				}
				delete compressed;
				compressed = 0;
			}
		}
	}
	
	if ( ok == false )
	{
		if ( (compressed != 0) && (compressed == recompressed) )
		{
			delete compressed;
			compressed = 0;
			recompressed = 0;
		}
		
		emit finished( false );
		return;
	}
	
	data = new CString();
	
	// there may be a byte order mark which is up to 4 bytes at the start of the file
	test.Set( (const char*)out.Data(), 9 );
	
	if ( test.Find("<?xml") != -1 )
	{
		data->Set( (const char*)out.Data(), out.Size() );
	}
	else
	{
		CIconv * ciconv = new CIconv( g_pConfig->GetRemoteEncoding(), g_pConfig->GetLocalEncoding() );
		
		CString rawtext;
		rawtext.Set( (const char*)out.Data(), out.Size() );
		*data = ciconv->encode( rawtext );
		
		delete ciconv;
	}
	
	emit finished( ok );
}

/** */
CString * DCFilelistDecompressor::LoadOldValknutList()
{
	CString * data = new CString();
	
	QFile file( filename.Data() );

	if ( file.open( IO_ReadOnly ) )
	{
		QString line;

		line = QString::fromUtf8(file.readLine(255));
		
		if ( line == "---HEADER START---\n" )
		{
			// read header
			while ( !(line.isEmpty()) && line!="---HEADER END---\n" )
			{
				line = QString::fromUtf8(file.readLine(255));

				if ( line.startsWith("TYPE=") )
				{
					//m_sType = line.mid(5).simplified();
					//if ( m_sType == "XMLFILELIST" )
					//{
						//m_sType = "xml";
					//}
					//else
					//{
						//m_sType = "text";
					//}
				}
				else if ( line.startsWith("NICK=") )
				{
					//m_sNick = line.mid(5).simplified();
				}
				else if ( line.startsWith("HUBNAME=") )
				{
					//m_sHubName = line.mid(8).simplified();
				}
				else if ( line.startsWith("HUBHOST=") )
				{
					//m_sHubHost = line.mid(8).simplified();
				}
			}

			// the loop reading one byte at a time was replaced
			// with this
			QByteArray ba = file.readAll();
			
			// WARNING! ba.data() includes trailing garbage!
			// it must only be used in conjunction with ba.size()
			
			data->Set( ba.data(), ba.size() );
		}

        	file.close();
	}
	
	//printf("LoadOldValknutFilelist output length=%d\n",data->Length());
	
	return data;
}
