/****************************************************************************
**
** Copyright (C) 2002-2006 Frank Hemer <frank@hemer.org>,
**                         Tilo Riemer <riemer@crossvc.com>
**
**
**----------------------------------------------------------------------------
**
**----------------------------------------------------------------------------
**
** CrossVC is available under two different licenses:
**
** If CrossVC is linked against the GPLed version of Qt 
** CrossVC is released under the terms of GPL also.
**
** If CrossVC is linked against a nonGPLed version of Qt 
** CrossVC is released under the terms of the 
** CrossVC License for non-Unix platforms (CLNU)
**
**
** CrossVC License for non-Unix platforms (CLNU):
**
** Redistribution and use in binary form, without modification, 
** are permitted provided that the following conditions are met:
**
** 1. Redistributions in binary form must reproduce the above copyright
**    notice, this list of conditions and the following disclaimer in the
**    documentation and/or other materials provided with the distribution.
** 2. It is not permitted to distribute the binary package under a name
**    different than CrossVC.
** 3. The name of the authors may not be used to endorse or promote
**    products derived from this software without specific prior written
**    permission.
** 4. The source code is the creative property of the authors.
**    Extensions and development under the terms of the Gnu Public License
**    are limited to the Unix platform. Any distribution or compilation of 
**    the source code against libraries licensed other than gpl requires 
**    the written permission of the authors.
**
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR 
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
**
**
** CrossVC License for Unix platforms:
**
** 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, version 2 of the License.
** 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 version 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
*****************************************************************************/

#include "config.h"


#include <qapplication.h>
#include <qlistview.h>
#include <qpushbutton.h>
#include <qregexp.h>
#include <qwhatsthis.h>
#include <qtimer.h>

#include "globals.h"
#include "ModuleBrowserImpl.h"
#include "pixmapcache.h"
#include "DirBase.h"

ModuleBrowserImpl::ModuleBrowserImpl(
				     const QIconSet &whatsThisIconSet,
				     QDir* topDir, QString cvsRoot, QObject * caller,
				     QWidget* parent,  const char* name, bool modal, WFlags fl )
   : ModuleBrowser( parent, name, modal, fl ),
     m_caller(caller),
     m_defButtonName(m_BrowseHorM->name()),
     m_defButtonText(m_BrowseHorM->text()),
     m_topDir(topDir),
     m_TmpCvsRoot(cvsRoot),
     m_running(false)
{
   m_pWhatsThis->setIconSet(whatsThisIconSet);
#ifdef Q_WS_MAC
  m_pWhatsThis->setMaximumWidth(m_pWhatsThis->height() * 2);
#else
  m_pWhatsThis->setMaximumWidth(m_pWhatsThis->height());
#endif
   
   m_ModDict.setAutoDelete(true);
   m_ModDict = QDict<Module>(100);
}

/*  
 *  Destroys the object and frees any allocated resources
 */
ModuleBrowserImpl::~ModuleBrowserImpl()
{
   // no need to delete child widgets, Qt does it all for us
}

void ModuleBrowserImpl::start() {
   show();
   QString topModule = QString::null;

   QString dir;
   QString files = "rls -e";
   QString cvsRoot = masqWs(m_TmpCvsRoot);
   callInteractive( topModule, dir, cvsRoot,
	 files, CVS_RLSBROWSEMODULES_CMD,
	 ExtApps::g_cvsRsh.path,
	 false);
}

void ModuleBrowserImpl::parseRls ( CvsBuffer *output) {

   QListViewItem *rootItem = NULL;
   unsigned int len = (*output).numLines();
   
   m_Modules->clear();
   m_Modules->setColumnText(1,"");
   m_Modules->setRootIsDecorated(false);
   
   QString line;
   bool found = false;
   unsigned int i;
   int skiplines = outputLineOffset;
   for (i = skiplines; i<len;i++) {
      line = (*output).textLine(i);
      if (line.startsWith("D")) {
	 line = line.section('/',1,1);
	 rootItem = new QListViewItem(m_Modules,line);
	 rootItem->setPixmap( 0, findEmbeddedPixmap ("FolderClosed16x16"));
	 found = true;
      }
   }
   m_BrowseHorM->setText("CVSROOT/modules");
   if (!found) QTimer::singleShot(0,this,SLOT(toggleBrowseHorM()));
}

void ModuleBrowserImpl::parseHistory ( CvsBuffer *output) {

   m_BrowseHorM->setText("CVSROOT/modules");
   unsigned int len = (*output).numLines();
   Module *module;

   m_Modules->clear();
   m_Modules->setColumnText(1,"Last Modified");
   m_Modules->setRootIsDecorated(true);

   QString line;
   unsigned int i;
   int skiplines = outputLineOffset;
   for (i = skiplines; i<len;i++) {
      line = (*output).textLine(i);
      if (line.isEmpty()) continue;

      QStringList list = QStringList::split (' ', line);
      QString cmd = list[0];
      if (cmd.length() != 1) {
	 continue;
      }

      QString name;

      QChar cmd_code = cmd[0];

      switch (cmd_code) {
	 case 'O': {
	    if (list[5].find('[')==0) {
	       name = list [6];
	    } else {
	       name = list[5];
	    }
	    break;
	 }
	    //       case 'T': {
	    // 	break;
	    //       }
	    //       case 'F': {
	    // 	break;
	    //       }
	 case 'W': {
	    name = list[7];
	    break;
	 }
	    //       case 'U': {
	    // 	break;
	    //       }
	 case 'G': {
	    name = list[7];
	    break;
	 }
	 case 'C': {
	    name = list[7];
	    break;
	 }
	 case 'M': {
	    name = list[7];
	    break;
	 }
	 case 'A': {
	    name = list[7];
	    break;
	 }
	 default:  {
	    continue;
	 }
      }

      QString datetime = list[1]+" "+list[2];

      if ((module=m_ModDict.find(name))) {
	 switch(cmd_code) {
	    //         case 'A': {
	    // 	  module->TmCreate = datetime;
	    // 	  break;
	    // 	}
	    case 'M': {
	       if (module->details < datetime) {
		  module->details = datetime;
	       }
	       break;
	    }
	    default: {
	       break;
	    }
	 }
      } else {
	 module = new Module();
	 module->name = name;
	 switch(cmd_code) {
	    //         case 'A': {
	    // 	  module->TmCreate = datetime;
	    // 	  break;
	    // 	}
	    case 'M': {
	       module->details = datetime;
	       break;
	    }
	    default: {
	       module->details = "";
	    }
	 }
	 m_ModDict.insert(module->name,module);
      }
   }


   QDictIterator<Module>it(m_ModDict);
   while(it.current()) {

      QString name = it.current()->name + "/";
      QListViewItem *lastItem = NULL;

      int pos = name.find("/");
      QString part;
      if (pos>=0) {
	 part = name.left(pos);
	 name = name.mid(pos+1);
      } else {
	 part = name;
      }
      QListViewItem *rootItem = NULL;

      if (!(rootItem=m_Modules->findItem(part,0))) {
	 rootItem = new QListViewItem(m_Modules,part);
	 rootItem->setPixmap( 0, findEmbeddedPixmap ("FolderClosed16x16"));
      }
      lastItem = rootItem;
      while ((pos=name.find("/"))>0) {
	 part = name.left(pos);
	 name = name.mid(pos+1);
	 QListViewItem *item = lastItem->firstChild();
	 bool found = false;
	 while(item) {
	    if (item->text(0)==part) {
	       lastItem = item;
	       found = true;
	       break;
	    } else {
	       item = item->nextSibling();
	    }
	 }
	 if (!found) {
	    lastItem = new QListViewItem(lastItem,part);
	    lastItem->setPixmap( 0, findEmbeddedPixmap ("FolderClosed16x16"));
	 }
      }
      lastItem->setText(1,it.current()->details);
      ++it;
   }
}

void ModuleBrowserImpl::parseModules ( CvsBuffer *output) {

   QListViewItem *rootItem = NULL;
   m_BrowseHorM->setText("CVSROOT/history");
   unsigned int len = (*output).numLines();
   int pos = 0;
   QString module;

   m_Modules->clear();
   m_Modules->setColumnText(1,"Alias/Dir");
   m_Modules->setRootIsDecorated(false);

   QString line;
   bool contLine = false;
   unsigned int i;
   int skiplines = outputLineOffset + 6;

   for (i = skiplines; i<len;i++) {
      if (contLine) {
	 line += (*output).textLine(i);
	 contLine = false;
      } else {
	 line = (*output).textLine(i);
      }
      if (line.isEmpty()) {
	 contLine = false;
	 continue;
      } else if (line.find("#")==0) {
	 continue;
      } else if ((pos=line.find("#"))>0) {
	 line = line.left(pos);
      }
      if ((pos=line.find("\\"))>-1) {
	 line = line.left(pos);
	 contLine = true;
	 continue;
      }

      line = line.simplifyWhiteSpace();
      pos = line.find(" ");
      module = line.left(pos);
      line = line.mid(pos+1);
      rootItem = new QListViewItem(m_Modules,module,line);
      rootItem->setPixmap( 0, findEmbeddedPixmap ("FolderClosed16x16"));
   }
}

QString ModuleBrowserImpl::getModule() {

   QString module;
   QListViewItem *item = m_Modules->selectedItem();

   while (item) {
      module = item->text(0) + "/" + module;
      if (!(item = item->parent())) {
	 // Remove trailing "/"
	 module.replace (QRegExp ("/+$"), "");
      };
   }

   return module;
}

QString ModuleBrowserImpl::getCheckoutAsDOption() {

   QString moduleAliasDir = "";
   QListViewItem *item = m_Modules->selectedItem();

   if (item) {
      QStringList options = QStringList::split(" ",item->text(1));
      for ( QStringList::Iterator it = options.begin(); it != options.end(); ++it ) {
	 if (*it == "-d") {
	    ++it;
	    if (it != options.end()) {
	       moduleAliasDir = *it;
	    }
	    break;
	 }
      }
   }
   return moduleAliasDir;
}

void ModuleBrowserImpl::accept() {
   emit OkClicked();
   ModuleBrowser::accept();
}

void ModuleBrowserImpl::select() {
   m_Choice->setText(getModule());
}

void ModuleBrowserImpl::toggleBrowseHorM() {

   if (m_running) {
    
      QTimer::singleShot(0,m_caller,SLOT(stopCurAction()));

   } else {

      QString dir = "";
      QString cvsRoot = masqWs(m_TmpCvsRoot);
      QString topModule = QString::null;
      
      if (m_BrowseHorM->text()=="CVSROOT/modules") {
	 QString strCmd = "checkout -p -n CVSROOT/modules";
	 callInteractive( topModule, dir, cvsRoot,
	       strCmd, CVS_MBROWSEMODULES_CMD,
	       ExtApps::g_cvsRsh.path,  //additional options of cvsRsh not supported yet
	       false);
      } else {
	 QString files = "history -xAMR -a -l";
	 callInteractive( topModule, dir, cvsRoot,
	       files, CVS_HBROWSEMODULES_CMD,
	       ExtApps::g_cvsRsh.path,  //additional options of cvsRsh not supported yet
	       false);
      }
   }
}

void ModuleBrowserImpl::setEnabled(bool state) {
   m_pWhatsThis->setEnabled(state);
   m_Modules->setEnabled(state);
   m_OkButton->setEnabled(state);
   m_CancelButton->setEnabled(state);
}

void ModuleBrowserImpl::cvsCallStarted() {
   m_running = true;
   m_defButtonText = m_BrowseHorM->text();
   m_BrowseHorM->setName("stop action");
   m_BrowseHorM->setText(tr("stop"));
   setEnabled(FALSE);
   QApplication::setOverrideCursor(Qt::waitCursor);
}

void ModuleBrowserImpl::cvsCallFinished() {
   QApplication::restoreOverrideCursor();
   setEnabled(TRUE);
   m_BrowseHorM->setName(m_defButtonName);
   m_running = false;
}

void ModuleBrowserImpl::afterCall(int cmd, CvsBuffer *output, bool failed) {
   if (!failed) {
      switch (cmd) {
	 case CVS_RLSBROWSEMODULES_CMD: {
	    parseRls (output);
	    break;
	 }
	 case CVS_MBROWSEMODULES_CMD: {
// 	    bool fileOk = false;
// 	    QString line;
// 	    unsigned int len = (*output).numLines();
// 	    unsigned int skipLines = outputLineOffset + 6;
// 	    for ( unsigned int i = skipLines; i<len;i++) {//only two lines if no CVSROOT/modules file
// 	       line = (*output).textLine(i);
// 	       if ( (line.at(0)!='#') && ( !(line.isEmpty()) ) ) {
// 		  fileOk = true;
// 		  break;
// 	       }
// 	    }
// 	    if (!fileOk) {
// 	       QString dir = "";
// 	       QString files = "history -xAMR -a -l";
// 	       QString topModule = QString::null;
// 	       callInteractive( topModule, dir, m_TmpCvsRoot,
// 		     files, CVS_HBROWSEMODULES_CMD,
// 		     ExtApps::g_cvsRsh.path,  //additional options of cvsRsh not supported yet
// 		     false);
// 	       return;
// 	    } else {
	       parseModules (output);
// 	    }
	    break;
	 }
	 case CVS_HBROWSEMODULES_CMD: {
	    parseHistory (output);
	    break;
	 }
      }
   } else {
      m_BrowseHorM->setName(m_defButtonName);
      m_BrowseHorM->setText(m_defButtonText);
   }
   cvsCallFinished();
}

void ModuleBrowserImpl::enterWhatsThisMode()
{
   QWhatsThis::enterWhatsThisMode();
}



syntax highlighted by Code2HTML, v. 0.9.1