/*
    KSysGuard, the KDE System Guard

    Copyright (c) 2003 Tobias Koenig <tokoe@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.

    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.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

*/

#include <KAcceleratorManager>
#include <KLocalizedString>

#include <QColorDialog>
#include <QLineEdit>
#include <QCheckBox>
#include <QDoubleSpinBox>
#include <QFormLayout>
#include <QGridLayout>
#include <QGroupBox>
#include <QHeaderView>
#include <QLabel>
#include <QPushButton>
#include <QSpinBox>
#include <QTreeView>

#include <limits>

#include "FancyPlotterSettings.h"

FancyPlotterSettings::FancyPlotterSettings( QWidget* parent, bool locked )
  : KPageDialog( parent ), mModel( new SensorModel( this ) )
{
  setFaceType( Tabbed );
  setWindowTitle( i18n( "Plotter Settings" ) );
  setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel);
  setObjectName( QStringLiteral("FancyPlotterSettings") );
  setModal( false );

  connect(buttonBox()->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, this, &FancyPlotterSettings::okClicked);
  connect(buttonBox()->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, this, &FancyPlotterSettings::applyClicked);

  QFrame *page = nullptr;
  QGridLayout *pageLayout = nullptr;
  QGridLayout *boxLayout = nullptr;
  QGroupBox *groupBox = nullptr;
  QLabel *label = nullptr;

  // Style page
  page = new QFrame();
  addPage( page, i18n( "General" ) );
  pageLayout = new QGridLayout( page );
  pageLayout->setContentsMargins( 0, 0, 0, 0 );

  label = new QLabel( i18n( "Title:" ), page );
  pageLayout->addWidget( label, 0, 0 );

  mTitle = new QLineEdit( page );
  mTitle->setWhatsThis( i18n( "Enter the title of the display here." ) );
  pageLayout->addWidget( mTitle, 0, 1 );
  label->setBuddy( mTitle );

  mStackBeams = new QCheckBox( i18n("Stack the beams on top of each other"), page);
  mStackBeams->setWhatsThis( i18n("The beams are stacked on top of each other, and the area is drawn filled in. So if one beam has a value of 2 and another beam has a value of 3, the first beam will be drawn at value 2 and the other beam drawn at 2+3=5.") );
  pageLayout->addWidget( mStackBeams, 1, 0,1,2);

  pageLayout->setRowStretch( 2, 1 );

  // Scales page
  page = new QFrame();
  addPage( page, i18n( "Scales" ) );
  pageLayout = new QGridLayout( page );
  pageLayout->setContentsMargins( 0, 0, 0, 0 );

  groupBox = new QGroupBox( i18n( "Vertical scale" ), page );
  boxLayout = new QGridLayout;
  groupBox->setLayout( boxLayout );
  boxLayout->setColumnStretch( 2, 1 );

  mManualRange = new QCheckBox( i18n( "Specify graph range:" ), groupBox );
  mManualRange->setWhatsThis( i18n( "Check this box if you want the display range to adapt dynamically to the currently displayed values; if you do not check this, you have to specify the range you want in the fields below." ) );
  mManualRange->setChecked(true);
  boxLayout->addWidget( mManualRange, 0, 0, 1, 5 );

  mMinValueLabel = new QLabel( i18n( "Minimum value:" ), groupBox );
  boxLayout->addWidget( mMinValueLabel, 1, 0 );

  mMinValue = new QDoubleSpinBox( groupBox );
  mMinValue->setMaximum( std::numeric_limits<long long>::max());
  mMinValue->setMinimum( std::numeric_limits<long long>::min());
  mMinValue->setWhatsThis( i18n( "Enter the minimum value for the display here." ) );
  mMinValue->setSingleStep(10);
  boxLayout->addWidget( mMinValue, 1, 1 );
  mMinValueLabel->setBuddy( mMinValue );

  mMaxValueLabel = new QLabel( i18n( "Maximum value:" ), groupBox );
  boxLayout->addWidget( mMaxValueLabel, 1, 3 );

  mMaxValue = new QDoubleSpinBox( groupBox);
  mMaxValue->setMaximum( std::numeric_limits<long long>::max());
  mMaxValue->setMinimum( std::numeric_limits<long long>::min());
  mMaxValue->setWhatsThis( i18n( "Enter the soft maximum value for the display here. The upper range will not be reduced below this value, but will still go above this number for values above this value." ) );
  mMaxValue->setSingleStep(10);
  boxLayout->addWidget( mMaxValue, 1, 4 );
  mMaxValueLabel->setBuddy( mMaxValue );

  pageLayout->addWidget( groupBox, 0, 0 );

  groupBox = new QGroupBox( i18n( "Horizontal scale" ), page );
  QFormLayout *formLayout = new QFormLayout(groupBox);

  mHorizontalScale = new QSpinBox( groupBox );
  mHorizontalScale->setValue( 1 );
  mHorizontalScale->setMinimum( 1 );
  mHorizontalScale->setMaximum( 50 );

  formLayout->addRow( i18n("Pixels per time period:"), mHorizontalScale );


  pageLayout->addWidget( groupBox, 1, 0 );

  // Grid page
  page = new QFrame( );
  addPage( page, i18n( "Grid" ) );
  pageLayout = new QGridLayout( page );
  pageLayout->setContentsMargins( 0, 0, 0, 0 );

  groupBox = new QGroupBox( i18n( "Lines" ), page );
  boxLayout = new QGridLayout;
  groupBox->setLayout( boxLayout );
  boxLayout->setColumnStretch( 1, 1 );

  mShowVerticalLines = new QCheckBox( i18n( "Vertical lines" ), groupBox );
  mShowVerticalLines->setWhatsThis( i18n( "Check this to activate the vertical lines if display is large enough." ) );
  boxLayout->addWidget( mShowVerticalLines, 0, 0 );

  label = new QLabel( i18n( "Distance:" ), groupBox );
  boxLayout->addWidget( label, 0, 2 );

  mVerticalLinesDistance = new QSpinBox( groupBox );
  mVerticalLinesDistance->setValue( 0 );
  mVerticalLinesDistance->setMinimum( 10 );
  mVerticalLinesDistance->setMaximum( 120 );
  mVerticalLinesDistance->setWhatsThis( i18n( "Enter the distance between two vertical lines here." ) );
  boxLayout->addWidget( mVerticalLinesDistance , 0, 3 );
  label->setBuddy( mVerticalLinesDistance );

  mVerticalLinesScroll = new QCheckBox( i18n( "Vertical lines scroll" ), groupBox );
  boxLayout->addWidget( mVerticalLinesScroll, 1, 0, 1, -1 );

  mShowHorizontalLines = new QCheckBox( i18n( "Horizontal lines" ), groupBox );
  mShowHorizontalLines->setWhatsThis( i18n( "Check this to enable horizontal lines if display is large enough." ) );
  boxLayout->addWidget( mShowHorizontalLines, 2, 0, 1, -1 );

  pageLayout->addWidget( groupBox, 0, 0, 1, 2 );

  groupBox = new QGroupBox( i18n( "Text" ), page );
  boxLayout = new QGridLayout;
  groupBox->setLayout( boxLayout );
  boxLayout->setColumnStretch( 1, 1 );

  mShowAxis = new QCheckBox( i18n( "Show axis labels" ), groupBox );
  mShowAxis->setWhatsThis( i18n( "Check this box if horizontal lines should be decorated with the values they mark." ) );
  boxLayout->addWidget( mShowAxis, 0, 0, 1, -1 );

  label = new QLabel( i18n( "Font size:" ), groupBox );
  boxLayout->addWidget( label, 1, 0 );

  mFontSize = new QSpinBox( groupBox );
  mFontSize->setValue( 8 );
  mFontSize->setMinimum( 1 );
  mFontSize->setMaximum( 1000 );
  boxLayout->addWidget( mFontSize, 1, 1 );
  label->setBuddy( mFontSize );

  pageLayout->addWidget( groupBox, 1, 0 );

  pageLayout->setRowStretch( 2, 1 );

  // Sensors page
  page = new QFrame( );
  addPage( page, i18n( "Sensors" ) );
  pageLayout = new QGridLayout( page );
  pageLayout->setContentsMargins( 0, 0, 0, 0 );
  pageLayout->setRowStretch( 2, 1 );
  pageLayout->setRowStretch( 5, 1 );

  mView = new QTreeView( page );
  mView->header()->setStretchLastSection( false );
  mView->setRootIsDecorated( false );
  mView->setItemsExpandable( false );
  mView->setModel( mModel );
  mView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
  bool hideFirstColumn = true;
  for(int i = 0; i < mModel->rowCount(); i++)
    if(mModel->data(mModel->index(i, 0)) != QLatin1String("localhost")) {
      hideFirstColumn = false;
      break;
    }
  if(hideFirstColumn)
    mView->hideColumn(0);

  pageLayout->addWidget( mView, 0, 0, 6, 1 );
  connect(mView, &QTreeView::doubleClicked, this, &FancyPlotterSettings::editSensor);

  mEditButton = new QPushButton( i18n( "Set Color..." ), page );
  mEditButton->setWhatsThis( i18n( "Push this button to configure the color of the sensor in the diagram." ) );
  pageLayout->addWidget( mEditButton, 0, 1 );

  mRemoveButton = nullptr;
  mMoveUpButton = nullptr;
  mMoveDownButton = nullptr;
  if ( !locked ) {
    mRemoveButton = new QPushButton( i18n( "Delete" ), page );
    mRemoveButton->setWhatsThis( i18n( "Push this button to delete the sensor." ) );
    pageLayout->addWidget( mRemoveButton, 1, 1 );
    connect(mRemoveButton, &QPushButton::clicked, this, &FancyPlotterSettings::removeSensor);

    mMoveUpButton = new QPushButton( i18n( "Move Up" ), page );
    mMoveUpButton->setEnabled( false );
    pageLayout->addWidget( mMoveUpButton, 2, 1 );
    connect(mMoveUpButton, &QPushButton::clicked, this, &FancyPlotterSettings::moveUpSensor);

    mMoveDownButton = new QPushButton( i18n( "Move Down" ), page );
    mMoveDownButton->setEnabled( false );
    pageLayout->addWidget( mMoveDownButton, 3, 1 );
    connect(mMoveDownButton, &QPushButton::clicked, this, &FancyPlotterSettings::moveDownSensor);

    connect(mView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &FancyPlotterSettings::selectionChanged);

  }

  connect(mManualRange, &QCheckBox::toggled, mMinValue, &QDoubleSpinBox::setEnabled);
  connect(mManualRange, &QCheckBox::toggled, mMaxValue, &QDoubleSpinBox::setEnabled);
  connect(mManualRange, &QCheckBox::toggled, mMinValueLabel, &QLabel::setEnabled);
  connect(mManualRange, &QCheckBox::toggled, mMaxValueLabel, &QLabel::setEnabled);

  connect(mShowVerticalLines, &QCheckBox::toggled, mVerticalLinesDistance, &QSpinBox::setEnabled);
  connect(mShowVerticalLines, &QCheckBox::toggled, mVerticalLinesScroll, &QCheckBox::setEnabled);

  connect(mEditButton, &QPushButton::clicked, this, &FancyPlotterSettings::editSensor);

  KAcceleratorManager::manage( this );
}

FancyPlotterSettings::~FancyPlotterSettings()
{
}

void FancyPlotterSettings::setStackBeams( bool stack )
{
  mStackBeams->setChecked(stack);
}
bool FancyPlotterSettings::stackBeams() const {
  return mStackBeams->isChecked();
}
void FancyPlotterSettings::moveUpSensor()
{
  mModel->moveUpSensor(mView->selectionModel()->currentIndex());
  selectionChanged(mView->selectionModel()->currentIndex());
}
void FancyPlotterSettings::moveDownSensor()
{
  mModel->moveDownSensor(mView->selectionModel()->currentIndex());
  selectionChanged(mView->selectionModel()->currentIndex());
}
void FancyPlotterSettings::selectionChanged(const QModelIndex &newCurrent)
{
  mMoveUpButton->setEnabled(newCurrent.isValid() && newCurrent.row() > 0);
  mMoveDownButton->setEnabled(newCurrent.isValid() && newCurrent.row() < mModel->rowCount() -1 );
  mEditButton->setEnabled(newCurrent.isValid());
  mRemoveButton->setEnabled(newCurrent.isValid());
}

void FancyPlotterSettings::setTitle( const QString &title )
{
  mTitle->setText( title );
}

QString FancyPlotterSettings::title() const
{
  return mTitle->text();
}

void FancyPlotterSettings::setRangeUnits( const QString & units )
{
  mMinValue->setSuffix(QLatin1Char(' ') + units);
  mMaxValue->setSuffix(QLatin1Char(' ') + units);
}

void FancyPlotterSettings::setUseManualRange( bool value )
{
  mManualRange->setChecked( value );
}

bool FancyPlotterSettings::useManualRange() const
{
  return mManualRange->isChecked();
}

void FancyPlotterSettings::setMinValue( double min )
{
  mMinValue->setValue( min );
}

double FancyPlotterSettings::minValue() const
{
  return mMinValue->value();
}

void FancyPlotterSettings::setMaxValue( double max )
{
  mMaxValue->setValue( max );
}

void FancyPlotterSettings::setHasIntegerRange( bool hasIntegerRange )
{
    mMaxValue->setDecimals( hasIntegerRange?0:2 );
    mMinValue->setDecimals( hasIntegerRange?0:2 );
}
double FancyPlotterSettings::maxValue() const
{
  return mMaxValue->value();
}

void FancyPlotterSettings::setHorizontalScale( int scale )
{
  mHorizontalScale->setValue( scale );
}

int FancyPlotterSettings::horizontalScale() const
{
  return mHorizontalScale->value();
}

void FancyPlotterSettings::setShowVerticalLines( bool value )
{
  mShowVerticalLines->setChecked( value );
  mVerticalLinesDistance->setEnabled(  value );
  mVerticalLinesScroll->setEnabled( value );
}

bool FancyPlotterSettings::showVerticalLines() const
{
  return mShowVerticalLines->isChecked();
}

void FancyPlotterSettings::setVerticalLinesDistance( int distance )
{
  mVerticalLinesDistance->setValue( distance );
}

int FancyPlotterSettings::verticalLinesDistance() const
{
  return mVerticalLinesDistance->value();
}

void FancyPlotterSettings::setVerticalLinesScroll( bool value )
{
  mVerticalLinesScroll->setChecked( value );
}

bool FancyPlotterSettings::verticalLinesScroll() const
{
  return mVerticalLinesScroll->isChecked();
}

void FancyPlotterSettings::setShowHorizontalLines( bool value )
{
  mShowHorizontalLines->setChecked( value );

}

bool FancyPlotterSettings::showHorizontalLines() const
{
  return mShowHorizontalLines->isChecked();
}

void FancyPlotterSettings::setShowAxis( bool value )
{
  mShowAxis->setChecked( value );
}

bool FancyPlotterSettings::showAxis() const
{
  return mShowAxis->isChecked();
}

void FancyPlotterSettings::setShowTopBar( bool value )
{
  mShowTopBar->setChecked( value );
}

bool FancyPlotterSettings::showTopBar() const
{
  return mShowTopBar->isChecked();
}

void FancyPlotterSettings::setFontSize( int size )
{
  mFontSize->setValue( size );
}

int FancyPlotterSettings::fontSize() const
{
  return mFontSize->value();
}
void FancyPlotterSettings::setSensors( const SensorModelEntry::List &list )
{
  mModel->setSensors( list );

  mView->selectionModel()->setCurrentIndex( mModel->index( 0, 0 ), QItemSelectionModel::SelectCurrent |
                                                                   QItemSelectionModel::Rows );
}

SensorModelEntry::List FancyPlotterSettings::sensors() const
{
  return mModel->sensors();
}

void FancyPlotterSettings::editSensor()
{
  if ( !mView->selectionModel() )
    return;

  const QModelIndex index = mView->selectionModel()->currentIndex();
  if ( !index.isValid() )
    return;

  SensorModelEntry sensor = mModel->sensor( index );

  QColorDialog dialog( this );
  dialog.setModal( true );
  connect( &dialog, &QColorDialog::colorSelected, this, &FancyPlotterSettings::setColorForSelectedItem );
  QColor color = sensor.color();
  dialog.setCurrentColor( color );
  int result = dialog.exec();

  if ( result == QColorDialog::Accepted )
    sensor.setColor( dialog.currentColor() );
  //If it's not accepted, make sure we set the color back to how it was
  mModel->setSensor( sensor, index );
}

void FancyPlotterSettings::setColorForSelectedItem(const QColor &color)
{
    const QModelIndex index = mView->selectionModel()->currentIndex();
    if ( !index.isValid() )
        return;

    SensorModelEntry sensor = mModel->sensor( index );

    sensor.setColor( color );
    mModel->setSensor( sensor, index );
}

void FancyPlotterSettings::removeSensor()
{
  if ( !mView->selectionModel() )
    return;

  const QModelIndex index = mView->selectionModel()->currentIndex();
  if ( !index.isValid() )
    return;
  mModel->removeSensor( index );
  selectionChanged( mView->selectionModel()->currentIndex() );
}

void FancyPlotterSettings::clearDeleted()
{
  mModel->clearDeleted();
}

QList<int> FancyPlotterSettings::deleted() const
{
  return mModel->deleted();
}

QList<int> FancyPlotterSettings::order() const
{
  return mModel->order();
}

void FancyPlotterSettings::resetOrder()
{
  mModel->resetOrder();
}




