/*
 * This file Copyright (C) 2009-2014 Mnemosyne LLC
 *
 * It may be used under the GNU Public License v2 or v3 licenses,
 * or any future license endorsed by Mnemosyne LLC.
 *
 * $Id: tracker-model.cc 14225 2014-01-19 01:09:44Z jordan $
 */

#include <algorithm> // std::sort()

#include <QUrl>

#include "app.h" // MyApp
#include "tracker-model.h"

int
TrackerModel :: rowCount (const QModelIndex& parent) const
{
  Q_UNUSED (parent);

  return parent.isValid() ? 0 : myRows.size();
}

QVariant
TrackerModel :: data (const QModelIndex& index, int role) const
{
  QVariant var;

  const int row = index.row ();

  if ((0<=row) && (row<myRows.size()))
    {
      const TrackerInfo& trackerInfo = myRows.at (row);

      switch (role)
        {
          case Qt::DisplayRole:
            var = QString (trackerInfo.st.announce);
            break;

          case Qt::DecorationRole:
            var = trackerInfo.st.getFavicon ();
            break;

          case TrackerRole:
            var = qVariantFromValue (trackerInfo);
            break;

          default:
            break;
        }
    }

  return var;
}

/***
****
***/

struct CompareTrackers
{
  bool operator() (const TrackerInfo& a, const TrackerInfo& b) const
  {
    if (a.torrentId != b.torrentId )
      return a.torrentId < b.torrentId;

    if (a.st.tier != b.st.tier)
      return a.st.tier < b.st.tier;

    if (a.st.isBackup != b.st.isBackup)
      return !a.st.isBackup;

    return a.st.announce < b.st.announce;
  }
};

void
TrackerModel :: refresh (const TorrentModel& torrentModel, const QSet<int>& ids)
{
  // build a list of the TrackerInfos
  QVector<TrackerInfo> trackers;
  foreach (int id, ids)
    {
      const Torrent * tor = torrentModel.getTorrentFromId (id);
      if (tor != 0)
        {
          const TrackerStatsList trackerList = tor->trackerStats ();
          foreach (const TrackerStat& st, trackerList)
            {
              TrackerInfo trackerInfo;
              trackerInfo.st = st;
              trackerInfo.torrentId = id;
              trackers.append (trackerInfo);
            }
        }
    }

  // sort 'em
  CompareTrackers comp;
  std::sort (trackers.begin(), trackers.end(), comp);

  // merge 'em with the existing list
  int old_index = 0;
  int new_index = 0;

  while  ((old_index < myRows.size()) ||  (new_index < trackers.size()))
    {
      if (old_index == myRows.size())
        {
          // add this new row
          beginInsertRows (QModelIndex (), old_index, old_index);
          myRows.insert (old_index, trackers.at (new_index));
          endInsertRows ();
          ++old_index;
          ++new_index;
        }
      else if (new_index == trackers.size())
        {
          // remove this old row
          beginRemoveRows (QModelIndex (), old_index, old_index);
          myRows.remove (old_index);
          endRemoveRows ();
        }
      else if (comp (myRows.at(old_index), trackers.at(new_index)))
        {
          // remove this old row
          beginRemoveRows (QModelIndex (), old_index, old_index);
          myRows.remove (old_index);
          endRemoveRows ();
        }
      else if (comp (trackers.at(new_index), myRows.at(old_index)))
        {
          // add this new row
          beginInsertRows (QModelIndex (), old_index, old_index);
          myRows.insert (old_index, trackers.at (new_index));
          endInsertRows ();
          ++old_index;
          ++new_index;
        }
      else // update existing row
        {
          myRows[old_index].st = trackers.at(new_index).st;
          QModelIndex topLeft;
          QModelIndex bottomRight;
          dataChanged (index(old_index,0), index(old_index,0));
          ++old_index;
          ++new_index;
        }
    }
}

int
TrackerModel :: find (int torrentId, const QString& url) const
{
  for (int i=0, n=myRows.size(); i<n; ++i)
    {
      const TrackerInfo& inf = myRows.at(i);

      if ((inf.torrentId == torrentId) &&  (url == inf.st.announce))
        return i;
    }

  return -1;
}
