
#include <QColor>

#include "reg_model.hh"
#include "history.hh"
#include "memchecker_events.h"

RegModel::RegModel(HistoryBase *hist, QObject *parent)
  : QAbstractItemModel(parent)
  , _hist(hist)
{
  _cache_cpu_id = _cache_reg_id = -1;
  _date = 1;
  _max_reg_count = _cpu_count = 0;
}

void RegModel::setDate(int date)
{
  _cache_cpu_id = _cache_reg_id = -1;
  _date = date;
  emit dataChanged(index(0, 0), index(_max_reg_count - 1, _cpu_count * 2 - 1));
}

bool RegModel::getReg(unsigned &cpu, unsigned &reg, const QModelIndex &index) const
{
  reg = index.row();
  cpu = index.column() / 2;
  return true;
}

QModelIndex RegModel::getIndex(unsigned cpu, unsigned reg) const
{
  return index(reg, cpu * 2 + 1);
}

QVariant RegModel::data(const QModelIndex &index, int role) const
{
  if (!index.isValid())
    return QVariant();

  unsigned reg_id = index.row();
  unsigned cpu_id = index.column() / 2;

  if (reg_id != _cache_reg_id || cpu_id != _cache_cpu_id)
    _cache_ok = _hist->regInfo(_cache, _cache_cpu_id = cpu_id, _cache_reg_id = reg_id, _date);

  bool ok = _cache_ok;
  HistoryBase::reg_info_s &i = _cache;

  switch (role)
    {
    case Qt::DisplayRole: {
      if (!ok)
	return QVariant();

      QString s;
      if (index.column() & 1)
	s.sprintf("%08x", i._data);
      else
	s = QString::fromStdString(i._name);

      return QVariant(s);
    }

    case Qt::BackgroundRole: {
      QColor c = Qt::white;

      if (index.column() & 2)
	c = c.darker(110);

      return QVariant(c);
    }

    default:
      return QVariant();
    }
}

Qt::ItemFlags RegModel::flags(const QModelIndex &index) const
{
  if (!index.isValid())
    return 0;
  return index.column() & 1 ? Qt::ItemIsEnabled | Qt::ItemIsSelectable : Qt::ItemIsEnabled;
}

QVariant RegModel::headerData(int section, Qt::Orientation orientation, int role) const
{
  if (role != Qt::DisplayRole)
    return QVariant();

  QString s;

  switch (orientation) {
  case Qt::Horizontal:
    if (!(section & 1))
      s.sprintf("Cpu %u", section / 2);
    break;
  case Qt::Vertical:
    break;
  }

  return QVariant(s);
}

QModelIndex RegModel::index(int row, int column, const QModelIndex &parent) const
{
  if (column < _cpu_count * 2 && row < _hist->regCount(column / 2))
    return createIndex(row, column, 0);
  else
    return QModelIndex();
}

QModelIndex RegModel::parent(const QModelIndex &index) const
{
  return QModelIndex();
}

int RegModel::rowCount(const QModelIndex &parent) const
{
  if (parent.isValid())
    return 0;
  return _max_reg_count;
}

int RegModel::columnCount(const QModelIndex &parent) const
{
  if (parent.isValid())
    return 0;
  return _cpu_count * 2;
}

void RegModel::resetEvent(unsigned cpu)
{
  if (cpu >= _cpu_count) {
    beginInsertColumns(QModelIndex(), _cpu_count * 2, cpu * 2 + 1);
    endInsertColumns();
    _cpu_count = cpu + 1;
  }

  unsigned count = _hist->regCount(cpu);
  if (count >= _max_reg_count) {
    beginInsertRows(QModelIndex(), _max_reg_count, count - 1);
    endInsertRows();
    _max_reg_count = count;
  }

  emit dataChanged(index(0, cpu * 2), index(_max_reg_count - 1, cpu * 2 + 1));
}

