/***************************************************************************
 *   Copyright (C) 2008 by Joris Guisson and Ivan Vasic                    *
 *   joris.guisson@gmail.com                                               *
 *   ivasic@gmail.com                                                      *
 *                                                                         *
 *   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.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
 ***************************************************************************/
#include "trackermodel.h"
#include <QList>
#include <klocale.h>
#include <interfaces/torrentinterface.h>
#include <interfaces/trackerinterface.h>

namespace kt
{

	TrackerModel::TrackerModel(QObject* parent)
			: QAbstractTableModel(parent),tc(0)
	{
		running = false;
	}


	TrackerModel::~TrackerModel()
	{
		qDeleteAll(trackers);
	}

	void TrackerModel::changeTC(bt::TorrentInterface* tc)
	{
		qDeleteAll(trackers);
		trackers.clear();
		this->tc = tc;
		if (tc)
		{
			QList<bt::TrackerInterface*> tracker_list = tc->getTrackersList()->getTrackers();
			foreach (bt::TrackerInterface* trk,tracker_list)
			{
				trackers.append(new Item(trk));
			}
		}
		
		reset();
	}
	
	void TrackerModel::update() 
	{
		if (!tc)
			return;
		
		int idx = 0;
		foreach (Item* t,trackers)
		{
			if (t->update())
				emit dataChanged(index(idx,1),index(idx,5));
			idx++;
		}
		
		running = tc->getStats().running;
	}


	int TrackerModel::rowCount(const QModelIndex &parent) const
	{
		if (parent.isValid() || !tc)
			return 0;
		else
			return trackers.count();
	}
	
	int TrackerModel::columnCount(const QModelIndex& parent) const 
	{
		if (parent.isValid())
			return 0;
		else
			return 6;
	}

	
	QVariant TrackerModel::data(const QModelIndex &index, int role) const
	{
		if (!tc || !index.isValid() ||  index.row() < 0 || index.row() >= trackers.count())
			return QVariant();
		
		Item* item = (Item*)index.internalPointer();
		if (!item)
			return QVariant();
		
		bt::TrackerInterface* trk = item->trk;
		
		if (role == Qt::CheckStateRole && index.column() == 0)
		{
			return trk->isEnabled() ? Qt::Checked : Qt::Unchecked;
		}
		else if (role == Qt::DisplayRole)
		{
			return item->displayData(index.column());
		}
		else if (role == Qt::UserRole)
		{
			return item->sortData(index.column());
		}
		else if (role == Qt::ForegroundRole && index.column() == 1 && trk->trackerStatus() == bt::TRACKER_ERROR)
		{
			return Qt::red;
		}
		
		return QVariant();
	}
	
	bool TrackerModel::setData(const QModelIndex & index,const QVariant & value,int role)
	{
		if (!tc || !index.isValid() || index.row() < 0 || index.row() >= trackers.count())
			return false;
		
		if (role == Qt::CheckStateRole)
		{
			KUrl url = trackers.at(index.row())->trk->trackerURL();
			tc->getTrackersList()->setTrackerEnabled(url,(Qt::CheckState)value.toUInt() == Qt::Checked);
			return true;
		}
		return false;
	}
	
	QVariant TrackerModel::headerData(int section, Qt::Orientation orientation,int role) const
	{
		if (orientation != Qt::Horizontal)
			return QVariant();
		
		if (role == Qt::DisplayRole)
		{
			switch (section)
			{
				case 0: return i18n("Url");
				case 1: return i18n("Status");
				case 2: return i18n("Seeders");
				case 3: return i18n("Leechers");
				case 4: return i18n("Times Downloaded");
				case 5: return i18n("Next Update");
			}
		}
		return QVariant();
	}
	
	bool TrackerModel::insertRows(int row,int count,const QModelIndex & parent)
	{
        Q_UNUSED(parent)
		beginInsertRows(QModelIndex(),row,row + count - 1);
		if (tc)
		{
			QList<bt::TrackerInterface*> tracker_list = tc->getTrackersList()->getTrackers();
			QList<Item*>::iterator i = trackers.begin();
			foreach (bt::TrackerInterface* trk,tracker_list)
			{
				if (i != trackers.end())
				{
					Item* item = *i;
					item->trk = trk;
				}
				else
					trackers.append(new Item(trk));
				i++;
			}
		}
		endInsertRows();
		return true;
	}
	
	bool TrackerModel::removeRows(int row,int count,const QModelIndex & parent)
	{
        Q_UNUSED(parent)
		beginRemoveRows(QModelIndex(),row,row + count - 1);
		if (tc)
		{
			for (int i = 0;i < count;i++)
			{
				Item* item = trackers.takeAt(row);
				KUrl url = item->trk->trackerURL();
				tc->getTrackersList()->removeTracker(url);
				delete item;
			}
		}
		endRemoveRows();
		return true;
	}
	
	Qt::ItemFlags TrackerModel::flags(const QModelIndex & index) const
	{
		if (!tc || !index.isValid() || index.row() >= trackers.count() || index.row() < 0 || index.column() != 0)
			return QAbstractItemModel::flags(index);
		else
			return QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable;
	}
	
	QModelIndex TrackerModel::index(int row, int column, const QModelIndex& parent) const 
	{
		if (parent.isValid() || row < 0 || row >= trackers.count() || column < 0 || column >= 6)
			return QModelIndex();
		else
			return createIndex(row,column,trackers.at(row));
	}

	
	KUrl TrackerModel::trackerUrl(const QModelIndex & index)
	{
		if (!tc || !index.isValid() ||  index.row() < 0 || index.row() >= trackers.count())
			return KUrl();
		
		return ((Item*)index.internalPointer())->trk->trackerURL();
	}
	
	bt::TrackerInterface* TrackerModel::tracker(const QModelIndex & index) 
	{
		if (!tc || !index.isValid() ||  index.row() < 0 || index.row() >= trackers.count())
			return 0;
		
		return ((Item*)index.internalPointer())->trk;
	}
	
	//////////////////////////////////////////
	
	TrackerModel::Item::Item(bt::TrackerInterface* tracker) : trk(tracker)
	{
		seeders = leechers = -1;
		times_downloaded = -1;
		time_to_next_update = 0;
		status = tracker->trackerStatus();
	}
	
	bool TrackerModel::Item::update()
	{
		bool ret = false;
		if (status != trk->trackerStatus())
		{
			status = trk->trackerStatus();
			ret = true;
		}
		
		if (seeders != trk->getNumSeeders())
		{
			seeders = trk->getNumSeeders();
			ret = true;
		}
		
		if (leechers != trk->getNumLeechers())
		{
			leechers = trk->getNumLeechers();
			ret = true;
		}
		
		if (times_downloaded != trk->getTotalTimesDownloaded())
		{
			times_downloaded = trk->getTotalTimesDownloaded();
			ret = true;
		}
		
		if (static_cast<bt::Uint32>(time_to_next_update) != trk->timeToNextUpdate())
		{
			time_to_next_update = trk->timeToNextUpdate();
			ret = true;
		}
		
		return ret;
	}
	
	QVariant TrackerModel::Item::displayData(int column) const
	{
		switch (column)
		{
			case 0: return trk->trackerURL().prettyUrl();
			case 1: return trk->trackerStatusString();
			case 2: return seeders >= 0 ? seeders : QVariant();
			case 3: return leechers >= 0 ? leechers : QVariant();
			case 4: return times_downloaded >= 0 ? times_downloaded : QVariant();
			case 5: 
			{
				int secs = time_to_next_update;
				if (secs)
					return QTime().addSecs(secs).toString("mm:ss");
				else
					return QVariant();
			}
			default: return QVariant();
		}
	}
	
	QVariant TrackerModel::Item::sortData(int column) const
	{
		switch (column)
		{
			case 0: return trk->trackerURL().prettyUrl();
			case 1: return status;
			case 2: return seeders;
			case 3: return leechers;
			case 4: return times_downloaded;
			case 5: return time_to_next_update;
			default: return QVariant();
		}
	}

}
