/***************************************************************************
*   Copyright (C) 2004 by karye                                           *
*   karye@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.                                   *
*                                                                         *
*   This program is distributed in the hope that it will be useful,       *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
*   GNU General Public License for more details.                          *
*                                                                         *
*   You should have received a copy of the GNU General Public License     *
*   along with this program; if not, write to the                         *
*   Free Software Foundation, Inc.,                                       *
*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
***************************************************************************/

#include <QtCore/qglobal.h>  // for qWarning, qCritical
#include <qdebug.h>          // for QDebug
#include <qlist.h>           // for QList<>::const_iterator, QList<>::ConstI...
#include <qstring.h>         // for QString, operator+

#include <utility>

#include "common.h"          // for KurooDBSingleton, PACKAGE_UPDATES_STRING
#include "portagedb.h"       // for KurooDB, DbConnection
#include "scanupdatesjob.h"
#include "signalist.h"       // for Signalist

namespace ThreadWeaver {
class Thread;
}  // namespace ThreadWeaver

//const QRegularExpression ScanUpdatesJobImpl::m_rxNew = QRegularExpression("\\bN\\b");

/**
* @class ScanUpdatesJob
* @short Thread for loading 'emerge -uDpv World' output into db.
*/
ScanUpdatesJob::ScanUpdatesJob( const EmergePackageList &packageList )
	: ThreadWeaver::QObjectDecorator( new ScanUpdatesJobImpl( packageList ) )
{}
ScanUpdatesJobImpl::ScanUpdatesJobImpl( EmergePackageList packageList ) : 
	m_db( KurooDBSingleton::Instance()->getStaticDbConnection() ), m_packageList(std::move( packageList ))
{}

ScanUpdatesJobImpl::~ScanUpdatesJobImpl()
{
	KurooDBSingleton::Instance()->returnStaticDbConnection( m_db );

	/*if ( isAborted() )
		SignalistSingleton::Instance()->scanAborted();*/
}

/**
* Insert found updates into db.
* @return success
*/
void ScanUpdatesJobImpl::run( ThreadWeaver::JobPointer /*self*/, ThreadWeaver::Thread*  /*thread*/)
{
	if ( !m_db->isConnected() ) {
		qCritical() << "Scanning updates. Can not connect to database";
		return;
	}

	if ( m_packageList.isEmpty() )
		qWarning() << "Scanning updates. No update package found";

	/*setStatus( "ScanUpdates", i18n("Refreshing updates view...") );
	setProgressTotalSteps( m_packageList.count() );*/
//	int count(0);

	// Temporary tables to avoid locking main table
	KurooDBSingleton::Instance()->singleQuery(	QStringLiteral("CREATE TEMP TABLE package_temp ( "
												"id INTEGER PRIMARY KEY AUTOINCREMENT, "
												"idCategory INTEGER, "
												"idSubCategory INTEGER, "
												"category VARCHAR(32), "
												"name VARCHAR(32), "
												"description VARCHAR(255), "
												"path VARCHAR(64), "
												"status INTEGER, "
												"meta VARCHAR(255), "
												"updateVersion VARCHAR(32) );")
												, m_db );

	KurooDBSingleton::Instance()->insert( QStringLiteral("INSERT INTO package_temp SELECT * FROM package;"), m_db );
	KurooDBSingleton::Instance()->singleQuery( QStringLiteral("UPDATE package_temp SET updateVersion = '', status = '%1' WHERE status = '%2';")
										.arg( PACKAGE_INSTALLED_STRING, PACKAGE_UPDATES_STRING ), m_db );
	KurooDBSingleton::Instance()->singleQuery(QStringLiteral("BEGIN TRANSACTION;"), m_db);

	EmergePackageList::ConstIterator itEnd = m_packageList.constEnd();
	for ( EmergePackageList::ConstIterator it = m_packageList.constBegin(); it != itEnd; ++it ) {

		// Abort the scan
		/*if ( isAborted() ) {
			qWarning() << "Scanning updates. Scan aborted!";
			KurooDBSingleton::Instance()->singleQuery( "ROLLBACK TRANSACTION;", m_db );
			return false;
		}*/

		// count is also ordering number
		//setProgress( count++ );

		// Find id for this category in db
		QString id = KurooDBSingleton::Instance()->singleQuery( QStringLiteral(" SELECT id FROM package WHERE name = '") +
			(*it).name + QStringLiteral("' AND category = '") + (*it).category + QStringLiteral("' LIMIT 1;"), m_db );

		if ( id.isEmpty() ) {
			qWarning() << QStringLiteral("Scanning updates. Can not find id in database for package %1/%2.")
				.arg( (*it).category, (*it).name );
		}
		else {

			// Mark as update in portage, but not for new packages
			if ( !(*it).updateFlags.contains( m_rxNew ) && !id.isEmpty() ) {

				// Is the package upgrade or downgrade?
				QString updateVersion;
				if ( (*it).updateFlags.contains(u'D') )
					updateVersion = (*it).version + QStringLiteral(" (D)");
				else
					updateVersion = (*it).version + QStringLiteral(" (U)");

				KurooDBSingleton::Instance()->singleQuery( QStringLiteral( "UPDATE package_temp SET updateVersion = '%1', status = '%2' WHERE id = '%3';" )
													.arg( updateVersion, PACKAGE_UPDATES_STRING, id ), m_db );

			}
		}
	}
	KurooDBSingleton::Instance()->singleQuery(QStringLiteral("COMMIT TRANSACTION;"), m_db );

	// Move content from temporary table
	KurooDBSingleton::Instance()->singleQuery( QStringLiteral("DELETE FROM package;"), m_db );
	KurooDBSingleton::Instance()->insert( QStringLiteral("INSERT INTO package SELECT * FROM package_temp;"), m_db );
	KurooDBSingleton::Instance()->singleQuery( QStringLiteral("DROP TABLE package_temp;"), m_db );

	/*setStatus( "ScanUpdates", i18n( "Done." ) );
	setProgressTotalSteps( 0 );*/

	SignalistSingleton::Instance()->loadUpdatesComplete();
}

