/*****************************************************************************
                          tdefilereplaceview.cpp  -  description
                             -------------------
    begin                : sam oct 16 15:28:00 CEST 1999
    copyright            : (C) 1999 by Fran�is Dupoux <dupoux@dupoux.com>
                           (C) 2004 Emiliano Gulmini <emi_barbarossa@yahoo.it>
*****************************************************************************/

/*****************************************************************************
 *                                                                           *
 *   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.                                     *
 *                                                                           *
 *****************************************************************************/

// TQt
#include <tqwhatsthis.h>
#include <tqmap.h>
#include <tqfileinfo.h>

// KDE
#include <tdelistview.h>
#include <tdemessagebox.h>
#include <tdelocale.h>
#include <tdepopupmenu.h>
#include <krun.h>
#include <kpropertiesdialog.h>
#include <tdeapplication.h>
#include <dcopclient.h>
#include <dcopref.h>
//#include <kdebug.h>
#include <kiconloader.h>
#include <kled.h>
#include <tdefiledialog.h>

// local
#include "tdefilereplaceview.h"
#include "tdefilereplacelib.h"
#include "kaddstringdlg.h"
#include "whatthis.h"

using namespace whatthisNameSpace;

TDEFileReplaceView::TDEFileReplaceView(RCOptions* info, TQWidget *parent,const char *name) :
    TDEFileReplaceViewWdg(parent,name)
{
  m_option = info;

  initGUI();

  // result listview: connect events
  connect(m_lvResults, TQT_SIGNAL(mouseButtonClicked(int, TQListViewItem *, const TQPoint &, int)),
          this, TQT_SLOT(slotResultMouseButtonClicked(int, TQListViewItem *, const TQPoint &)));
  connect(m_lvResults, TQT_SIGNAL(returnPressed(TQListViewItem *)),
          this, TQT_SLOT(slotResultReturnPressed(TQListViewItem *)));
  connect(m_lvResults, TQT_SIGNAL(executed(TQListViewItem *)),
          this, TQT_SLOT(slotResultReturnPressed(TQListViewItem *)));
  connect(m_lvResults_2, TQT_SIGNAL(mouseButtonClicked(int, TQListViewItem *, const TQPoint &, int)),
          this, TQT_SLOT(slotResultMouseButtonClicked(int, TQListViewItem *, const TQPoint &))); 
  connect(m_lvResults_2, TQT_SIGNAL(returnPressed(TQListViewItem *)),
          this, TQT_SLOT(slotResultReturnPressed(TQListViewItem *)));
  connect(m_lvResults_2, TQT_SIGNAL(executed(TQListViewItem *)),
          this, TQT_SLOT(slotResultReturnPressed(TQListViewItem *)));
  // connect header events
  connect(m_lvResults->header(), TQT_SIGNAL(clicked(int)), this,TQT_SLOT(slotResultHeaderClicked(int)));
  connect(m_lvResults_2->header(), TQT_SIGNAL(clicked(int)), this,TQT_SLOT(slotResultHeaderClicked(int)));
  
  // string listview: connect events
  connect(m_lvStrings, TQT_SIGNAL(doubleClicked(TQListViewItem *)), this, TQT_SLOT(slotStringsEdit()));
  connect(m_lvStrings_2, TQT_SIGNAL(doubleClicked(TQListViewItem *)), this, TQT_SLOT(slotStringsEdit()));

  whatsThis();
}

TQString TDEFileReplaceView::currentPath()
{
  TQListViewItem *lvi;

  if(! m_lviCurrent) lvi = m_rv->currentItem();
  else lvi = (TQListViewItem*) m_lviCurrent;

  while (lvi->parent())
    lvi = lvi->parent();

  return TQString(lvi->text(1)+"/"+lvi->text(0));
}

void TDEFileReplaceView::showSemaphore(TQString s)
{
  if(s == "green")
  {
    m_ledGo->setState(KLed::On);
    m_ledWait->setState(KLed::Off);
    m_ledStop->setState(KLed::Off);
  }
  else
    if(s == "yellow")
  {
    m_ledGo->setState(KLed::Off);
    m_ledWait->setState(KLed::On);
    m_ledStop->setState(KLed::Off);
  }
  else
    if(s == "red")
  {
    m_ledGo->setState(KLed::Off);
    m_ledWait->setState(KLed::Off);
    m_ledStop->setState(KLed::On);
  }
}

void TDEFileReplaceView::displayScannedFiles(int foldersNumber, int filesNumber)
{ 
  m_lcdFoldersNumber->display(TQString::number(foldersNumber,10));
  m_lcdFilesNumber->display(TQString::number(filesNumber,10));
}

void TDEFileReplaceView::stringsInvert(bool invertAll)
{
  TQListViewItem* lviCurItem,
  * lviFirst;
  TDEListView* sv = getStringsView();

  if(invertAll)
    lviCurItem = lviFirst = sv->firstChild();
  else
    lviCurItem = lviFirst = sv->currentItem();

  if(lviCurItem == 0)
    return ;

  do
  {
    TQString searchText = lviCurItem->text(0),
            replaceText = lviCurItem->text(1);

      // Cannot invert the string when search string is empty
    if (replaceText.isEmpty())
    {
      KMessageBox::error(0, i18n("<qt>Cannot invert string <b>%1</b>, because the search string would be empty.</qt>").arg(searchText));
      return;
    }

    lviCurItem->setText(0, replaceText);
    lviCurItem->setText(1, searchText);

    lviCurItem = lviCurItem->nextSibling();
    if(!invertAll)
      break;
  } while(lviCurItem && lviCurItem != lviFirst);
  setCurrentStringsViewMap();
}

void TDEFileReplaceView::changeView(bool searchingOnlyMode)
{
  if(searchingOnlyMode)
    {
      m_stackResults->raiseWidget(m_lvResults_2);
      m_stackStrings->raiseWidget(m_lvStrings_2);
      m_rv = m_lvResults_2;
      m_sv = m_lvStrings_2;
    }
  else
    {
      m_stackResults->raiseWidget(m_lvResults);
      m_stackStrings->raiseWidget(m_lvStrings);
      m_rv = m_lvResults;
      m_sv = m_lvStrings;
    }
}

TDEListView* TDEFileReplaceView::getResultsView()
{
  if(m_option->m_searchingOnlyMode)
    m_rv = m_lvResults_2;
  else
    m_rv = m_lvResults;

  return m_rv;
}

TDEListView* TDEFileReplaceView::getStringsView()
{
  if(m_option->m_searchingOnlyMode)
    m_sv = m_lvStrings_2;
  else
    m_sv = m_lvStrings;
  return m_sv;
}

//PUBLIC SLOTS
void TDEFileReplaceView::slotResultMouseButtonClicked(int button, TQListViewItem *lvi, const TQPoint &pos)
{
  if (lvi == 0) // No item selected
    return;

  if (button == Qt::RightButton)
  {
    // Right mouse button: open popup menub
    m_lviCurrent = static_cast<TDEListViewItem*>(lvi);
    m_menuResult->popup(pos);
  }
}

void TDEFileReplaceView::slotResultReturnPressed (TQListViewItem *lvi)
{
  if (lvi == 0) // No item selected
    return;

  // Left mouse button: open item in default view
  m_lviCurrent = static_cast<TDEListViewItem*>(lvi);
  slotResultOpen();
}

void TDEFileReplaceView::slotResultProperties()
{
  TQString currItem = currentPath();
  if(! currItem.isEmpty())
    {
      KURL url(currItem);
      (void) new KPropertiesDialog(url);
      m_lviCurrent = 0;
    }
}

void TDEFileReplaceView::slotResultOpen()
{
  TQString currItem = currentPath();
  if(!currItem.isEmpty())
    {
      (void) new KRun(KURL(currItem), 0, true, true);
      m_lviCurrent = 0;
    }
}

void TDEFileReplaceView::slotResultOpenWith()
{
  TQString currItem = currentPath();
  if(!currItem.isEmpty())
    {
      KURL::List kurls;
      kurls.append(KURL(currItem));
      KRun::displayOpenWithDialog(kurls);
      m_lviCurrent = 0;
    }
}

void TDEFileReplaceView::slotResultDirOpen()
{
  TQString currItem = currentPath();
  if(!currItem.isEmpty())
    {
      TQFileInfo fi;
      fi.setFile(currItem);
      (void) new KRun (KURL::fromPathOrURL(fi.dirPath()), 0, true, true);
      m_lviCurrent = 0;
    }
}

void TDEFileReplaceView::slotResultEdit()
{
  TQListViewItem *lvi = m_rv->firstChild();

  while (lvi)
    {
      DCOPClient *client = kapp->dcopClient();
      DCOPRef quanta(client->appId(),"WindowManagerIf");
      TQString path = TQString(lvi->text(1)+"/"+lvi->text(0));
      TQListViewItem *lviChild = lvi;

      while(lviChild)
        {
          if(lviChild->isSelected())
            {
              coord c;
              if(lviChild == lvi)
                {
                  c.line = 0;
                  c.column = 0;
                }
              else
                {
                  c= extractWordCoordinates(lviChild);
                }
              bool success = quanta.send("openFile", path, c.line, c.column);

              if(!success)
                {
                  TQString message = i18n("File %1 cannot be opened. Might be a DCOP problem.").arg(path);
                  KMessageBox::error(parentWidget(), message);
                }
            }
            if (lviChild == lvi)
              lviChild = lviChild->firstChild();
            else
              lviChild = lviChild->nextSibling();
        }

      lvi = lvi->nextSibling();
    }

  m_lviCurrent = 0;
}

void TDEFileReplaceView::slotResultDelete()
{
  TQString currItem = currentPath();
  if (!currItem.isEmpty())
    {
      TQFile fi;
      int answer = KMessageBox::warningContinueCancel(this, i18n("Do you really want to delete %1?").arg(currItem),
                                                      TQString(),KStdGuiItem::del());

      if(answer == KMessageBox::Continue)
        {
          fi.setName(currItem);
          fi.remove();

          delete m_lviCurrent;
          m_lviCurrent = 0;
        }
    }
}

void TDEFileReplaceView::slotResultTreeExpand()
{
  TQListViewItem *lviRoot = getResultsView()->firstChild();

  if(lviRoot)
    expand(lviRoot, true);
}

void TDEFileReplaceView::slotResultTreeReduce()
{
  TQListViewItem *lviRoot = getResultsView()->firstChild();

  if(lviRoot)
    expand(lviRoot, false);
}

void TDEFileReplaceView::slotResultHeaderClicked(int sortCol)
{
  TDEListView *lv = getResultsView();
  int oldSortCol = lv->columnSorted();
    
  if (oldSortCol == -1 || sortCol != oldSortCol)
  {
    lv->setSorting(sortCol, true);
  }
  else
  {
    lv->setSorting(sortCol, lv->ascendingSort());
  }
}

void TDEFileReplaceView::slotStringsAdd()
{
  KeyValueMap oldMap(m_option->m_mapStringsView);

  KAddStringDlg addStringDlg(m_option, false);

  if(!addStringDlg.exec())
    return;

  KeyValueMap addedStringsMap(m_option->m_mapStringsView);
  KeyValueMap::Iterator itMap;

  for(itMap = oldMap.begin(); itMap != oldMap.end(); ++itMap)
    addedStringsMap.insert(itMap.key(),itMap.data());

  m_option->m_mapStringsView = addedStringsMap;

  raiseResultsView();
  raiseStringsView();

  loadMapIntoView(addedStringsMap);
}

void TDEFileReplaceView::slotQuickStringsAdd(const TQString& quickSearch, const TQString& quickReplace)
{
  if(!quickSearch.isEmpty())
  {
    KeyValueMap map;
    if(quickReplace.isEmpty())
    {
      map[quickSearch] = TQString();
      m_option->m_searchingOnlyMode = true;
    }
    else
    {
      map[quickSearch] = quickReplace;
      m_option->m_searchingOnlyMode = false;
    }

    m_option->m_mapStringsView = map;

    raiseResultsView();
    raiseStringsView();

    loadMapIntoView(map);
  }
}

void TDEFileReplaceView::slotStringsEdit()
{
  KeyValueMap oldMap(m_option->m_mapStringsView);
  if(oldMap.isEmpty()) return;
  bool oldSearchFlagValue = m_option->m_searchingOnlyMode;

  oldMap.remove(m_sv->currentItem()->text(0));

  m_option->m_mapStringsView.clear();

  m_option->m_mapStringsView.insert(m_sv->currentItem()->text(0), m_sv->currentItem()->text(1));

  KAddStringDlg addStringDlg(m_option, true);

  if(!addStringDlg.exec())
    return;

  KeyValueMap newMap(m_option->m_mapStringsView);
  if(oldSearchFlagValue == m_option->m_searchingOnlyMode)
  {
    KeyValueMap::Iterator itMap;

      //merges the two maps
    for(itMap = oldMap.begin(); itMap != oldMap.end(); ++itMap)
      newMap.insert(itMap.key(),itMap.data());
  }

  m_option->m_mapStringsView = newMap;

  raiseResultsView();
  raiseStringsView();

  loadMapIntoView(newMap);
}

void TDEFileReplaceView::slotStringsSave()
{
  // Check there are strings in the list
  TDEListView* sv = getStringsView();

  if (sv->firstChild() == 0)
  {
    KMessageBox::error(0, i18n("No strings to save as the list is empty."));
    return ;
  }

  TQString header("<?xml version=\"1.0\" ?>\n<kfr>"),
  footer("\n</kfr>"),
  body;
  if(m_option->m_searchingOnlyMode)
    header += "\n\t<mode search=\"true\"/>";
  else
    header += "\n\t<mode search=\"false\"/>";

  TQListViewItem*  lvi = sv->firstChild();

  while( lvi )
  {
    body += TQString("\n\t<replacement>"
	"\n\t\t<oldstring><![CDATA[%1]]></oldstring>"
	"\n\t\t<newstring><![CDATA[%2]]></newstring>"
	"\n\t</replacement>").arg(lvi->text(0)).arg(lvi->text(1));
    lvi = lvi->nextSibling();
  }

   // Selects the file where strings will be saved
  TQString menu = "*.kfr|" + i18n("TDEFileReplace Strings") + " (*.kfr)\n*|" + i18n("All Files") + " (*)";
  TQString fileName = KFileDialog::getSaveFileName(TQString(), menu, 0, i18n("Save Strings to File"));
  if (fileName.isEmpty())
    return;

   // Forces the extension to be "kfr" == TDEFileReplace extension

  fileName = TDEFileReplaceLib::addExtension(fileName, "kfr");

  TQFile file( fileName );
  if(!file.open( IO_WriteOnly ))
  {
    KMessageBox::error(0, i18n("File %1 cannot be saved.").arg(fileName));
    return ;
  }
  TQTextStream oTStream( &file );
  oTStream.setEncoding(TQTextStream::UnicodeUTF8);
  oTStream << header
      << body
      << footer;
  file.close();
}

void TDEFileReplaceView::slotStringsDeleteItem()
{
  TQListViewItem* item = m_sv->currentItem();
  if(item != 0)
  {
    KeyValueMap m = m_option->m_mapStringsView;
    m.remove(item->text(0));
    m_option->m_mapStringsView = m;
    delete item;
  }
}

void TDEFileReplaceView::slotStringsEmpty()
{
  TQListViewItem * myChild = m_sv->firstChild();
  while( myChild )
  {
    TQListViewItem* item = myChild;
    myChild = myChild->nextSibling();
    delete item;
  }
  KeyValueMap m;
  m_option->m_mapStringsView = m;
}

//PRIVATE
void TDEFileReplaceView::initGUI()
{
  m_option->m_searchingOnlyMode = true;

  m_stackResults->addWidget(m_lvResults);
  m_stackResults->addWidget(m_lvResults_2);
  m_stackStrings->addWidget(m_lvStrings);
  m_stackStrings->addWidget(m_lvStrings_2);

  DCOPClient *client = kapp->dcopClient();
  QCStringList appList = client->registeredApplications();
  bool quantaFound = false;


  for(QCStringList::Iterator it = appList.begin(); it != appList.end(); ++it)
    {
      if((*it).left(6) == "quanta")
        {
          quantaFound = true;
          break;
        }
    }

  m_menuResult = new TDEPopupMenu(this, "ResultPopup");



  m_menuResult->insertItem(SmallIconSet(TQString::fromLatin1("document-open")),
                           i18n("&Open"),
                           this,
                           TQT_SLOT(slotResultOpen()));
  if(!quantaFound)
    {
      m_menuResult->insertItem(i18n("Open &With..."),
                               this,
                               TQT_SLOT(slotResultOpenWith()));
    }

  if(quantaFound)
    {
      m_menuResult->insertItem(SmallIconSet("quanta"),
                               i18n("&Edit in Quanta"),
                               this,
                               TQT_SLOT(slotResultEdit()));
    }

  m_menuResult->insertItem(SmallIconSet(TQString::fromLatin1("go-up")),
                           i18n("Open Parent &Folder"),
                           this,
                           TQT_SLOT(slotResultDirOpen()));
  m_menuResult->insertItem(SmallIconSet(TQString::fromLatin1("edit-delete")),
                           i18n("&Delete"),
                           this,
                           TQT_SLOT(slotResultDelete()));
  m_menuResult->insertSeparator();
  m_menuResult->insertItem(SmallIconSet(TQString::fromLatin1("application-vnd.tde.info")),
                           i18n("&Properties"),
                           this,
                           TQT_SLOT(slotResultProperties()));
  raiseResultsView();
  raiseStringsView();
}

void TDEFileReplaceView::raiseStringsView()
{
  if(m_option->m_searchingOnlyMode)
    m_sv = m_lvStrings_2;
  else
    m_sv = m_lvStrings;

  m_stackStrings->raiseWidget(m_sv);
}

void TDEFileReplaceView::raiseResultsView()
{
  if(m_option->m_searchingOnlyMode)
    m_rv = m_lvResults_2;
  else
    m_rv = m_lvResults;

  m_stackResults->raiseWidget(m_rv);
}

coord TDEFileReplaceView::extractWordCoordinates(TQListViewItem* lvi)
{
  //get coordinates of the first string of the current selected file
  coord c;
  c.line = 0;
  c.column = 0;
  TQString s = lvi->text(0);
  //tqWarning("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW=%s",s.latin1());
 /* if(lvi->parent()) s = lvi->text(0);
  else return c;*/

  TQString temp;
  int i = 0;

  //extracts line and column from lvi->text(0)
  //FIXME: Don't get the line and column number from the text as it's translated and it will
  //fail for non-English languages!

  //EMILIANO: This is not a good fixing but for now it should reduce the problems
  while(true)
    {
      if(s[i] < '0' || s[i] > '9')
	i++;
      else
	break;
    }
  while(true)
    {
      if(s[i] >= '0' && s[i] <= '9')
        {
	  temp += s[i];
	  i++;
	}
      else
	break;
    }
  c.line = temp.toInt();
  temp = TQString();

  while(true)
    {
      if(s[i] < '0' || s[i] > '9')
	i++;
      else
	break;
    }
  while(true)
    {
      if(s[i] >= '0' && s[i] <= '9')
      {
	temp += s[i];
	i++;
      }
      else
	break;
    }
  c.column = temp.toInt();

  if(c.line > 0) c.line--;
  if(c.column > 0) c.column--;

  return c;
}

void TDEFileReplaceView::expand(TQListViewItem *lviCurrent, bool b)
{
  // current item
  lviCurrent->setOpen(b);

  // recursivity
  while((lviCurrent = lviCurrent->nextSibling()) != 0)
    {
      lviCurrent->setOpen(b);

      if (lviCurrent->firstChild())
        expand(lviCurrent->firstChild(), b);
    }
}

void TDEFileReplaceView::setMap()
{
  KeyValueMap map;
  TQListViewItem* i = m_sv->firstChild();
  while(i != 0)
  {
    if(m_option->m_searchingOnlyMode)
      map[i->text(0)] = TQString();
    else
      map[i->text(0)] = i->text(1);
    i = i->nextSibling();
  }
  m_option->m_mapStringsView = map;
}

void TDEFileReplaceView::loadMapIntoView(KeyValueMap map)
{
  m_sv->clear();
  KeyValueMap::Iterator itMap;

  for(itMap = map.begin(); itMap != map.end(); ++itMap)
    {
      TQListViewItem* lvi = new TQListViewItem(m_sv);
      lvi->setMultiLinesEnabled(true);
      lvi->setText(0,itMap.key());
      if(!m_option->m_searchingOnlyMode)
        lvi->setText(1,itMap.data());
    }

}

void TDEFileReplaceView::whatsThis()
{
  TQWhatsThis::add(getResultsView(), lvResultWhatthis);
  TQWhatsThis::add(getStringsView(), lvStringsWhatthis);
}
#include "tdefilereplaceview.moc"
