/***************************************************************************
 *   Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org>                  *
 *   Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr>           *
 *                                                                         *
 *   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.                                   *
 ***************************************************************************/
#include "pic_config_word_editor.h"

#include <tqlabel.h>
#include <tqlayout.h>
#include <tqcombobox.h>
#include <tdelocale.h>

#include "common/common/misc.h"
#include "common/gui/misc_gui.h"

//----------------------------------------------------------------------------
Pic::ConfigWordComboBox::ConfigWordComboBox(TQWidget *parent)
  : ComboBox(parent)
{
  setIgnoreWheelEvent(true);
}

uint Pic::ConfigWordComboBox::index() const
{
  if ( isValid() ) return _map[currentItem()];
  if ( currentItem()==0 ) return _invalidIndex;
  return _map[currentItem()-1];
}

void Pic::ConfigWordComboBox::setItem(uint i)
{
  if ( !isValid() ) removeItem(0);
  for (uint l=0; l<_map.count(); l++)
    if ( _map[l]==i ) setCurrentItem(l);
}

void Pic::ConfigWordComboBox::setInvalidItem(uint i, const TQString &label)
{
  if ( !isValid() ) changeItem(label, 0);
  else insertItem(label, 0);
  setCurrentItem(0);
  _invalidIndex = i;
}

//----------------------------------------------------------------------------
Pic::ConfigWordDialog::ConfigWordDialog(const Memory &memory, uint ci, TQWidget *parent)
  : Dialog(parent, "config_word_dialog", true, i18n("Config Word Details"), Close, Close, false)
{
  uint nbChars = memory.device().nbCharsWord(MemoryRangeType::Config);
  const Config::Word &cword = memory.device().config()._words[ci];

  TQGridLayout *grid = new TQGridLayout(mainWidget(), 0, 0, 10, 10);
  uint row = 0;
  TQLabel *label = new TQLabel(i18n("Name:"), mainWidget());
  grid->addWidget(label, row, 0);
  label = new TQLabel(cword.name, mainWidget());
  grid->addWidget(label, row, 1);
  row++;
  label = new TQLabel(i18n("Index:"), mainWidget());
  grid->addWidget(label, row, 0);
  label = new TQLabel(TQString::number(ci), mainWidget());
  grid->addWidget(label, row, 1);
  row++;
  label = new TQLabel(i18n("Raw Value:"), mainWidget());
  grid->addWidget(label, row, 0);
  label = new TQLabel(toHexLabel(memory.word(MemoryRangeType::Config, ci), nbChars), mainWidget());
  grid->addWidget(label, row, 1);
  row++;
  label = new TQLabel(i18n("Value:"), mainWidget());
  grid->addWidget(label, row, 0);
  label = new TQLabel(toHexLabel(memory.normalizedWord(MemoryRangeType::Config, ci), nbChars), mainWidget());
  grid->addWidget(label, row, 1);
  row++;
  label = new TQLabel(i18n("Raw Blank Value:"), mainWidget());
  grid->addWidget(label, row, 0);
  label = new TQLabel(toHexLabel(cword.bvalue, nbChars), mainWidget());
  grid->addWidget(label, row, 1);
  row++;
  label = new TQLabel(i18n("Used Mask:"), mainWidget());
  grid->addWidget(label, row, 0);
  label = new TQLabel(toHexLabel(cword.usedMask(), nbChars), mainWidget());
  grid->addWidget(label, row, 1);
  row++;
  label = new TQLabel(i18n("Write Mask:"), mainWidget());
  grid->addWidget(label, row, 0);
  label = new TQLabel(toHexLabel(cword.wmask, nbChars), mainWidget());
  grid->addWidget(label, row, 1);
  row++;
  label = new TQLabel(i18n("Protected Mask:"), mainWidget());
  grid->addWidget(label, row, 0);
  label = new TQLabel(toHexLabel(cword.pmask, nbChars), mainWidget());
  grid->addWidget(label, row, 1);
  row++;
  label = new TQLabel(i18n("Checksum Mask:"), mainWidget());
  grid->addWidget(label, row, 0);
  label = new TQLabel(toHexLabel(cword.cmask, nbChars), mainWidget());
  grid->addWidget(label, row, 1);
  row++;
}

//----------------------------------------------------------------------------
Pic::ConfigWordEditor::ConfigWordEditor(Memory &memory, uint ci, bool withWordEditor, TQWidget *parent)
  : MemoryEditor(MemoryRangeType::Config, memory, parent, "pic_config_word_editor"), _configIndex(ci)
{
  if (withWordEditor) {
    TQHBoxLayout *hbox = new TQHBoxLayout(_top);
    _mdb = new MemoryRangeEditor(MemoryRangeType::Config, memory, 1, 1, ci, 1, this);
    _mdb->init();
    connect(_mdb, TQ_SIGNAL(modified()), TQ_SIGNAL(modified()));
    connect(_mdb, TQ_SIGNAL(modified()), TQ_SLOT(updateDisplay()));
    hbox->addWidget(_mdb);
    KPushButton *button = new KPushButton(i18n("Details..."), this);
    button->setFixedHeight(button->sizeHint().height());
    connect(button, TQ_SIGNAL(clicked()), TQ_SLOT(showDialog()));
    hbox->addWidget(button);
    hbox->addStretch(1);
  } else _mdb = 0;

  TQGridLayout *grid = new TQGridLayout(_top);
  grid->setColStretch(2, 1);
  const Config::Word &cword = device().config()._words[ci];
  _combos.resize(cword.masks.count());
  uint nbChars = device().nbCharsWord(MemoryRangeType::Config);
  for (uint k=0; k<_combos.count(); k++) {
    const Config::Mask &cmask = cword.masks[k];
    TQLabel *label = new TQLabel(Config::maskLabel(cmask.name) + ":", this);
    grid->addWidget(label, k, 0);
    label = new TQLabel(cmask.name, this);
    grid->addWidget(label, k, 1);
    _combos[k] = new ConfigWordComboBox(this);
    for (uint i=0; i<cmask.values.count(); i++) {
      if ( !cmask.values[i].isValid() ) continue;
      TQString label = Config::valueLabel(cmask.name, cmask.values[i].name);
      label += " (" + toHexLabel(cmask.values[i].value, nbChars) + ")";
      _combos[k]->appendItem(label, i);
    }
    connect(_combos[k], TQ_SIGNAL(activated(int)), TQ_SLOT(slotModified()));
    grid->addWidget(_combos[k], k, 2);
  }
}

void Pic::ConfigWordEditor::setReadOnly(bool readOnly)
{
  if (_mdb) _mdb->setReadOnly(readOnly);
  const Config::Word &cword = device().config()._words[_configIndex];
  for (uint k=0; k<_combos.count(); k++) {
    const Config::Mask &cmask = cword.masks[k];
    _combos[k]->setEnabled(!readOnly && !cmask.value.isOverlapping(cword.pmask) && cmask.values.count()!=1);
  }
}

void Pic::ConfigWordEditor::slotModified()
{
  BitValue v = memory().word(MemoryRangeType::Config, _configIndex);
  //tqDebug("BinWordEditor::slotModified %i: %s", _configIndex, toHex(v, 4).data());
  for (uint k=0; k<_combos.count(); k++) {
    const Config::Mask &cmask = device().config()._words[_configIndex].masks[k];
    v = v.clearMaskBits(cmask.value);
    v |= cmask.values[_combos[k]->index()].value; // set value
  }
  memory().setWord(MemoryRangeType::Config, _configIndex, v);
  //tqDebug("  now: %s", toHex(v, 4).data());
  if (_mdb) _mdb->updateDisplay();
  emit modified();
}

void Pic::ConfigWordEditor::updateDisplay()
{
  BitValue v = memory().word(MemoryRangeType::Config, _configIndex);
  uint nbChars = device().nbCharsWord(MemoryRangeType::Config);
  //tqDebug("BinWordEditor::updateDisplay %i: %s", _configIndex, toHex(v, 4).data());
  for (uint k=0; k<_combos.count(); k++) {
    const Config::Mask &cmask = device().config()._words[_configIndex].masks[k];
    for (int i=cmask.values.count()-1; i>=0; i--) {
      if ( cmask.values[i].value.isInside(v) ) {
        if ( cmask.values[i].isValid() ) _combos[k]->setItem(i);
        else {
          TQString label = i18n("<invalid>") + " (" + toHexLabel(cmask.values[i].value, nbChars) + ")";
          _combos[k]->setInvalidItem(i, label);
        }
        break;
      }
    }
  }
  if (_mdb) _mdb->updateDisplay();
}

void Pic::ConfigWordEditor::showDialog()
{
  ConfigWordDialog dialog(memory(), _configIndex, this);
  dialog.exec();
}

#include "pic_config_word_editor.moc"
