/***************************************************************************
 *   Copyright (C) 2007 by Anistratov Oleg                                 *
 *   ower86@gmail.com                                                      *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License version 2        *
 *   as published by the Free Software Foundation;                         *
 *                                                                         *
 *   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.                          *
 *                                                                         *
 ***************************************************************************/
#include "usersstatisticsmodel.h"
#include "globals.h"

#include "userslist.h"
#include "userwgt.h"
#include "userinfo.h"
#include "userstatistics.h"
#include "qchaticon.h"

#include <assert.h>

UsersStatisticsModel::UsersStatisticsModel(QObject* parent) :
  QAbstractTableModel(parent),
  m_users(NULL),
  m_sortingColumn(0),
  m_sortOrder(Qt::AscendingOrder),
  m_usersOrder(NULL),
  m_usersOrderSize(0),
  m_usersOrderMaxSize(1024)
{
  m_usersOrder = (UserWgt**)malloc(m_usersOrderMaxSize * sizeof(UserWgt*));

  m_columns.append(NickName);
  m_columns.append(Gender);
  m_columns.append(RealName);
  m_columns.append(Status);
  m_columns.append(StatusDescription);
  m_columns.append(IP);
  m_columns.append(CompName);
  m_columns.append(OS);
  m_columns.append(Uptime);
  m_columns.append(ChatTime);
}

UsersStatisticsModel::~UsersStatisticsModel()
{
}

int UsersStatisticsModel::rowCount(const QModelIndex &) const
{
  if(!m_users)
    return 0;

  return m_users->num();
}

QVariant UsersStatisticsModel::data(const QModelIndex & index, int role) const
{
  UserInfo* info;
  UserWgt*  user;

  if(!index.isValid() || !m_users)
    return QVariant();

  if(index.row() > (int)m_users->num() || index.column() >= m_columns.size())
    return QVariant();

  if(m_usersOrderSize && (index.row() < m_usersOrderSize))
    user = m_usersOrder[index.row()];
  else
    user = m_users->user(index.row());

  info = user->info();
  switch(m_columns[index.column()])
  {
    case NickName :
      if(role == Qt::DecorationRole)
        return user->icon();
      else if(role == Qt::DisplayRole || role == Qt::ToolTipRole)
        return info->nickname();
      else
        return QVariant();

    case Gender :
      if(role == Qt::DisplayRole || role == Qt::ToolTipRole)
        switch(info->gender())
        {
          case 'm' : return QString(tr("Male"));
          case 'f' : return tr("Female");
          default  : return tr("Not Shure");
        }
      else if(role == Qt::DecorationRole)
        switch(info->gender())
        {
          case 'm' : return QIcon(QChatIcon::pixmap("user-male"  , 24, 24));
          case 'f' : return QIcon(QChatIcon::pixmap("user-female", 24, 24));
          default  : return QIcon(QChatIcon::pixmap("unknown"    , 24, 24));
        }
      else
        return QVariant();

    case RealName :
      if(role == Qt::DisplayRole || role == Qt::ToolTipRole) return info->firstName();
      break;

    case Status :
      if(role == Qt::DisplayRole || role == Qt::ToolTipRole) return Globals::StatusStr[info->status()];
      else if(role == Qt::DecorationRole)
      {
        QString icon_name = "unknown";

        switch(info->status())
        {
          case Globals::READY4CHAT : icon_name = "status/user-ready-for-chat"; break;
          case Globals::FREE       : icon_name = "status/user-online";         break;
          case Globals::BUSY       : icon_name = "status/user-busy";           break;
          case Globals::DND        : icon_name = "status/user-dnd";            break;
          case Globals::INACTIVE   : icon_name = "status/user-away";           break;
          case Globals::AWAY       : icon_name = "status/user-away-extended";  break;
        }

        return QIcon(QChatIcon::pixmap(icon_name, 24, 24));
      }
      break;

    case StatusDescription :
      if(role == Qt::DisplayRole || role == Qt::ToolTipRole) return info->statusDescription();
      break;

    case IP :
      if(role == Qt::DisplayRole || role == Qt::ToolTipRole) return QHostAddress(info->ip()).toString();
      break;

    case CompName :
      if(role == Qt::DisplayRole || role == Qt::ToolTipRole) return info->compName();
      break;

    case OS :
      if(role == Qt::DisplayRole || role == Qt::ToolTipRole)
        return user->stats()->os();
      break;

    case Uptime :
      if(role == Qt::DisplayRole || role == Qt::ToolTipRole)
        if(user->stats()->uptime() > 0)
          return user->stats()->uptimeString();
        else
          return tr("Unknown");
      break;

    case ChatTime :
      if(role == Qt::DisplayRole || role == Qt::ToolTipRole)
        return user->stats()->chatTimeString();
      break;

    default : return QVariant();
  }

  return QVariant();
}

QVariant UsersStatisticsModel::headerData(int section, Qt::Orientation orientation, int role) const
{
  if(role != Qt::DisplayRole || section >= m_columns.size())
    return QVariant();

  if(orientation == Qt::Horizontal)
  {
    switch(m_columns[section])
    {
      case NickName          : return tr("Nickname");
      case Gender            : return tr("Gender");
      case RealName          : return tr("Real Name");
      case Status            : return tr("Status");
      case StatusDescription : return tr("Status Description");
      case IP                : return tr("IP");
      case CompName          : return tr("Comp Name");
      case OS                : return tr("OS");
      case Uptime            : return tr("Uptime");
      case ChatTime          : return tr("Time in Chat");
      default                : return QVariant();
    }
  }
  else
    return QString("%1").arg(section + 1);
}

void UsersStatisticsModel::sort(int column, Qt::SortOrder order) const
{
  UserWgt* tmp;

  for(uint i = 0; i < m_users->num(); i++)
    m_usersOrder[i] = m_users->user(i);

  if(column != 0)
    sort(0, order);

  m_usersOrderSize = m_users->num();
  if(m_usersOrderSize > m_usersOrderMaxSize)
  {
    m_usersOrderMaxSize = m_usersOrderSize;
    m_usersOrder = (UserWgt**)realloc(m_usersOrder, m_usersOrderMaxSize * sizeof(UserWgt*));
    assert(NULL != m_usersOrder);
  }

  uint num = m_usersOrderSize;
  for(uint i = 0; i < num; i++)
    for(uint j = i + 1; j < num; j++)
    {
      if(cmp(m_usersOrder[i], m_usersOrder[j], column, order) > 0)
      {
        tmp = m_usersOrder[i];
        m_usersOrder[i] = m_usersOrder[j];
        m_usersOrder[j] = tmp;
      }
    }

  m_sortingColumn = column;
  m_sortOrder     = order;
}

int UsersStatisticsModel::cmp(UserWgt* u1, UserWgt* u2, int column, Qt::SortOrder order) const
{
  Q_ASSERT(column >= 0 && column < m_columns.size());

  switch(m_columns[column])
  {
    case NickName :
      if(order) return u1->info()->nickname().compare(u2->info()->nickname());
      else      return u2->info()->nickname().compare(u1->info()->nickname());

    case Gender :
      if(order)
        return (u1->info()->gender() > u2->info()->gender() ? 1 :
              -(u1->info()->gender() < u2->info()->gender()));
      else
        return (u2->info()->gender() > u1->info()->gender() ? 1 :
              -(u2->info()->gender() < u1->info()->gender()));

    case RealName :
      if(order) return u1->info()->firstName().compare(u2->info()->firstName());
      else      return u2->info()->firstName().compare(u1->info()->firstName());

    case Status :
      if(order)
        return Globals::StatusStr[u1->info()->status()].compare(Globals::StatusStr[u2->info()->status()]);
      else
        return Globals::StatusStr[u2->info()->status()].compare(Globals::StatusStr[u1->info()->status()]);

    case StatusDescription :
      if(order) return u1->info()->statusDescription().compare(u2->info()->statusDescription());
      else      return u2->info()->statusDescription().compare(u1->info()->statusDescription());

    case IP :
      if(order)
        return (u1->info()->ip() > u2->info()->ip() ? 1 : -(u1->info()->ip() < u2->info()->ip()));
      else
        return (u2->info()->ip() > u1->info()->ip() ? 1 : -(u2->info()->ip() < u1->info()->ip()));

    case CompName :
      if(order) return u1->info()->compName().compare(u2->info()->compName());
      else      return u2->info()->compName().compare(u1->info()->compName());

    case OS :
      if(order) return u1->stats()->os().compare(u2->stats()->os());
      else      return u2->stats()->os().compare(u1->stats()->os());

    case Uptime :
      if(order)
        return (u1->stats()->uptime() > u2->stats()->uptime() ? 1 :
              -(u1->stats()->uptime() < u2->stats()->uptime()));
      else
        return (u2->stats()->uptime() > u1->stats()->uptime() ? 1 :
              -(u2->stats()->uptime() < u1->stats()->uptime()));

    case ChatTime :
      if(order)
        return (u1->stats()->chatTime() > u2->stats()->chatTime() ? 1 :
              -(u1->stats()->chatTime() < u2->stats()->chatTime()));
      else
        return (u2->stats()->chatTime() > u1->stats()->chatTime() ? 1 :
              -(u2->stats()->chatTime() < u1->stats()->chatTime()));

    default : return 0;
  }
}
