/***************************************************************************
 *   Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org>                  *
 *                                                                         *
 *   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 "prog_group_ui.h"

#include <tdelocale.h>
#include <tdeaction.h>
#include <kiconloader.h>

#include "common/common/misc.h"
#include "common/global/purl.h"
#include "common/gui/purl_gui.h"
#include "progs/base/generic_prog.h"
#include "progs/base/prog_group.h"
#include "progs/base/prog_config.h"
#include "libgui/main_global.h"
#include "libgui/toplevel.h"
#include "devices/base/device_group.h"
#include "devices/pic/prog/pic_prog.h"

//----------------------------------------------------------------------------
Programmer::StandaloneMemoryCalibrationEditor::StandaloneMemoryCalibrationEditor(const Pic::Memory &memory, TQWidget *parent)
  : Pic::MemoryCalibrationEditor(0, const_cast<Pic::Memory &>(memory), parent)
{}

void Programmer::StandaloneMemoryCalibrationEditor::init(bool first)
{
  Pic::MemoryCalibrationEditor::init(first);
  TDEAction *action = new TDEAction(i18n("Read"), "reload", 0, TQT_TQOBJECT(this), TQT_SIGNAL(updateCalibration()), Main::toplevel().actionCollection());
  addAction(action);
  action = new TDEAction(i18n("Regenerating..."), 0, 0, TQT_TQOBJECT(this), TQT_SIGNAL(regenerate()), Main::toplevel().actionCollection());
  addAction(action);
}

//----------------------------------------------------------------------------
Programmer::ButtonContainer::ButtonContainer(const TQString &title,
                                    TQObject *receiver, const char *updateSlot, TQWidget *parent)
  : ::ButtonContainer(title, parent)
{
  if (receiver) button().appendAction(i18n("Read"), "reload", receiver, updateSlot);
}

//----------------------------------------------------------------------------
Programmer::AdvancedDialog::AdvancedDialog(Base &base, TQWidget *parent, const char *name)
  : Dialog(IconList, i18n("Advanced Dialog"), Close, Close, parent, name, true, false),
    _base(base), _calEditor(0)
{
  // programmer
  TDEIconLoader loader;
  TQPixmap pixmap = loader.loadIcon("piklab_burnchip", TDEIcon::Toolbar, TDEIcon::SizeMedium);
  TQFrame *page = addPage(i18n("Programmer"), _base.group().label(), pixmap);
  TQVBoxLayout *vbox = new TQVBoxLayout(page);
  _programmerContainer = new Container(page);
  vbox->addWidget(_programmerContainer);

  Properties properties = _base.group().properties();
  uint row = _programmerContainer->numRows();
  if ( properties & HasFirmware ) {
    _firmwareContainer = new ButtonContainer(i18n("Firmware"), TQT_TQOBJECT(this), TQT_SLOT(updateFirmware()), _programmerContainer);
    _programmerContainer->addWidget(_firmwareContainer, row,row, 0,1);
    if ( _base.group().properties() & CanUploadFirmware )
      _firmwareContainer->button().appendAction(i18n("Uploading..."), "piklab_burnchip", TQT_TQOBJECT(this), TQT_SLOT(uploadFirmware()));
    TQLabel *label = new TQLabel(i18n("Version:"), _firmwareContainer);
    _firmwareContainer->addWidget(label, 1,1, 0,0);
    _firmwareLabel = new TQLabel(_firmwareContainer);
    _firmwareContainer->addWidget(_firmwareLabel, 1,1, 1,1);
    row++;
  } else {
    _firmwareContainer = 0;
    _firmwareLabel = 0;
  }

  if ( _base.group().canReadVoltages() ) {
    _voltagesContainer = new ButtonContainer(i18n("Voltages"), TQT_TQOBJECT(this), TQT_SLOT(updateVoltages()), _programmerContainer);
    _programmerContainer->addWidget(_voltagesContainer, row,row, 0,1);
    row++;
  } else _voltagesContainer = 0;

  if ( properties & HasSelfTest ) {
    _selfTestContainer = new ButtonContainer(i18n("Self-test"), TQT_TQOBJECT(this), TQT_SLOT(updateSelfTest()), _programmerContainer);
    _programmerContainer->addWidget(_selfTestContainer, row,row, 0,1);
    row++;
  } else _selfTestContainer = 0;

  // calibration
  pixmap = loader.loadIcon("configure", TDEIcon::Toolbar, TDEIcon::SizeMedium);
  page = addPage(i18n("Calibration"), i18n("Calibration"), pixmap);
  vbox = new TQVBoxLayout(page);
  _calibrationContainer = new Container(page);
  vbox->addWidget(_calibrationContainer);
  const Device::Data *data = Main::deviceData();
  TQString s;
  if ( data==0 ) s = i18n("No device selected.");
  else if ( data->group().name()!="pic" || !static_cast<const Pic::Data *>(data)->isReadable(Pic::MemoryRangeType::Cal) )
    s = i18n("This device has no calibration information.");
  else if ( !_base.group().isSupported(data->name()) ) s = i18n("The selected device is not supported by this programmer.");
  else {
    const ::Programmer::PicBase &pbase = static_cast<const ::Programmer::PicBase &>(_base);
    _calEditor = new StandaloneMemoryCalibrationEditor(pbase.deviceMemory(), _calibrationContainer);
    connect(_calEditor, TQT_SIGNAL(updateCalibration()), TQT_SLOT(updateCalibration()));
    connect(_calEditor, TQT_SIGNAL(regenerate()), TQT_SLOT(regenerateCalibration()));
    _calEditor->init(true);
    _calEditor->setReadOnly(true);
    _calibrationContainer->addWidget(_calEditor, 0,0, 0,0);
  }
  if ( !s.isEmpty() ) {
    TQLabel *label = new TQLabel(s, _calibrationContainer);
    _calibrationContainer->addWidget(label, 0,0, 0,0);
  }
}

bool Programmer::AdvancedDialog::connectProgrammer()
{
  _base.disconnectHardware();
  if ( !_base.connectHardware() ) {
    MessageBox::sorry(i18n("Could not connect programmer."), Log::Show);
    return false;
  }
  return true;
}

bool Programmer::AdvancedDialog::ensureConnected()
{
  if ( (_base.state()==NotConnected || _base.state()==Running) && !connectProgrammer() ) return false;
  return _base.setTargetPowerOn(!readConfigEntry(Config::TargetSelfPowered).toBool());
}

void Programmer::AdvancedDialog::updateFirmware()
{
  ::PBusyCursor bc;
  if ( ensureConnected() ) _base.readFirmwareVersion();
  updateDisplay();
}

void Programmer::AdvancedDialog::uploadFirmware()
{
  PURL::Url url = PURL::getOpenUrl(":open_firmware", PURL::filter(PURL::Hex), this ,i18n("Open Firmware"));
  if ( url.isEmpty() ) return;
  ::PBusyCursor bc;
  if ( !connectProgrammer() ) return;
  if ( _base.uploadFirmware(url) )
    MessageBox::information(i18n("Firmware uploaded successfully."), Log::Show);
  else MessageBox::sorry(i18n("Error uploading firmware."), Log::Show);
  updateFirmware();
}

void Programmer::AdvancedDialog::updateVoltages()
{
  ::PBusyCursor bc;
  if ( ensureConnected() ) _base.readVoltages();
  updateDisplay();
}

void Programmer::AdvancedDialog::updateSelfTest()
{
  ::PBusyCursor bc;
  if ( ensureConnected() ) _base.selfTest(false);
  updateDisplay();
}

void Programmer::AdvancedDialog::updateCalibration()
{
  ::PBusyCursor bc;
  if ( ensureConnected() ) static_cast< ::Programmer::PicBase &>(_base).readCalibration();
  updateDisplay();
}

void Programmer::AdvancedDialog::regenerateCalibration()
{
  MessageBox::sorry(i18n("Oscillator calibration regeneration is not available with the selected programmer."), Log::Show);
}

void Programmer::AdvancedDialog::updateDisplay()
{
  if (_firmwareLabel) _firmwareLabel->setText(_base.firmwareVersion().pretty());
  if (_calEditor) _calEditor->updateDisplay();
}
