/*
** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
**
*/

/*
** 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 in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
** MA 02110-1301, USA.
*/

/*
** Bug reports and questions can be sent to kde-devel@kde.org
*/

#include "../config.h"
#include <stdlib.h>

#include "tdelocale.h"
#include <tdeaction.h>
#include <kstdaction.h>
#include <kdebug.h>

#include "kpackage.h"
#include "updateLoc.h"
#include "debAptInterface.h"
#include "cache.h"
#include "pkgOptions.h"



//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

DEBAPT::DEBAPT():DEB()
{
  head = "DEBAPT";
  name = i18n("APT: Debian");

  queryMsg = i18n("Querying DEB APT package list: ");
  procMsg = i18n("KPackage: Waiting on APT-GET");

  hasRemote = TRUE;

  locatedialog = new Locations(i18n("Location of Debian Packages"));

  locatedialog->aLocations(1, 60, this, i18n("APT sources", "A"),
			   i18n("APT Sources Entries"));
  locatedialog->dLocations(1, 8, this, i18n("Folders", "F"),
			   "Deb", "*.deb",
			   i18n("Location of Folders Containing Debian Packages"));
   connect(locatedialog,TQT_SIGNAL(returnVal(LcacheObj *)),
	  this,TQT_SLOT(setAvail(LcacheObj *)));
  locatedialog->apply_slot();

  paramsInst.append(new param(i18n("Download only"),FALSE,FALSE,"-d"));
  paramsInst.append(new param(i18n("No download"),FALSE,FALSE,"--no-download"));
  paramsInst.append(new param(i18n("Ignore missing"),FALSE,FALSE,"-m"));
  paramsInst.append(new param(i18n("Ignore hold"),FALSE,FALSE,"--ignore-hold"));
  paramsInst.append(new param(i18n("Allow Unauthenticated"),FALSE,FALSE,"--allow-unauthenticated"));
  paramsInst.append(new param(i18n("Assume yes"),TRUE,FALSE,"--yes"));
  paramsInst.append(new param(i18n("Test (do not uninstall)"),FALSE,FALSE,"-s"));

  paramsUninst.append(new param(i18n("Purge Config Files"),FALSE,FALSE,"--purge"));
  paramsUninst.append(new param(i18n("Assume yes"),TRUE,FALSE,"--yes"));
  paramsUninst.append(new param(i18n("Test (do not uninstall)"),FALSE,FALSE,"-s"));

  env = "DEBIAN_FRONTEND=readline; export DEBIAN_FRONTEND; ";

  noFetch = TRUE;
  hasSearchAll = TRUE;

  hasProgram = ifExe("apt-get");
}

//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
DEBAPT::~DEBAPT()
{
}

//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

bool DEBAPT::isType(char *, const TQString &)
{
  return false;
}

void DEBAPT::makeMenu(TDEActionCollection* act)
{
  updateM = new TDEAction( i18n("&Update"), TQString(),
			 0, this,
			 TQT_SLOT(updateS()), act, "debapt_update");

  upgradeM = new TDEAction( i18n("U&pgrade"), TQString(),
			  0, this,
			  TQT_SLOT(upgradeS()), act, "debapt_upgrade");

  fixupM = new TDEAction( i18n("&Fixup"), TQString(),
			 0, this,
			 TQT_SLOT(fixupS()), act, "debapt_fixup");

  fileM = new TDEAction( i18n("&Apt-File Update"), TQString(),
			 0, this,
			 TQT_SLOT(fileS()), act, "debapt_file");
}

void DEBAPT::setMenu(TDEActionCollection*, bool enable)
{
  updateM->setEnabled(enable);
  upgradeM->setEnabled(enable);
  fixupM->setEnabled(enable);
  fileM->setEnabled(enable);
}

void DEBAPT::updateS()
{
  if (kprun->run("apt-get update", "APT update")) {
    if (kprun->exec())
      kpackage->management->collectData(TRUE);
  }
}

void DEBAPT::upgradeS()
{
  if (kprun->run(env + "apt-get dist-upgrade", "APT upgrade")) {
    if (kprun->exec())
      kpackage->management->collectData(TRUE);
  }
}

void DEBAPT::fixupS()
{
  if (kprun->run(env + "apt-get -f install", "APT fixup")) {
    if (kprun->exec())
      kpackage->management->collectData(TRUE);
  }
}

void DEBAPT::fileS()
{
  if (ifExe("apt-file") || !hostName.isEmpty()) {
    if (kprun->run(env + "apt-file update", "APT file update")) {
      kprun->exec();
   } 
  } else {
    KpMsg("Error",i18n("The %1 program needs to be installed").arg("apt-file"), TRUE);
  }
}

void DEBAPT::listPackages(TQPtrList<packageInfo> *pki)
{
  if (hostName.isEmpty()) {
    listInstalledPackages(pki);
  } else {
    listRemotePackages(pki);
  }
  listAvail(pki);
  if (hostName.isEmpty() && packageLoc) {
    listUnIPackages(pki, packageLoc);
  }
}

void DEBAPT::listRemotePackages(TQPtrList<packageInfo> *pki)
{
  listRPack(pki);
}

void DEBAPT::listRPack(TQPtrList<packageInfo> *pki)
{
  int NLINES =  70000;

  packageInfo *p;
  TQStringList  plist;

  kpackage->setStatus(i18n("Querying DEB APT remote package list: %1").arg(hostName));
  kpackage->setPercent(0);

  TQString cmd = "cat " STATUS;

  TQStringList list = kpty->run(cmd);
  kpackage->setStatus(i18n("Processing DEB APT remote package list: %1").arg(hostName));
  //  kdDebug() << "P=" << list.count() <<"\n";
  kpackage->setPercent(50);


  if (list.count() > 0) {

    TQString s;

    kpackage->setPercent(50 );

    int cnt = 0;
    for ( TQStringList::Iterator it = list.begin();  it != list.end(); ++it ) {
      cnt++;
      if (cnt % (NLINES/20) == 0) {
	kpackage->setPercent(((cnt * 100)/ NLINES ) + 50);
	//	kdDebug() << cnt << "_" << ((cnt * 100) / NLINES) <<"\n";
      }

      if (!(*it).isEmpty()) {
	s = *it;
	//	kdDebug() << s.length() << "<" << s << ">\n";
	plist << s;
      } else {
	//	kdDebug() << "---------\n";
	p = collectInfo(plist);
	if (p) {
	  if (!p->pkgInsert(pki, typeID, TRUE)) {
	    delete p;
	  }
	}
	plist.clear();
      }
    }
  }

  list.clear();
  kpackage->setStatus(i18n("DEB APT"));
  kpackage->setPercent(100);
}

void DEBAPT::listAvail(TQPtrList<packageInfo> *pki)
{
  int NLINES =  150000;

  packageInfo *p;
  TQStringList  plist;

  //  kdDebug() << "H=" << hostName << "\n";
  if (hostName.isEmpty())
    kpackage->setStatus(i18n("Querying DEB APT available list"));
  else
    kpackage->setStatus(i18n("Querying DEB APT available list: %1").arg(hostName));
  kpackage->setPercent(0);

  TQStringList list = kpty->run("apt-cache dumpavail");
  if (hostName.isEmpty())
    kpackage->setStatus(i18n("Processing DEB APT available list"));
  else
     kpackage->setStatus(i18n("Processing DEB APT available list: %1").arg(hostName));

  //  kdDebug() << "A=" << list.count() <<"\n";
  kpackage->setPercent(50);

  if (list.count() > 0) {

    TQString s;

    kpackage->setPercent(50 );

    int cnt = 0;
    for ( TQStringList::Iterator it = list.begin();  it != list.end(); ++it ) {
      cnt++;
      if (cnt % (NLINES/20) == 0) {
	kpackage->setPercent(((cnt * 100)/ NLINES ) + 50);
      }

      if (!(*it).isEmpty()) {
	s = *it;
	plist << s;
      } else {
	p = collectInfo(plist);
	if (p) {
	  if (!p->pkgInsert(pki, typeID, FALSE)) {
	    delete p;
	  }
	}
	plist.clear();
      }
    }
  }

  list.clear();
  kpackage->setStatus(i18n("DEB APT"));
  kpackage->setPercent(100);
}

TQStringList  DEBAPT::listInstalls(const TQStringList &packs, bool install, bool &cancel)
{
  bool extras=FALSE, found=FALSE;

  TQString match;
  TQString s = "apt-get -s ";
  if (install) {
    s += "install ";
    match = " extra packages ";
  } else {
    match = "packages will be REMOVED:";
    s += "remove ";
  }

  for ( TQStringList::ConstIterator it = packs.begin(); it != packs.end(); ++it ) {
    s +=  *it;
    s += " ";
  }

  TQStringList list = kpty->run(s, TRUE, TRUE);
  if (!kpty->inSession) {
    cancel = TRUE; // Root login did not work
  } else {
    cancel = FALSE;
  }
  //  kdDebug() << "LS=" << list.count()  << "\n";

  TQString packAll;
  for ( TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it ) {
    //        kdDebug() << "M=" << *it << "\n";
    if ((*it).find(match) >= 0 || extras) {
      if (extras) {
	if ((*it)[0] == ' ') {
	  packAll += *it;
	  found = true;
	} else {
	  break;
	}
      }
      extras=TRUE;
    }
  }

  if (!found) {
    TQStringList nill;
    return nill;
  } else {
    TQStringList plist = TQStringList::split(' ',packAll);
    return plist;
  }
}

//////////////////////////////////////////////////////////////////////////////
TQStringList DEBAPT::FindFile(const TQString &name, bool searchAll)
{
  if (searchAll) {
    if (ifExe("apt-file") || !hostName.isEmpty()) {
      TQString s = "apt-file search  ";
      s += name;

      TQStringList filelist = kpty->run(s);

      for ( TQStringList::Iterator it = filelist.begin(); it != filelist.end(); ++it ) {
       int p =  (*it).find(": ");
        if( p !=-1 )
          (*it).replace(p, 2, "\t");
      }

      if (filelist.count() == 1) {
       TQStringList::Iterator it = filelist.begin();
        if ((*it).find("not found") >= 0) {
	 filelist.remove(it);
        }
      }

      return filelist;
    } else {
      KpMsg("Error",i18n("The %1 program needs to be installed").arg("apt-file"), TRUE);
      TQStringList nill;
      return nill;
    }
  } else {
    return DEB::FindFile(name);
  }
}


TQStringList DEBAPT::getFileList(packageInfo *p)
{
  TQString fn( p->getFilename());
  if(!fn.isEmpty())
    return getUFileList(fn);
  else {
    if (hostName.isEmpty())
      return getIFileList(p);
    else {
      if (p->packageState == packageInfo::INSTALLED) {
	return getRFileList(p);
      } else
	return "";
    }
  }
}

 TQStringList DEBAPT::getRFileList(packageInfo *p)
{
  TQString from;
  TQString name = p->getProperty("name");

  from = "cat " INFODIR;
  from += name;
  from += ".list";

  return kpty->run(from);
}

//////////////////////////////////////////////////////////////////////////////
TQString DEBAPT::doUninstall(int uninstallFlags, const TQString &packs, bool &test)
{
  TQString s = env + "apt-get remove ";
  s += setOptions(uninstallFlags, paramsUninst);
  s +=  packs;

  kdDebug() << "uCMD=" << s << "\n";

  if (uninstallFlags>>2 & 1)
    test = TRUE;

  return s;
}

//////////////////////////////////////////////////////////////////////////////
TQString DEBAPT::install(int installFlags, TQPtrList<packageInfo> *p,
			      bool &test)
{
  TQString packs = "";
  TQString files = "";
  packageInfo *i;

  for (i = p->first(); i!= 0; i = p->next())  {
    TQString file = i->getFilename();
    TQString fname = i->fetchFilename();

    if (!file.isEmpty()) {
      files += TDEProcess::quote(file);
      files += " ";
    } else if (!fname.isEmpty()) {
      packs += TDEProcess::quote(fname);
      packs += " ";
    }
  }

  if (!files.isEmpty()) { // What if mixed?
    return DEB::doInstall(installFlags, files, test);
  } else {
    return doInstall(installFlags, packs, test);
  }
}

TQString DEBAPT::doInstall(int installFlags, const TQString &packs, bool &test)
{
  TQString s = env + "apt-get install ";
  s += setOptions(installFlags, paramsInst);
  s +=  packs;

  kdDebug() << "iCMD=" << s << "\n";

  if ((installFlags>>0 & 1) || (installFlags>>5 & 1))
    test = TRUE;

  return s;
}


//////////////////////////////////////////////////////////////////////////////

TQStringList DEBAPT::readApt()
{
  if (hostName.isEmpty()) {
    return readAptF();
  } else {
    return readAptS();
  }
}

TQStringList DEBAPT::readAptS()
{
  TQString cmd = "cat -E "  APT_SOURCE;

  TQStringList list = kpty->run(cmd);
  if (!kpty->Result) {
    TQString s;
    for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
      (*it).truncate((*it).length() - 1);
      (*it) = (*it).stripWhiteSpace();
    }
    return list;
  } else {
    return 0;
  }
}

TQStringList DEBAPT::readAptF()
{
  TQStringList lines;
  TQFile file( "/etc/apt/sources.list" );
  if ( file.open( IO_ReadOnly ) ) {
    TQTextStream stream( &file );
    TQString line;
    while ( !stream.atEnd() ) {
      line = stream.readLine(); // line of text excluding '\n'
      line = line.stripWhiteSpace();
      lines += line;
    }
    file.close();
    return lines;
  } else {
    return 0;
  }
}

void DEBAPT::writeApt(const TQStringList &list) {
  kdDebug() << "writeApt\n";
  TQString cmd = "sh -c \"/bin/echo -e '";
  for ( TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it ) {
    TQString s = *it;
    s.replace("\""," ");
    s.replace("'"," ");
    s.replace("!"," ");
    s.replace("`"," ");
    cmd += s;
    cmd += "\n";
  }
  cmd += "' > /etc/apt/sources.list.n; if [ $? = 0 ]; then ";
  cmd += "mv /etc/apt/sources.list /etc/apt/sources.list.b; mv /etc/apt/sources.list.n /etc/apt/sources.list; fi\" ";
  

 TQStringList rlist =  kpty->run(cmd,TRUE,TRUE);
  //for ( TQStringList::Iterator it = rlist.begin(); it != rlist.end(); ++it ) {
  // kdDebug() << "SL=" << *it << "\n";
  //}
}
  

#include "debAptInterface.moc"
