/***************************************************************************
    copyright            : (C) 2003-2006 by Robby Stephenson
    email                : robby@periapsis.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of version 2 of the GNU General Public License as  *
 *   published by the Free Software Foundation;                            *
 *                                                                         *
 ***************************************************************************/

#include "tablefieldwidget.h"
#include "../field.h"
#include "../tellico_utils.h"
#include "../tellico_kernel.h"

#include <tdelocale.h>
#include <tdepopupmenu.h>
#include <kiconloader.h>
#include <kinputdialog.h>

#include <tqtable.h>

namespace {
  static const int MIN_TABLE_ROWS = 5;
  static const int MAX_TABLE_COLS = 10;
}

using Tellico::GUI::TableFieldWidget;

TableFieldWidget::TableFieldWidget(Data::FieldPtr field_, TQWidget* parent_, const char* name_/*=0*/)
    : FieldWidget(field_, parent_, name_), m_field(field_), m_row(-1), m_col(-1) {

  bool ok;
  m_columns = Tellico::toUInt(field_->property(TQString::fromLatin1("columns")), &ok);
  if(!ok) {
    m_columns = 1;
  } else {
    m_columns = TQMIN(m_columns, MAX_TABLE_COLS); // max of 5 columns
  }

  m_table = new TQTable(MIN_TABLE_ROWS, m_columns, this);
  labelColumns(m_field);
  // allow renaming of column titles
  m_table->horizontalHeader()->setClickEnabled(true);
  m_table->horizontalHeader()->installEventFilter(this);

  m_table->verticalHeader()->setClickEnabled(true);
  m_table->verticalHeader()->installEventFilter(this);
  connect(m_table->verticalHeader(), TQT_SIGNAL(indexChange(int, int, int)), TQT_SIGNAL(modified()));

  m_table->setDragEnabled(false);
  m_table->setFocusStyle(TQTable::FollowStyle);
  m_table->setRowMovingEnabled(true); // rows can be moved
  m_table->setColumnMovingEnabled(false); // columns remain fixed

  m_table->setColumnStretchable(m_columns-1, true);
  m_table->adjustColumn(m_columns-1);
  m_table->setSelectionMode(TQTable::NoSelection);
  m_table->setHScrollBarMode(TQScrollView::AlwaysOff);

  connect(m_table, TQT_SIGNAL(valueChanged(int, int)), TQT_SIGNAL(modified()));
  connect(m_table, TQT_SIGNAL(currentChanged(int, int)), TQT_SLOT(slotCheckRows(int, int)));
  connect(m_table, TQT_SIGNAL(valueChanged(int, int)), TQT_SLOT(slotResizeColumn(int, int)));
  connect(m_table, TQT_SIGNAL(contextMenuRequested(int, int, const TQPoint&)), TQT_SLOT(contextMenu(int, int, const TQPoint&)));

  registerWidget();
}

TQString TableFieldWidget::text() const {
  TQString text, str, rstack, cstack, rowStr;
  for(int row = 0; row < m_table->numRows(); ++row) {
    rowStr.truncate(0);
    cstack.truncate(0);
    for(int col = 0; col < m_table->numCols(); ++col) {
      str = m_table->text(row, col).simplifyWhiteSpace();
      if(str.isEmpty()) {
        cstack += TQString::fromLatin1("::");
      } else {
        rowStr += cstack + str + TQString::fromLatin1("::");
        cstack.truncate(0);
      }
    }
    if(rowStr.isEmpty()) {
      rstack += TQString::fromLatin1("; ");
    } else {
      rowStr.truncate(rowStr.length()-2); // remove last semi-colon and space
      text += rstack + rowStr + TQString::fromLatin1("; ");
      rstack.truncate(0);
    }
  }
  if(!text.isEmpty()) {
    text.truncate(text.length()-2); // remove last semi-colon and space
  }

  // now reduce number of rows if necessary
  bool loop = true;
  for(int row = m_table->numRows()-1; loop && row > MIN_TABLE_ROWS; --row) {
    bool empty = true;
    for(int col = 0; col < m_table->numCols(); ++col) {
      if(!m_table->text(row, col).isEmpty()) {
        empty = false;
        break;
      }
    }
    if(empty) {
      m_table->removeRow(row);
    } else {
      loop = false;
    }
  }
  return text;
}

void TableFieldWidget::setText(const TQString& text_) {
  TQStringList list = Data::Field::split(text_, true);
  // add additional rows if needed
  if(static_cast<int>(list.count()) > m_table->numRows()) {
    m_table->insertRows(m_table->numRows(), list.count()-m_table->numRows());
  }
  int row;
  for(row = 0; row < static_cast<int>(list.count()); ++row) {
    for(int col = 0; col < m_table->numCols(); ++col) {
      m_table->setText(row, col, list[row].section(TQString::fromLatin1("::"), col, col));
    }
    m_table->showRow(row);
  }
  // remove any un-needed rows
  int minRow = TQMAX(row, MIN_TABLE_ROWS);
  for(row = m_table->numRows()-1; row >= minRow; --row) {
    m_table->removeRow(row);
  }
  // adjust all columns
  for(int col = 0; col < m_table->numCols()-1; ++col) {
    m_table->adjustColumn(col);
  }
}

void TableFieldWidget::clear() {
  bool wasEmpty = true;
  for(int row = 0; row < m_table->numRows(); ++row) {
    if(!emptyRow(row)) {
      wasEmpty = false;
    }
    for(int col = 0; col < m_table->numCols(); ++col) {
      m_table->setText(row, col, TQString());
    }
    if(row >= MIN_TABLE_ROWS) {
      m_table->removeRow(row);
      --row;
    }
  }
  editMultiple(false);
  if(!wasEmpty) {
    emit modified();
  }
}

TQWidget* TableFieldWidget::widget() {
  return m_table;
}

void TableFieldWidget::slotCheckRows(int row_, int) {
  if(row_ == m_table->numRows()-1 && !emptyRow(row_)) { // if is last row and row above is not empty
    m_table->insertRows(m_table->numRows());
  }
}

void TableFieldWidget::slotResizeColumn(int, int col_) {
  m_table->adjustColumn(col_);
}

void TableFieldWidget::slotRenameColumn() {
  if(m_col < 0 || m_col >= m_columns) {
    return;
  }
  TQString name = m_table->horizontalHeader()->label(m_col);
  bool ok;
  TQString newName = KInputDialog::getText(i18n("Rename Column"), i18n("New column name:"),
                                          name, &ok, this);
  if(ok && !newName.isEmpty()) {
    Data::FieldPtr newField = new Data::Field(*m_field);
    newField->setProperty(TQString::fromLatin1("column%1").arg(m_col+1), newName);
    if(Kernel::self()->modifyField(newField)) {
      m_field = newField;
      labelColumns(m_field);
    }
  }
}

bool TableFieldWidget::emptyRow(int row_) const {
  for(int col = 0; col < m_table->numCols(); ++col) {
    if(!m_table->text(row_, col).isEmpty()) {
      return false;
    }
  }
  return true;
}

void TableFieldWidget::labelColumns(Data::FieldPtr field_) {
  for(int i = 0; i < m_columns; ++i) {
    TQString s = field_->property(TQString::fromLatin1("column%1").arg(i+1));
    if(s.isEmpty()) {
      s = i18n("Column %1").arg(i+1);
    }
    m_table->horizontalHeader()->setLabel(i, s);
  }
}

void TableFieldWidget::updateFieldHook(Data::FieldPtr, Data::FieldPtr newField_) {
  bool ok;
  m_columns = Tellico::toUInt(newField_->property(TQString::fromLatin1("columns")), &ok);
  if(!ok) {
    m_columns = 1;
  } else {
    m_columns = TQMIN(m_columns, MAX_TABLE_COLS); // max of 5 columns
  }
  if(m_columns != m_table->numCols()) {
    m_table->setNumCols(m_columns);
  }
  m_table->horizontalHeader()->adjustHeaderSize();
  labelColumns(newField_);
}

bool TableFieldWidget::eventFilter(TQObject* obj_, TQEvent* ev_) {
  if(ev_->type() == TQEvent::MouseButtonPress
      && static_cast<TQMouseEvent*>(ev_)->button() == TQt::RightButton) {
    if(obj_ == m_table->horizontalHeader()) {
      TQMouseEvent* ev = static_cast<TQMouseEvent*>(ev_);
      // might be scrolled
      int pos = ev->x() + m_table->horizontalHeader()->offset();
      int col = m_table->horizontalHeader()->sectionAt(pos);
      if(col >= m_columns) {
        return false;
      }
      m_row = -1;
      m_col = col;
      TDEPopupMenu menu(this);
      menu.insertItem(SmallIconSet(TQString::fromLatin1("edit")), i18n("Rename Column..."),
                      this, TQT_SLOT(slotRenameColumn()));
      menu.exec(ev->globalPos());
      return true;
    } else if(obj_ == m_table->verticalHeader()) {
      TQMouseEvent* ev = static_cast<TQMouseEvent*>(ev_);
      // might be scrolled
      int pos = ev->y() + m_table->verticalHeader()->offset();
      int row = m_table->verticalHeader()->sectionAt(pos);
      if(row < 0 || row > m_table->numRows()-1) {
        return false;
      }
      m_row = row;
      m_col = -1;
      // show regular right-click menu
      contextMenu(m_row, m_col, ev->globalPos());
      return true;
    }
  }
  return FieldWidget::eventFilter(obj_, ev_);
}

void TableFieldWidget::contextMenu(int row_, int col_, const TQPoint& p_) {
  // might get called with col == -1 for clicking on vertical header
  // but a negative row means clicking outside bounds of table
  if(row_ < 0) {
    return;
  }
  m_row = row_;
  m_col = col_;

  int id;
  TDEPopupMenu menu(this);
  menu.insertItem(SmallIconSet(TQString::fromLatin1("insrow")), i18n("Insert Row"),
                  this, TQT_SLOT(slotInsertRow()));
  menu.insertItem(SmallIconSet(TQString::fromLatin1("remrow")), i18n("Remove Row"),
                  this, TQT_SLOT(slotRemoveRow()));
  id = menu.insertItem(SmallIconSet(TQString::fromLatin1("1uparrow")), i18n("Move Row Up"),
                       this, TQT_SLOT(slotMoveRowUp()));
  if(m_row == 0) {
    menu.setItemEnabled(id, false);
  }
  id = menu.insertItem(SmallIconSet(TQString::fromLatin1("1downarrow")), i18n("Move Row Down"),
                       this, TQT_SLOT(slotMoveRowDown()));
  if(m_row == m_table->numRows()-1) {
    menu.setItemEnabled(id, false);
  }
  menu.insertSeparator();
  id = menu.insertItem(SmallIconSet(TQString::fromLatin1("edit")), i18n("Rename Column..."),
                       this, TQT_SLOT(slotRenameColumn()));
  if(m_col < 0 || m_col > m_columns-1) {
    menu.setItemEnabled(id, false);
  }
  menu.insertSeparator();
  menu.insertItem(SmallIconSet(TQString::fromLatin1("locationbar_erase")), i18n("Clear Table"),
                  this, TQT_SLOT(clear()));
  menu.exec(p_);
}

void TableFieldWidget::slotInsertRow() {
  if(m_row > -1) {
    m_table->insertRows(m_row);
    emit modified();
  }
}

void TableFieldWidget::slotRemoveRow() {
  if(m_row > -1) {
    m_table->removeRow(m_row);
    emit modified();
  }
}

void TableFieldWidget::slotMoveRowUp() {
  if(m_row > 0) {
    m_table->swapRows(m_row, m_row-1, true);
    m_table->updateContents();
    emit modified();
  }
}

void TableFieldWidget::slotMoveRowDown() {
  if(m_row < m_table->numRows()-1) {
    m_table->swapRows(m_row, m_row+1, true);
    m_table->updateContents();
    emit modified();
  }
}

#include "tablefieldwidget.moc"
