/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* Resolver.h
 *
 * Copyright (C) 2000-2002 Ximian, Inc.
 * Copyright (C) 2005 SUSE Linux Products GmbH
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * 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; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307, USA.
 */

#ifndef ZYPP_SOLVER_DETAIL_RESOLVER_H
#define ZYPP_SOLVER_DETAIL_RESOLVER_H
#ifndef ZYPP_USE_RESOLVER_INTERNALS
#error Do not directly include this file!
#else

#include <iosfwd>
#include <string>
#include <list>
#include <map>

#include <zypp-core/Globals.h>
#include <zypp/solver/Types.h>
#include <zypp/base/SerialNumber.h>

/////////////////////////////////////////////////////////////////////////
namespace zypp
{
  namespace sat
  {
    class Transaction;
  }
  ///////////////////////////////////////////////////////////////////////
  namespace solver
  {
    /////////////////////////////////////////////////////////////////////
    namespace detail
    {
      class SATResolver;
      typedef std::list<PoolItem> PoolItemList;
      typedef std::set<PoolItem> PoolItemSet;

///////////////////////////////////////////////////////////////////
//
//	CLASS NAME : Resolver
/** A mid layer class we should remove
 * \todo Merge this and class SATResolver. Logic and date are horribly
 * distributed between this and SATResolver. Either SATResolver becomes
 * a pure wrapper adapting the libsolv C interface to fit our needs, and
 * all the solver logic and problem handling goes here; or completely merge
 * both classes.
 */
class ZYPP_API_DEPTESTOMATIC Resolver : private base::NonCopyable
{
  typedef std::multimap<PoolItem,ItemCapKind> ItemCapKindMap;
  private:
    ResPool _pool;
    SATResolver *_satResolver;
    SerialNumberWatcher _poolchanged;

    CapabilitySet _extra_requires;
    CapabilitySet _extra_conflicts;
    std::set<Repository> _upgradeRepos;

    // Regard dependencies of the item weak onl
    PoolItemList _addWeak;

    /** \name Solver flags */
    //@{
    bool _upgradeMode:1;              // Resolver has been called with doUpgrade
    bool _updateMode:1;               // Resolver has been called with doUpdate
    bool _verifying:1;                // The system will be checked
    bool _solveSrcPackages:1;         // whether to generate solver jobs for selected source packges.
    bool _ignoreAlreadyRecommended:1; // ignore recommended packages that have already been recommended by the installed packages
    //@}

    /** \name applyDefaults
     * Remember whether global default or explicit settings are applied to SATResolver.
     * Global defaults may change with the Target, explicit settings not.
     */
    //@{
    bool _applyDefault_focus:1;
    bool _applyDefault_forceResolve:1;
    bool _applyDefault_cleandepsOnRemove:1;
    bool _applyDefault_onlyRequires:1;
    bool _applyDefault_allowDowngrade:1;
    bool _applyDefault_allowNameChange:1;
    bool _applyDefault_allowArchChange:1;
    bool _applyDefault_allowVendorChange:1;
    bool _applyDefault_dupAllowDowngrade:1;
    bool _applyDefault_dupAllowNameChange:1;
    bool _applyDefault_dupAllowArchChange:1;
    bool _applyDefault_dupAllowVendorChange:1;
    //@}

    // Additional QueueItems which has to be regarded by the solver
    // This will be used e.g. by solution actions
    solver::detail::SolverQueueItemList _removed_queue_items;
    solver::detail::SolverQueueItemList _added_queue_items;

    // Additional information about the solverrun
    ItemCapKindMap _isInstalledBy;
    ItemCapKindMap _installs;
    ItemCapKindMap _satifiedByInstalled;
    ItemCapKindMap _installedSatisfied;

    // helpers
    void collectResolverInfo();

    // Unmaintained packages which does not fit to the updated system
    // (broken dependencies) will be deleted.
    // returns true if solving was successful
    bool checkUnmaintainedItems ();

    void solverInit();

  public:

    Resolver( ResPool  pool );
    virtual ~Resolver();

    // ---------------------------------- I/O

    std::ostream & dumpOn( std::ostream & str ) const;

    friend std::ostream& operator<<( std::ostream& str, const Resolver & obj )
    { return obj.dumpOn (str); }

    // ---------------------------------- methods

    ResPool pool() const;
    void setPool( const ResPool & pool ) { _pool = pool; }

    /**
     * Reset all solver flags to the systems default (e.g. from zypp.conf).
     *
     * The information whether a \ref SATResolver setting was explicitly set or follows
     * the targets default (zypp.conf) is stored here in the \ref Resolver.
     * If \a all_r is \c false, only those settings are updated, which still follow
     * the target defaults (e.g. after the target has changed). Otherwise all explicit
     * settings are discarded and the defaults are applied.
     */
    void setDefaultSolverFlags( bool all_r );

    void addUpgradeRepo( Repository repo_r ) 		{ if ( repo_r && ! repo_r.isSystemRepo() ) _upgradeRepos.insert( repo_r ); }
    bool upgradingRepo( Repository repo_r ) const	{ return( _upgradeRepos.find( repo_r ) != _upgradeRepos.end() ); }
    void removeUpgradeRepo( Repository repo_r )		{ _upgradeRepos.erase( repo_r ); }
    void removeUpgradeRepos()				{ _upgradeRepos.clear(); }
    const std::set<Repository> & upgradeRepos() const	{ return _upgradeRepos; }

    void addExtraRequire( const Capability & capability );
    void removeExtraRequire( const Capability & capability );
    void addExtraConflict( const Capability & capability );
    void removeExtraConflict( const Capability & capability );

    void removeQueueItem( const SolverQueueItem_Ptr& item );
    void addQueueItem( const SolverQueueItem_Ptr& item );

    CapabilitySet extraRequires() const		{ return _extra_requires; }
    CapabilitySet extraConflicts() const	{ return _extra_conflicts; }

    void addWeak( const PoolItem & item );

    bool verifySystem();
    bool resolvePool();
    bool resolveQueue( SolverQueueItemList & queue );
    void doUpdate();

    bool doUpgrade();
    PoolItemList problematicUpdateItems() const;

    /** \name Solver flags */
    //@{
    bool ignoreAlreadyRecommended() const	{ return _ignoreAlreadyRecommended; }
    void setIgnoreAlreadyRecommended( bool yesno_r ) { _ignoreAlreadyRecommended = yesno_r; }

    bool isUpgradeMode() const 			{ return _upgradeMode; }// Resolver has been called with doUpgrade
    void setUpgradeMode( bool yesno_r )		{ _upgradeMode = yesno_r; }

    bool isUpdateMode() const 			{ return _updateMode; }	// Resolver has been called with doUpdate
    void setUpdateMode( bool yesno_r )		{ _updateMode = yesno_r; }

    bool isVerifyingMode() const 		{ return _verifying; }	// The system will be checked
    void setVerifyingMode( TriBool state_r )	{ _verifying = indeterminate(state_r) ? false : bool(state_r); }

    bool solveSrcPackages() const 		{ return _solveSrcPackages; }
    void setSolveSrcPackages( TriBool state_r )	{ _solveSrcPackages = indeterminate(state_r) ? false : bool(state_r); }
    //@}

    void setRemoveOrphaned( bool yesno_r );
    bool removeOrphaned() const;

    void setRemoveUnneeded( bool yesno_r );
    bool removeUnneeded() const;

    void setFocus( ResolverFocus focus_r );
    ResolverFocus focus() const;

#define ZOLV_FLAG_TRIBOOL( ZSETTER, ZGETTER )	\
    void ZSETTER( TriBool state_r );		\
    bool ZGETTER() const;			\

    ZOLV_FLAG_TRIBOOL( setForceResolve          ,forceResolve         )
    ZOLV_FLAG_TRIBOOL( setCleandepsOnRemove     ,cleandepsOnRemove    )
    ZOLV_FLAG_TRIBOOL( setOnlyRequires          ,onlyRequires         )
    ZOLV_FLAG_TRIBOOL( setAllowDowngrade        ,allowDowngrade       )
    ZOLV_FLAG_TRIBOOL( setAllowNameChange       ,allowNameChange      )
    ZOLV_FLAG_TRIBOOL( setAllowArchChange       ,allowArchChange      )
    ZOLV_FLAG_TRIBOOL( setAllowVendorChange     ,allowVendorChange    )
    ZOLV_FLAG_TRIBOOL( dupSetAllowDowngrade     ,dupAllowDowngrade    )
    ZOLV_FLAG_TRIBOOL( dupSetAllowNameChange    ,dupAllowNameChange   )
    ZOLV_FLAG_TRIBOOL( dupSetAllowArchChange    ,dupAllowArchChange   )
    ZOLV_FLAG_TRIBOOL( dupSetAllowVendorChange  ,dupAllowVendorChange )
#undef ZOLV_FLAG_TRIBOOL

    ResolverProblemList problems() const;

    void applySolutions( const ProblemSolutionList & solutions );
    bool applySolution( const ProblemSolution & solution );

    // Return the Transaction computed by the last solver run.
    sat::Transaction getTransaction();

    // reset all SOLVER transaction in pool
    void undo();

    void reset( bool keepExtras = false );

    // Get more information about the solverrun
    // Which item will be installed by another item or triggers an item for
    // installation
    ItemCapKindList isInstalledBy( const PoolItem & item );
    ItemCapKindList installs( const PoolItem & item );
    ItemCapKindList satifiedByInstalled (const PoolItem & item );
    ItemCapKindList installedSatisfied( const PoolItem & item );

public:
    /** Expert backdoor. */
    sat::detail::CSolver * get() const;
};

///////////////////////////////////////////////////////////////////
    };// namespace detail
    /////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////
  };// namespace solver
  ///////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////////
};// namespace zypp
/////////////////////////////////////////////////////////////////////////
#endif // ZYPP_USE_RESOLVER_INTERNALS
#endif // ZYPP_SOLVER_DETAIL_RESOLVER_H
