/***************************************************************************
*   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 qDebug
#include <cstddef>            // for NULL
#include <kio/simplejob.h>     // for file_delete
#include <klocalizedstring.h>  // for i18n
#include <qdatetime.h>         // for QDate
#include <qdebug.h>            // for QDebug
#include <qevent.h>            // for QContextMenuEvent
#include <qicon.h>             // for QIcon
#include <qmenu.h>             // for QMenu
#include <qregexp.h>           // for QRegExp
#include <qurl.h>              // for QUrl
#include <utility>             // for move

#include "common.h"            // for EtcUpdateSingleton
#include "etcupdate.h"         // for EtcUpdate
#include "mergelistview.h"

class QWidget;

/**
 * @class MergeItem
 * @short ListViewItem with merge files.
 */
MergeListView::MergeItem::MergeItem( QTreeWidget* parent, const QString& date )
    : QTreeWidgetItem( parent )
{
	setText( 0, date );
}

MergeListView::MergeItem::MergeItem( QTreeWidget* parent, QString  source, QString  destination )
    : QTreeWidgetItem( parent ), m_source(std::move( source )), m_destination(std::move( destination ))
{
	setText( 0 , m_source );
}

MergeListView::MergeItem::MergeItem( MergeItem* parent, QString  source, QString  destination )
    : QTreeWidgetItem( parent ), m_source(std::move( source )), m_destination(std::move( destination ))
{
	static const QRegularExpression eightDigitUnderscoreFourDigitSlash( QStringLiteral("\\d{8}_\\d{4}/") );
	setText( 0 , m_source.section( eightDigitUnderscoreFourDigitSlash, 1, 1 ).replace( u':' , u'/' ) );
}

auto MergeListView::MergeItem::source() -> QString
{
	return m_source;
}

auto MergeListView::MergeItem::destination() -> QString
{
	return m_destination;
}

/**
 * @class MergeListView
 * @short Specialized listview for emerge history.
 */
MergeListView::MergeListView( QWidget *parent/*, const QString& name */)
	: QTreeWidget( parent )
{
	setHeaderLabel( i18n("Configuration file") );

	setProperty( "selectionMode", QStringLiteral("Extended") );
	//setFrameShape( QFrame::NoFrame );
	setRootIsDecorated( true );
	//setFullWidth( true );

	setColumnWidth( 0, 300 );
	setColumnWidth( 1, 300 );
	//setColumnWidthMode( 0, QTreeWidget::Manual );
	//setResizeMode( QTreeWidget::LastColumn );

	//setSorting( -1 );
	connect( this, &QTreeWidget::itemDoubleClicked, this, &MergeListView::itemDoubleClicked );
}

MergeListView::~MergeListView()
= default;

struct mergeFunctor {
	explicit mergeFunctor( MergeListView::MergeItem* item ) : item( item ) {}
	void operator()() {
		EtcUpdateSingleton::Instance()->runDiff( item->source(), item->destination()/*, true */);
	}

private:
	MergeListView::MergeItem* item;
};

struct zapUpdateFunctor {
	explicit zapUpdateFunctor( MergeListView::MergeItem* item ) : item( item ) {}
	void operator()() {
		KIO::file_delete( QUrl::fromLocalFile( item->source() ) );
		item->treeWidget()->takeTopLevelItem( item->treeWidget()->indexOfTopLevelItem( item ) );
	}

private:
	MergeListView::MergeItem* item;
};

void MergeListView::contextMenuEvent( QContextMenuEvent* event )
{
	auto* item = dynamic_cast<MergeItem*>( itemAt( event->pos() ) );

	qDebug() << "MergeListView::contextMenuEvent, item is " << item;
	if (nullptr != item) {
		QMenu menu(this);
		menu.addAction( QIcon::fromTheme( QStringLiteral("merge") ), i18n("&Merge"), mergeFunctor( item ) );
		menu.addAction( QIcon::fromTheme( QStringLiteral("edit-delete") ), i18n("&Zap update"), zapUpdateFunctor( item ) );
		menu.exec( event->globalPos() );
	}
}

/**
 * Append the new unmerged configuration files.
 */
void MergeListView::loadConfFiles( const QStringList& filesList )
{
	clear();
	m_itemMap.clear();

	for ( const QString& file : filesList ) {
		const QString& source = file;
		QString destination = source;
		static const QRegularExpression dotCfgFourDigitUnderscore(QStringLiteral("\\._cfg\\d\\d\\d\\d_"));
		destination.remove( dotCfgFourDigitUnderscore );
		auto* item = new MergeItem( this, source, destination );
		addTopLevelItem( item );
	}
}

/**
 * Insert merged configurations files from backup.
 */
void MergeListView::loadBackupFiles( const QStringList& filesList )
{
	clear();
	m_itemMap.clear();

	// Find dates
	for ( const QString& file : filesList ) {
		QString date = file.section( u'/', -2, -2 ).mid(0,8);
		if ( !m_itemMap.contains( date ) )
			m_itemMap[ date ] = nullptr;
	}

	// Insert sorted dates
	for ( ItemMap::Iterator it = m_itemMap.begin(); it != m_itemMap.end(); ++it ) {
		const QString& date = it.key();
		QString localDate = QDate( date.mid(0,4).toInt(), date.mid(4,2).toInt(), date.mid(6,2).toInt() ).toString();
		
		auto *item = new MergeItem( this, localDate );
		item->setExpanded( true );
		m_itemMap[ date ] = item;
		addTopLevelItem( item );
	}

	// Insert files
	for ( const QString& source : filesList ) {
		QString date = source.section( u'/', -2, -2 ).mid(0,8);
		auto* item = new MergeItem( m_itemMap[ date ], source, source + QStringLiteral(".orig") );
		m_itemMap[ date ]->addChild( item );
	}
}

void MergeListView::itemDoubleClicked( QTreeWidgetItem* item, int column )
{
	Q_UNUSED( column )
	auto *mergeItem = dynamic_cast<MergeListView::MergeItem*>( item );
	if ( nullptr != item )
		EtcUpdateSingleton::Instance()->runDiff( mergeItem->source(), mergeItem->destination()/*, true */);
}
