// -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: algorithms.cc,v 1.19 1999/06/28 03:11:24 jgg Exp $
+// $Id: algorithms.cc,v 1.44 2002/11/28 18:49:16 jgg Exp $
 /* ######################################################################
 
    Algorithms - A set of misc algorithms
 #include <apt-pkg/algorithms.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
-#include <iostream.h>
+#include <apt-pkg/pkgsystem.h>
+#include <apt-pkg/version.h>
+#include <apt-pkg/sptr.h>
+
+    
+#include <apti18n.h>
+#include <sys/types.h>
+#include <regex.h>
+#include <iostream>
                                                                        /*}}}*/
+using namespace std;
 
 pkgProblemResolver *pkgProblemResolver::This = 0;
 
 // Simulate::Simulate - Constructor                                    /*{{{*/
 // ---------------------------------------------------------------------
-/* */
-pkgSimulate::pkgSimulate(pkgDepCache &Cache) : pkgPackageManager(Cache), 
-                            Sim(Cache.GetMap())
+/* The legacy translations here of input Pkg iterators is obsolete, 
+   this is not necessary since the pkgCaches are fully shared now. */
+pkgSimulate::pkgSimulate(pkgDepCache *Cache) : pkgPackageManager(Cache),
+                           iPolicy(Cache),
+                            Sim(&Cache->GetCache(),&iPolicy)
+{
+   Sim.Init(0);
+   Flags = new unsigned char[Cache->Head().PackageCount];
+   memset(Flags,0,sizeof(*Flags)*Cache->Head().PackageCount);
+
+   // Fake a filename so as not to activate the media swapping
+   string Jnk = "SIMULATE";
+   for (unsigned int I = 0; I != Cache->Head().PackageCount; I++)
+      FileNames[I] = Jnk;
+}
+                                                                       /*}}}*/
+// Simulate::Describe - Describe a package                             /*{{{*/
+// ---------------------------------------------------------------------
+/* Parameter Current == true displays the current package version,
+   Parameter Candidate == true displays the candidate package version */
+void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Current,bool Candidate)
 {
-   Flags = new unsigned char[Cache.HeaderP->PackageCount];
-   memset(Flags,0,sizeof(*Flags)*Cache.HeaderP->PackageCount);
+   VerIterator Ver(Sim);
+ 
+   out << Pkg.Name();
+
+   if (Current == true)
+   {
+      Ver = Pkg.CurrentVer();
+      if (Ver.end() == false)
+         out << " [" << Ver.VerStr() << ']';
+   }
+
+   if (Candidate == true)
+   {
+      Ver = Sim[Pkg].CandidateVerIter(Sim);
+      if (Ver.end() == true)
+         return;
+   
+      out << " (" << Ver.VerStr() << ' ' << Ver.RelStr() << ')';
+   }
 }
                                                                        /*}}}*/
 // Simulate::Install - Simulate unpacking of a package                 /*{{{*/
    PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
    Flags[Pkg->ID] = 1;
    
-   cout << "Inst " << Pkg.Name();
+   cout << "Inst ";
+   Describe(Pkg,cout,true,true);
    Sim.MarkInstall(Pkg,false);
    
    // Look for broken conflicts+predepends.
       if (Sim[I].InstallVer == 0)
         continue;
       
-      for (DepIterator D = Sim[I].InstVerIter(Sim).DependsList(); D.end() == false; D++)
-        if (D->Type == pkgCache::Dep::Conflicts || D->Type == pkgCache::Dep::PreDepends)
+      for (DepIterator D = Sim[I].InstVerIter(Sim).DependsList(); D.end() == false;)
+      {
+        DepIterator Start;
+        DepIterator End;
+        D.GlobOr(Start,End);
+        if (Start->Type == pkgCache::Dep::Conflicts ||
+            Start->Type == pkgCache::Dep::Obsoletes ||
+            End->Type == pkgCache::Dep::PreDepends)
          {
-           if ((Sim[D] & pkgDepCache::DepInstall) == 0)
+           if ((Sim[End] & pkgDepCache::DepGInstall) == 0)
            {
-              cout << " [" << I.Name() << " on " << D.TargetPkg().Name() << ']';
-              if (D->Type == pkgCache::Dep::Conflicts)
+              cout << " [" << I.Name() << " on " << Start.TargetPkg().Name() << ']';
+              if (Start->Type == pkgCache::Dep::Conflicts)
                  _error->Error("Fatal, conflicts violated %s",I.Name());
            }       
-        }      
+        }
+      }      
    }
 
    if (Sim.BrokenCount() != 0)
             (Sim[D] & pkgDepCache::DepInstall) != 0)
            continue;
         
-        if (D->Type == pkgCache::Dep::Conflicts)
+        if (D->Type == pkgCache::Dep::Obsoletes)
+           cout << " Obsoletes:" << D.TargetPkg().Name();
+        else if (D->Type == pkgCache::Dep::Conflicts)
            cout << " Conflicts:" << D.TargetPkg().Name();
         else
            cout << " Depends:" << D.TargetPkg().Name();
       _error->Error("Conf Broken %s",Pkg.Name());
    }   
    else
-      cout << "Conf " <<  Pkg.Name();
+   {
+      cout << "Conf "; 
+      Describe(Pkg,cout,false,true);
+   }
 
    if (Sim.BrokenCount() != 0)
       ShortBreaks();
 // Simulate::Remove - Simulate the removal of a package                        /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool pkgSimulate::Remove(PkgIterator iPkg)
+bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge)
 {
    // Adapt the iterator
    PkgIterator Pkg = Sim.FindPkg(iPkg.Name());
 
    Flags[Pkg->ID] = 3;
    Sim.MarkDelete(Pkg);
-   cout << "Remv " << Pkg.Name();
+   if (Purge == true)
+      cout << "Purg ";
+   else
+      cout << "Remv ";
+   Describe(Pkg,cout,true,false);
 
    if (Sim.BrokenCount() != 0)
       ShortBreaks();
 {
    for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
    {
+      if (I->VersionList == 0)
+        continue;
+        
       // Only choice for a ReInstReq package is to reinstall
       if (I->InstState == pkgCache::State::ReInstReq ||
          I->InstState == pkgCache::State::HoldReInstReq)
       {
-        if (I.CurrentVer().Downloadable() == true)
+        if (I->CurrentVer != 0 && I.CurrentVer().Downloadable() == true)
            Cache.MarkKeep(I);
         else
         {
            // Is this right? Will dpkg choke on an upgrade?
-           if (Cache[I].CandidateVerIter(Cache).Downloadable() == true)
+           if (Cache[I].CandidateVer != 0 &&
+                Cache[I].CandidateVerIter(Cache).Downloadable() == true)
               Cache.MarkInstall(I);
            else
-              return _error->Error("The package %s needs to be reinstalled, "
-                                   "but I can't find an archive for it.",I.Name());
+              return _error->Error(_("The package %s needs to be reinstalled, "
+                                   "but I can't find an archive for it."),I.Name());
         }
         
         continue;
            re-unpacked (probably) */
         case pkgCache::State::UnPacked:
         case pkgCache::State::HalfConfigured:
-        if (I.CurrentVer().Downloadable() == true || 
+        if ((I->CurrentVer != 0 && I.CurrentVer().Downloadable() == true) ||
             I.State() != pkgCache::PkgIterator::NeedsUnpack)
            Cache.MarkKeep(I);
         else
         {
-           if (Cache[I].CandidateVerIter(Cache).Downloadable() == true)
+           if (Cache[I].CandidateVer != 0 &&
+                Cache[I].CandidateVerIter(Cache).Downloadable() == true)
               Cache.MarkInstall(I);
            else
               Cache.MarkDelete(I);
       Cache.MarkInstall(I,true);      
    }
    
-   pkgProblemResolver Fix(Cache);
+   pkgProblemResolver Fix(&Cache);
    return Fix.Resolve(true);
 }
                                                                        /*}}}*/
       if (I->CurrentVer != 0)
         Cache.MarkInstall(I,false);
 
-   pkgProblemResolver Fix(Cache);
+   pkgProblemResolver Fix(&Cache);
 
    // Hold back held packages.
-   if (_config->FindB("APT::Ingore-Hold",false) == false)
+   if (_config->FindB("APT::Ignore-Hold",false) == false)
    {
       for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
       {
    to install packages not marked for install */
 bool pkgAllUpgrade(pkgDepCache &Cache)
 {
-   pkgProblemResolver Fix(Cache);
+   pkgProblemResolver Fix(&Cache);
 
    if (Cache.BrokenCount() != 0)
       return false;
       if (Cache[I].Install() == true)
         Fix.Protect(I);
          
-      if (_config->FindB("APT::Ingore-Hold",false) == false)
+      if (_config->FindB("APT::Ignore-Hold",false) == false)
         if (I->SelectedState == pkgCache::State::Hold)
            continue;
       
    if (Cache.BrokenCount() != 0)
       return false;
    
-   // We loop indefinately to get the minimal set size.
+   // We loop for 10 tries to get the minimal set size.
    bool Change = false;
+   unsigned int Count = 0;
    do
    {
       Change = false;
         // Not interesting
         if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
            continue;
-        
+
         // Keep it and see if that is OK
         Cache.MarkKeep(I);
         if (Cache.BrokenCount() != 0)
            Cache.MarkInstall(I,false);
         else
-           Change = true;
+        {
+           // If keep didnt actually do anything then there was no change..
+           if (Cache[I].Upgrade() == false)
+              Change = true;
+        }       
       }      
+      Count++;
    }
-   while (Change == true);
+   while (Change == true && Count < 10);
 
    if (Cache.BrokenCount() != 0)
       return _error->Error("Internal Error in pkgMinimizeUpgrade");
 // ProblemResolver::pkgProblemResolver - Constructor                   /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-pkgProblemResolver::pkgProblemResolver(pkgDepCache &Cache) : Cache(Cache)
+pkgProblemResolver::pkgProblemResolver(pkgDepCache *pCache) : Cache(*pCache)
 {
    // Allocate memory
-   unsigned long Size = Cache.HeaderP->PackageCount;
+   unsigned long Size = Cache.Head().PackageCount;
    Scores = new signed short[Size];
    Flags = new unsigned char[Size];
    memset(Flags,0,sizeof(*Flags)*Size);
    Debug = _config->FindB("Debug::pkgProblemResolver",false);
 }
                                                                        /*}}}*/
+// ProblemResolver::~pkgProblemResolver - Destructor                   /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgProblemResolver::~pkgProblemResolver()
+{
+   delete [] Scores;
+   delete [] Flags;
+}
+                                                                       /*}}}*/
 // ProblemResolver::ScoreSort - Sort the list by score                 /*{{{*/
 // ---------------------------------------------------------------------
 /* */
 /* */
 void pkgProblemResolver::MakeScores()
 {
-   unsigned long Size = Cache.HeaderP->PackageCount;
+   unsigned long Size = Cache.Head().PackageCount;
    memset(Scores,0,sizeof(*Scores)*Size);
 
    // Generate the base scores for a package based on its properties
    }   
    
    // Copy the scores to advoid additive looping
-   signed short *OldScores = new signed short[Size];
+   SPtrArray<signed short> OldScores = new signed short[Size];
    memcpy(OldScores,Scores,sizeof(*Scores)*Size);
       
    /* Now we cause 1 level of dependency inheritance, that is we add the 
         Scores[I->ID] += 10000;
       if ((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
         Scores[I->ID] += 5000;
-   }
-   
-   delete [] OldScores;
+   }   
 }
                                                                        /*}}}*/
 // ProblemResolver::DoUpgrade - Attempt to upgrade this package                /*{{{*/
 {
    if ((Flags[Pkg->ID] & Upgradable) == 0 || Cache[Pkg].Upgradable() == false)
       return false;
+   if ((Flags[Pkg->ID] & Protected) == Protected)
+      return false;
    
    Flags[Pkg->ID] &= ~Upgradable;
    
       pkgCache::DepIterator Start = D;
       pkgCache::DepIterator End = D;
       unsigned char State = 0;
-      for (bool LastOR = true; D.end() == false && LastOR == true; D++)
+      for (bool LastOR = true; D.end() == false && LastOR == true;)
       {
         State |= Cache[D];
         LastOR = (D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
+        D++;
         if (LastOR == true)
            End = D;
       }
       // We only worry about critical deps.
       if (End.IsCritical() != true)
         continue;
-      
-      // Dep is ok
-      if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
-        continue;
-      
-      // Hm, the group is broken.. I have no idea how to handle this
-      if (Start != End)
-      {
-        clog << "Note, a broken or group was found in " << Pkg.Name() << "." << endl;
-        Fail = true;
-        break;
-      }
-
-      // Do not change protected packages
-      PkgIterator P = Start.SmartTargetPkg();
-      if ((Flags[P->ID] & Protected) == Protected)
+            
+      // Iterate over all the members in the or group
+      while (1)
       {
-        if (Debug == true)
-           clog << "    Reinet Failed because of protected " << P.Name() << endl;
-        Fail = true;
-        break;
-      }      
-      
-      // Upgrade the package if the candidate version will fix the problem.
-      if ((Cache[Start] & pkgDepCache::DepCVer) == pkgDepCache::DepCVer)
-      {
-        if (DoUpgrade(P) == false)
+        // Dep is ok now
+        if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
+           break;
+        
+        // Do not change protected packages
+        PkgIterator P = Start.SmartTargetPkg();
+        if ((Flags[P->ID] & Protected) == Protected)
         {
            if (Debug == true)
-              clog << "    Reinst Failed because of " << P.Name() << endl;
+              clog << "    Reinst Failed because of protected " << P.Name() << endl;
            Fail = true;
+        }      
+        else
+        {
+           // Upgrade the package if the candidate version will fix the problem.
+           if ((Cache[Start] & pkgDepCache::DepCVer) == pkgDepCache::DepCVer)
+           {
+              if (DoUpgrade(P) == false)
+              {
+                 if (Debug == true)
+                    clog << "    Reinst Failed because of " << P.Name() << endl;
+                 Fail = true;
+              }
+              else
+              {
+                 Fail = false;
+                 break;
+              }            
+           }
+           else
+           {
+              /* We let the algorithm deal with conflicts on its next iteration,
+               it is much smarter than us */
+              if (Start->Type == pkgCache::Dep::Conflicts || 
+                  Start->Type == pkgCache::Dep::Obsoletes)
+                  break;
+              
+              if (Debug == true)
+                 clog << "    Reinst Failed early because of " << Start.TargetPkg().Name() << endl;
+              Fail = true;
+           }     
+        }
+        
+        if (Start == End)
            break;
-        }       
+        Start++;
       }
-      else
-      {
-        /* We let the algorithm deal with conflicts on its next iteration,
-           it is much smarter than us */
-        if (End->Type == pkgCache::Dep::Conflicts)
-           continue;
-        
-        if (Debug == true)
-           clog << "    Reinst Failed early because of " << Start.TargetPkg().Name() << endl;
-        Fail = true;
+      if (Fail == true)
         break;
-      }      
    }
    
    // Undo our operations - it might be smart to undo everything this did..
    upgrade packages to advoid problems. */
 bool pkgProblemResolver::Resolve(bool BrokenFix)
 {
-   unsigned long Size = Cache.HeaderP->PackageCount;
+   unsigned long Size = Cache.Head().PackageCount;
 
    // Record which packages are marked for install
    bool Again = false;
       operates from highest score to lowest. This prevents problems when
       high score packages cause the removal of lower score packages that
       would cause the removal of even lower score packages. */
-   pkgCache::Package **PList = new pkgCache::Package *[Size];
+   SPtrArray<pkgCache::Package *> PList = new pkgCache::Package *[Size];
    pkgCache::Package **PEnd = PList;
    for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
       *PEnd++ = I;
         if (Cache[I].InstallVer == 0 || Cache[I].InstBroken() == false)
            continue;
         
+        if (Debug == true)
+           cout << "Investigating " << I.Name() << endl;
+        
         // Isolate the problem dependency
         PackageKill KillList[100];
         PackageKill *LEnd = KillList;
-        for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false;)
+        bool InOr = false;
+        pkgCache::DepIterator Start;
+        pkgCache::DepIterator End;
+        PackageKill *OldEnd = LEnd;
+        
+        enum {OrRemove,OrKeep} OrOp = OrRemove;
+        for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList();
+             D.end() == false || InOr == true;)
         {
            // Compute a single dependency element (glob or)
-           pkgCache::DepIterator Start;
-           pkgCache::DepIterator End;
-           D.GlobOr(Start,End);
-           
-           // We only worry about critical deps.
-           if (End.IsCritical() != true)
-              continue;
-           
+           if (Start == End)
+           {
+              // Decide what to do
+              if (InOr == true)
+              {
+                 if (OldEnd == LEnd && OrOp == OrRemove)
+                 {
+                    if ((Flags[I->ID] & Protected) != Protected)
+                    {
+                       if (Debug == true)
+                          clog << "  Or group remove for " << I.Name() << endl;
+                       Cache.MarkDelete(I);
+                       Change = true;
+                    }               
+                 }               
+                 if (OldEnd == LEnd && OrOp == OrKeep)
+                 {
+                    if (Debug == true)
+                       clog << "  Or group keep for " << I.Name() << endl;
+                    Cache.MarkKeep(I);
+                    Change = true;
+                 }
+              }
+              
+              /* We do an extra loop (as above) to finalize the or group
+                 processing */
+              InOr = false;
+              OrOp = OrRemove;
+              D.GlobOr(Start,End);
+              if (Start.end() == true)
+                 break;
+
+              // We only worry about critical deps.
+              if (End.IsCritical() != true)
+                 continue;
+
+              InOr = Start != End;
+              OldEnd = LEnd;
+           }
+           else
+              Start++;
+
            // Dep is ok
            if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
-              continue;
-           
-           // Hm, the group is broken.. I have no idea how to handle this
-           if (Start != End)
            {
-              if (Debug == true)
-                 clog << "Note, a broken or group was found in " << I.Name() << "." << endl;
-              if ((Flags[I->ID] & Protected) != Protected)
-                 Cache.MarkDelete(I);
-              break;
+              InOr = false;
+              continue;
            }
-                   
+           
            if (Debug == true)
-              clog << "Package " << I.Name() << " has broken dep on " << End.TargetPkg().Name() << endl;
+              clog << "Package " << I.Name() << " has broken dep on " << Start.TargetPkg().Name() << endl;
 
            /* Look across the version list. If there are no possible
               targets then we keep the package and bail. This is necessary
               if a package has a dep on another package that cant be found */
-           pkgCache::Version **VList = End.AllTargets();
+           SPtrArray<pkgCache::Version *> VList = Start.AllTargets();
            if (*VList == 0 && (Flags[I->ID] & Protected) != Protected &&
-               End->Type != pkgCache::Dep::Conflicts && 
+               Start->Type != pkgCache::Dep::Conflicts &&
+               Start->Type != pkgCache::Dep::Obsoletes &&
                Cache[I].NowBroken() == false)
-           {
+           {          
+              if (InOr == true)
+              {
+                 /* No keep choice because the keep being OK could be the
+                    result of another element in the OR group! */
+                 continue;
+              }
+              
               Change = true;
-              Cache.MarkKeep(I);
+              Cache.MarkKeep(I);                 
               break;
            }
            
            {
               pkgCache::VerIterator Ver(Cache,*V);
               pkgCache::PkgIterator Pkg = Ver.ParentPkg();
-           
+
               if (Debug == true)
-                 clog << "  Considering " << Pkg.Name() << ' ' << (int)Scores[Pkg->ID] << 
+                 clog << "  Considering " << Pkg.Name() << ' ' << (int)Scores[Pkg->ID] <<
                  " as a solution to " << I.Name() << ' ' << (int)Scores[I->ID] << endl;
+
+              /* Try to fix the package under consideration rather than
+                 fiddle with the VList package */
               if (Scores[I->ID] <= Scores[Pkg->ID] ||
-                  ((Cache[End] & pkgDepCache::DepGNow) == 0 &&
-                   End->Type != pkgCache::Dep::Conflicts))
+                  ((Cache[Start] & pkgDepCache::DepNow) == 0 &&
+                   End->Type != pkgCache::Dep::Conflicts &&
+                   End->Type != pkgCache::Dep::Obsoletes))
               {
                  // Try a little harder to fix protected packages..
                  if ((Flags[I->ID] & Protected) == Protected)
                  {
                     if (DoUpgrade(Pkg) == true)
-                       Scores[Pkg->ID] = Scores[I->ID];
+                    {
+                       if (Scores[Pkg->ID] > Scores[I->ID])
+                          Scores[Pkg->ID] = Scores[I->ID];
+                       break;
+                    }
+                    
                     continue;
                  }
                  
                  /* See if a keep will do, unless the package is protected,
-                    then installing it will be necessary */    
+                    then installing it will be necessary */
+                 bool Installed = Cache[I].Install();
                  Cache.MarkKeep(I);
                  if (Cache[I].InstBroken() == false)
                  {
+                    // Unwind operation will be keep now
+                    if (OrOp == OrRemove)
+                       OrOp = OrKeep;
+                    
+                    // Restore
+                    if (InOr == true && Installed == true)
+                       Cache.MarkInstall(I,false);
+                    
                     if (Debug == true)
-                       clog << "  Holding Back " << I.Name() << " rather than change " << End.TargetPkg().Name() << endl;
+                       clog << "  Holding Back " << I.Name() << " rather than change " << Start.TargetPkg().Name() << endl;
                  }               
                  else
-                 {
+                 {                  
                     if (BrokenFix == false || DoUpgrade(I) == false)
                     {
-                       if (Debug == true)
-                          clog << "  Removing " << I.Name() << " rather than change " << End.TargetPkg().Name() << endl;
-                       Cache.MarkDelete(I);
-                       if (Counter > 1)
-                          Scores[I->ID] = Scores[Pkg->ID];
+                       // Consider other options
+                       if (InOr == false)
+                       {
+                          if (Debug == true)
+                             clog << "  Removing " << I.Name() << " rather than change " << Start.TargetPkg().Name() << endl;
+                          Cache.MarkDelete(I);
+                          if (Counter > 1)
+                          {
+                             if (Scores[Pkg->ID] > Scores[I->ID])
+                                Scores[I->ID] = Scores[Pkg->ID];
+                          }                       
+                       }                       
                     }
                  }
                                  
               }
               else
               {
-                 // Skip this if it is protected
+                 /* This is a conflicts, and the version we are looking
+                    at is not the currently selected version of the 
+                    package, which means it is not necessary to 
+                    remove/keep */
+                 if (Cache[Pkg].InstallVer != Ver &&
+                     (Start->Type == pkgCache::Dep::Conflicts ||
+                      Start->Type == pkgCache::Dep::Obsoletes))
+                    continue;
+                 
+                 // Skip adding to the kill list if it is protected
                  if ((Flags[Pkg->ID] & Protected) != 0)
                     continue;
+               
+                 if (Debug == true)
+                    clog << "  Added " << Pkg.Name() << " to the remove list" << endl;
                  
                  LEnd->Pkg = Pkg;
                  LEnd->Dep = End;
                  LEnd++;
                  
-                 if (End->Type != pkgCache::Dep::Conflicts)
+                 if (Start->Type != pkgCache::Dep::Conflicts &&
+                     Start->Type != pkgCache::Dep::Obsoletes)
                     break;
               }
            }
 
            // Hm, nothing can possibly satisify this dep. Nuke it.
-           if (VList[0] == 0 && End->Type != pkgCache::Dep::Conflicts &&
+           if (VList[0] == 0 && 
+               Start->Type != pkgCache::Dep::Conflicts &&
+               Start->Type != pkgCache::Dep::Obsoletes &&
                (Flags[I->ID] & Protected) != Protected)
            {
+              bool Installed = Cache[I].Install();
               Cache.MarkKeep(I);
               if (Cache[I].InstBroken() == false)
               {
+                 // Unwind operation will be keep now
+                 if (OrOp == OrRemove)
+                    OrOp = OrKeep;
+                 
+                 // Restore
+                 if (InOr == true && Installed == true)
+                    Cache.MarkInstall(I,false);
+                 
                  if (Debug == true)
-                    clog << "  Holding Back " << I.Name() << " because I can't find " << End.TargetPkg().Name() << endl;
+                    clog << "  Holding Back " << I.Name() << " because I can't find " << Start.TargetPkg().Name() << endl;
               }               
               else
               {
                  if (Debug == true)
-                    clog << "  Removing " << I.Name() << " because I can't find " << End.TargetPkg().Name() << endl;
-                 Cache.MarkDelete(I);
+                    clog << "  Removing " << I.Name() << " because I can't find " << Start.TargetPkg().Name() << endl;
+                 if (InOr == false)
+                    Cache.MarkDelete(I);
               }
 
               Change = true;
               Done = true;
            }
            
-           delete [] VList;
+           // Try some more
+           if (InOr == true)
+              continue;
+           
            if (Done == true)
               break;
         }
         
         // Apply the kill list now
         if (Cache[I].InstallVer != 0)
+        {
            for (PackageKill *J = KillList; J != LEnd; J++)
-         {
-           Change = true;
-           if ((Cache[J->Dep] & pkgDepCache::DepGNow) == 0)
            {
-              if (J->Dep->Type == pkgCache::Dep::Conflicts)
+              Change = true;
+              if ((Cache[J->Dep] & pkgDepCache::DepGNow) == 0)
+              {
+                 if (J->Dep->Type == pkgCache::Dep::Conflicts || 
+                     J->Dep->Type == pkgCache::Dep::Obsoletes)
+                 {
+                    if (Debug == true)
+                       clog << "  Fixing " << I.Name() << " via remove of " << J->Pkg.Name() << endl;
+                    Cache.MarkDelete(J->Pkg);
+                 }
+              }
+              else
               {
                  if (Debug == true)
-                    clog << "  Fixing " << I.Name() << " via remove of " << J->Pkg.Name() << endl;
-                 Cache.MarkDelete(J->Pkg);
+                    clog << "  Fixing " << I.Name() << " via keep of " << J->Pkg.Name() << endl;
+                 Cache.MarkKeep(J->Pkg);
               }
-           }
-           else
-           {
-              if (Debug == true)
-                 clog << "  Fixing " << I.Name() << " via keep of " << J->Pkg.Name() << endl;
-              Cache.MarkKeep(J->Pkg);
-           }
-           
-           if (Counter > 1)
-              Scores[J->Pkg->ID] = Scores[I->ID];
-        }      
-      }
+
+              if (Counter > 1)
+              {
+                 if (Scores[I->ID] > Scores[J->Pkg->ID])                 
+                    Scores[J->Pkg->ID] = Scores[I->ID];
+              }               
+           }      
+        }
+      }      
    }
 
    if (Debug == true)
       clog << "Done" << endl;
-   
-   delete [] Scores;
-   delete [] PList;
-   
+      
    if (Cache.BrokenCount() != 0)
    {
       // See if this is the result of a hold
         if (Cache[I].InstBroken() == false)
            continue;
         if ((Flags[I->ID] & Protected) != Protected)
-           return _error->Error("Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages.");
+           return _error->Error(_("Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages."));
       }
-      return _error->Error("Unable to correct problems, you have held broken packages.");
+      return _error->Error(_("Unable to correct problems, you have held broken packages."));
    }
    
+   // set the auto-flags (mvo: I'm not sure if we _really_ need this, but
+   // I didn't managed 
+   pkgCache::PkgIterator I = Cache.PkgBegin();
+   for (;I.end() != true; I++) {
+      if (Cache[I].NewInstall() && !(Flags[I->ID] & PreInstalled)) {
+        if(_config->FindI("Debug::pkgAutoRemove",false)) {
+           std::clog << "Resolve installed new pkg: " << I.Name() 
+                     << " (now marking it as auto)" << std::endl;
+        }
+        Cache[I].Flags |= pkgCache::Flag::Auto;
+      }
+   }
+
+
    return true;
 }
                                                                        /*}}}*/
    system was non-broken previously. */
 bool pkgProblemResolver::ResolveByKeep()
 {
-   unsigned long Size = Cache.HeaderP->PackageCount;
+   unsigned long Size = Cache.Head().PackageCount;
 
    if (Debug == true)      
       clog << "Entering ResolveByKeep" << endl;
         continue;
 
       /* Keep the package. If this works then great, otherwise we have
-                to be significantly more agressive and manipulate its dependencies */      
+                to be significantly more agressive and manipulate its dependencies */
       if ((Flags[I->ID] & Protected) == 0)
       {
         if (Debug == true)
         Cache.MarkKeep(I);
         if (Cache[I].InstBroken() == false)
         {
-           K = PList;
+           K = PList - 1;
            continue;
         }
       }
       // Isolate the problem dependencies
       for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false;)
       {
-        // Compute a single dependency element (glob or)
-        pkgCache::DepIterator Start = D;
-        pkgCache::DepIterator End = D;
-        unsigned char State = 0;
-        for (bool LastOR = true; D.end() == false && LastOR == true; D++)
-        {
-           State |= Cache[D];
-           LastOR = (D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
-           if (LastOR == true)
-              End = D;
-        }
-        
+        DepIterator Start;
+        DepIterator End;
+        D.GlobOr(Start,End);
+
         // We only worry about critical deps.
         if (End.IsCritical() != true)
            continue;
         // Dep is ok
         if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
            continue;
-        
-        // Hm, the group is broken.. I have no idea how to handle this
-        if (Start != End)
-        {
-           clog << "Note, a broken or group was found in " << I.Name() << "." << endl;
-           if ((Flags[I->ID] & Protected) == 0)
-              Cache.MarkKeep(I);
-           break;
-        }
-        
-        if (Debug == true)
-           clog << "Package " << I.Name() << " has broken dep on " << End.TargetPkg().Name() << endl;
-        
-        // Look at all the possible provides on this package
-        pkgCache::Version **VList = End.AllTargets();
-        for (pkgCache::Version **V = VList; *V != 0; V++)
+
+        /* Hm, the group is broken.. I suppose the best thing to do is to
+           is to try every combination of keep/not-keep for the set, but thats
+           slow, and this never happens, just be conservative and assume the
+           list of ors is in preference and keep till it starts to work. */
+        while (true)
         {
-           pkgCache::VerIterator Ver(Cache,*V);
-           pkgCache::PkgIterator Pkg = Ver.ParentPkg();
-           
-           // It is not keepable
-           if (Cache[Pkg].InstallVer == 0 || 
-               Pkg->CurrentVer == 0)
-              continue;
+           if (Debug == true)
+              clog << "Package " << I.Name() << " has broken dep on " << Start.TargetPkg().Name() << endl;
            
-           if ((Flags[I->ID] & Protected) == 0)
+           // Look at all the possible provides on this package
+           SPtrArray<pkgCache::Version *> VList = Start.AllTargets();
+           for (pkgCache::Version **V = VList; *V != 0; V++)
            {
-              if (Debug == true)
-                 clog << "  Keeping Package " << Pkg.Name() << " due to dep" << endl;
-              Cache.MarkKeep(Pkg);
+              pkgCache::VerIterator Ver(Cache,*V);
+              pkgCache::PkgIterator Pkg = Ver.ParentPkg();
+              
+              // It is not keepable
+              if (Cache[Pkg].InstallVer == 0 ||
+                  Pkg->CurrentVer == 0)
+                 continue;
+              
+              if ((Flags[I->ID] & Protected) == 0)
+              {
+                 if (Debug == true)
+                    clog << "  Keeping Package " << Pkg.Name() << " due to dep" << endl;
+                 Cache.MarkKeep(Pkg);
+              }
+              
+              if (Cache[I].InstBroken() == false)
+                 break;
            }
            
            if (Cache[I].InstBroken() == false)
               break;
-        }
 
+           if (Start == End)
+              break;
+           Start++;
+        }
+             
         if (Cache[I].InstBroken() == false)
            break;
       }
       if (K == LastStop)
         return _error->Error("Internal Error, pkgProblemResolver::ResolveByKeep is looping on package %s.",I.Name());
       LastStop = K;
-      K = PList;
+      K = PList - 1;
    }   
 
    return true;
    }   
 }
                                                                        /*}}}*/
+
+// PrioSortList - Sort a list of versions by priority                  /*{{{*/
+// ---------------------------------------------------------------------
+/* This is ment to be used in conjunction with AllTargets to get a list 
+   of versions ordered by preference. */
+static pkgCache *PrioCache;
+static int PrioComp(const void *A,const void *B)
+{
+   pkgCache::VerIterator L(*PrioCache,*(pkgCache::Version **)A);
+   pkgCache::VerIterator R(*PrioCache,*(pkgCache::Version **)B);
+   
+   if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential &&
+       (R.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential)
+     return 1;
+   if ((L.ParentPkg()->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential &&
+       (R.ParentPkg()->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
+     return -1;
+   
+   if (L->Priority != R->Priority)
+      return R->Priority - L->Priority;
+   return strcmp(L.ParentPkg().Name(),R.ParentPkg().Name());
+}
+void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List)
+{
+   unsigned long Count = 0;
+   PrioCache = &Cache;
+   for (pkgCache::Version **I = List; *I != 0; I++)
+      Count++;
+   qsort(List,Count,sizeof(*List),PrioComp);
+}
+                                                                       /*}}}*/
+
+
+// mark a single package in Mark-and-Sweep
+void pkgMarkPackage(pkgDepCache &Cache,
+                   const pkgCache::PkgIterator &pkg,
+                   const pkgCache::VerIterator &ver,
+                   bool follow_recommends,
+                   bool follow_suggests)
+{
+   pkgDepCache::StateCache &state=Cache[pkg];
+   pkgCache::VerIterator candver=state.CandidateVerIter(Cache);
+   pkgCache::VerIterator instver=state.InstVerIter(Cache);
+
+#if 0
+   // If a package was garbage-collected but is now being marked, we
+   // should re-select it 
+   // For cases when a pkg is set to upgrade and this trigger the
+   // removal of a no-longer used dependency.  if the pkg is set to
+   // keep again later it will result in broken deps
+   if(state.Delete() && state.RemoveReason=pkgDepCache::Unused) 
+   {
+      if(ver==candver)
+        mark_install(pkg, false, false, NULL);
+      else if(ver==pkg.CurrentVer())
+        MarkKeep(pkg);
+      
+      instver=state.InstVerIter(*this);
+   }
+#endif
+
+   // Ignore versions other than the InstVer, and ignore packages
+   // that are already going to be removed or just left uninstalled.
+   if(!(ver==instver && !instver.end()))
+      return;
+
+   // if we are marked already we are done
+   if(state.Marked)
+      return;
+
+   //std::cout << "Setting Marked for: " << pkg.Name() << std::endl;
+   state.Marked=true;
+
+   if(!ver.end())
+   {
+     for(pkgCache::DepIterator d=ver.DependsList(); !d.end(); ++d)
+     {
+       if(d->Type==pkgCache::Dep::Depends ||
+          d->Type==pkgCache::Dep::PreDepends ||
+          (follow_recommends &&
+           d->Type==pkgCache::Dep::Recommends) ||
+          (follow_suggests &&
+           d->Type==pkgCache::Dep::Suggests))
+        {
+          // Try all versions of this package.
+          for(pkgCache::VerIterator V=d.TargetPkg().VersionList(); 
+              !V.end(); ++V)
+          {
+             if(_system->VS->CheckDep(V.VerStr(),d->CompareOp, d.TargetVer()))
+             {
+                pkgMarkPackage(Cache, V.ParentPkg(), V, 
+                               follow_recommends, follow_suggests);
+             }
+          }
+          // Now try virtual packages
+          for(pkgCache::PrvIterator prv=d.TargetPkg().ProvidesList(); 
+              !prv.end(); ++prv)
+          {
+             if(_system->VS->CheckDep(prv.ProvideVersion(), d->CompareOp, 
+                                      d.TargetVer()))
+             {
+                pkgMarkPackage(Cache, prv.OwnerPkg(), prv.OwnerVer(),
+                               follow_recommends, follow_suggests);
+             }
+          }
+       }
+     }
+   }
+}
+
+
+// Helper for APT::NeverAutoRemove, always include the packages matching
+// this regexp into the root-set
+inline bool 
+pkgMarkAlwaysInclude(pkgCache::PkgIterator p, vector<regex_t*> alwaysMark)
+{
+   for(unsigned int i=0;i<alwaysMark.size();i++)
+      if (regexec(alwaysMark[i],p.Name(),0,0,0) == 0)
+        return true;
+
+   return false;
+}
+
+// the main mark algorithm
+bool pkgMarkUsed(pkgDepCache &Cache, InRootSetFunc func)
+{
+   bool follow_recommends;
+   bool follow_suggests;
+
+   // init the states
+   for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p)
+   {
+      Cache[p].Marked=false;
+      Cache[p].Garbage=false;
+
+      // debug output
+      if(_config->FindB("Debug::pkgAutoRemove",false) 
+        && Cache[p].Flags & pkgCache::Flag::Auto)
+        std::clog << "AutoDep: " << p.Name() << std::endl;
+   }
+
+   // init vars
+   follow_recommends=_config->FindB("APT::AutoRemove::RecommendsImportant",false);
+   follow_suggests=_config->FindB("APT::AutoRemove::SuggestsImportant", false);
+
+
+   // init the "NeverAutoRemove" variable
+   vector<regex_t *> neverAutoRemoveRegexp;
+   Configuration::Item const *Opts;
+   Opts = _config->Tree("APT::NeverAutoRemove");
+   if (Opts != 0 && Opts->Child != 0)
+   {
+      Opts = Opts->Child;
+      for (; Opts != 0; Opts = Opts->Next)
+      {
+        if (Opts->Value.empty() == true)
+           continue;
+
+        regex_t *p = new regex_t;
+        if(regcomp(p,Opts->Value.c_str(),
+                   REG_EXTENDED | REG_ICASE |  REG_NOSUB) != 0)
+        {
+           regfree(p);
+           for(unsigned int i=0;i<neverAutoRemoveRegexp.size();i++)
+              regfree(neverAutoRemoveRegexp[i]);
+           return _error->Error("Regex compilation error for APT::NeverAutoRemove");
+        }
+        neverAutoRemoveRegexp.push_back(p);
+      }
+   }
+
+
+   // do the mark part, this is the core bit of the algorithm
+   for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p)
+   {
+      if( (func != NULL ? (*func)(p) : false) ||
+          pkgMarkAlwaysInclude(p, neverAutoRemoveRegexp) ||
+        !(Cache[p].Flags & pkgCache::Flag::Auto) ||
+         (p->Flags & pkgCache::Flag::Essential))
+          
+      {
+        // the package is installed (and set to keep)
+        if(Cache[p].Keep() && !p.CurrentVer().end())
+           pkgMarkPackage(Cache, p, p.CurrentVer(),
+                          follow_recommends, follow_suggests);
+        // the package is to be installed 
+        else if(Cache[p].Install())
+           pkgMarkPackage(Cache, p, Cache[p].InstVerIter(Cache),
+                          follow_recommends, follow_suggests);
+      }
+   }
+
+
+   // do the sweep
+   for(pkgCache::PkgIterator p=Cache.PkgBegin(); !p.end(); ++p)
+  {
+     pkgDepCache::StateCache &state=Cache[p];
+
+     // if it is not marked and it is installed, it's garbage 
+     if(!state.Marked && !p.CurrentVer().end())
+     {
+       state.Garbage=true;
+       if(_config->FindB("Debug::pkgAutoRemove",false))
+          std::cout << "Garbage: " << p.Name() << std::endl;
+     
+#if 0   // mvo: the below bits still needs to be ported
+
+       // Be sure not to re-delete already deleted packages.
+       if(delete_unused && (!p.CurrentVer().end() || state.Install()) &&
+          !state.Delete())
+       {
+             bool do_delete=true;
+
+             // If the package is being upgraded, check if we're
+             // losing a versioned dep.  If the dependency matches
+             // the previous version and not the new version, keep
+             // the package back instead of removing it.
+             if(!p.CurrentVer().end() && state.Install())
+               {
+                 const char *vs=p.CurrentVer().VerStr();
+
+                 // Check direct revdeps only.  THIS ASSUMES NO
+                 // VERSIONED PROVIDES, but Debian probably won't
+                 // have them for ages if ever.
+                 for(pkgCache::DepIterator revdep=p.RevDependsList();
+                     !revdep.end(); ++revdep)
+                   {
+                     pkgCache::PkgIterator depender=revdep.ParentPkg();
+                     // Find which version of the depending package
+                     // will be installed.
+                     pkgCache::VerIterator instver=(*this)[depender].InstVerIter(*this);
+
+                     // Only pay attention to strong positive
+                     // dependencies whose parents will be installed.
+                     if(revdep.ParentVer()==instver &&
+                        (revdep->Type==pkgCache::Dep::Depends ||
+                         revdep->Type==pkgCache::Dep::PreDepends ||
+                         (revdep->Type==pkgCache::Dep::Recommends &&
+                          follow_recommends)))
+                       {
+                         // If the previous version matched, cancel the
+                         // deletion.  (note that I assume that the new
+                         // version does NOT match; otherwise it would
+                         // not be unused!)
+                         if(_system->VS->CheckDep(vs,
+                                                  revdep->CompareOp,
+                                                  revdep.TargetVer()))
+                           {
+                             mark_keep(p, false, false, undo);
+                             do_delete=false;
+                             break;
+                           }
+                       }
+                   }
+               }
+
+             if(do_delete)
+               mark_delete(p, false, true, undo);
+           }
+#endif
+     }
+  }
+
+   // cleanup
+   for(unsigned int i=0;i<neverAutoRemoveRegexp.size();i++)
+      regfree(neverAutoRemoveRegexp[i]);
+   
+
+   return true;
+}