/*---------------------------------------------------------------------\
|                          ____ _   __ __ ___                          |
|                         |__  / \ / / . \ . \                         |
|                           / / \ V /|  _/  _/                         |
|                          / /__ | | | | | |                           |
|                         /_____||_| |_| |_|                           |
|                                                                      |
\---------------------------------------------------------------------*/
/** \file	zypp/target/CommitPackageCache.cc
 *
*/
#include <iostream>
#include <utility>
#include <zypp-core/base/Logger.h>
#include <zypp-core/base/Exception.h>

#include <zypp/target/CommitPackageCache.h>
#include <zypp/target/CommitPackageCacheImpl.h>
#include <zypp/target/CommitPackageCacheReadAhead.h>

using std::endl;

#include <zypp/target/rpm/librpmDb.h>
#include <zypp/repo/PackageProvider.h>
#include <zypp/repo/DeltaCandidates.h>
#include <zypp/ResPool.h>

///////////////////////////////////////////////////////////////////
namespace zypp
{ /////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////
  namespace target
  { /////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////
    namespace {
      ///////////////////////////////////////////////////////////////////
      /// \class QueryInstalledEditionHelper
      /// \short Helper for PackageProvider queries during download.
      /// Queries the exact version of a currently installed package
      /// in context(/) which may then be used by \ref applydeltarpm
      /// to build a final rpm.
      ///////////////////////////////////////////////////////////////////
      struct QueryInstalledEditionHelper
      {
        bool operator()( const std::string & name_r, const Edition & ed_r, const Arch & arch_r ) const
        {
          rpm::librpmDb::db_const_iterator it( "/" );
          for ( it.findByName( name_r ); *it; ++it )
          {
            if ( arch_r == it->tag_arch()
              && ( ed_r == Edition::noedition || ed_r == it->tag_edition() ) )
            {
              return true;
            }
          }
          return false;
        }
      };
    } // namespace
    ///////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////
    //
    //	class RepoProvidePackage
    //
    ///////////////////////////////////////////////////////////////////

    struct RepoProvidePackage::Impl
    {
      repo::RepoMediaAccess _access;
      std::list<Repository> _repos;
      repo::PackageProviderPolicy _packageProviderPolicy;
    };

    RepoProvidePackage::RepoProvidePackage()
      : _impl( new Impl )
    {
       const ResPool & pool( ResPool::instance() );
      _impl->_repos.insert( _impl->_repos.begin(), pool.knownRepositoriesBegin(), pool.knownRepositoriesEnd() );
      _impl->_packageProviderPolicy.queryInstalledCB( QueryInstalledEditionHelper() );
    }

    RepoProvidePackage::~RepoProvidePackage()
    {}

    ManagedFile RepoProvidePackage::operator()( const PoolItem & pi_r, bool fromCache_r )
    {
      ManagedFile ret;
      if ( fromCache_r )
      {
        repo::PackageProvider pkgProvider( _impl->_access, pi_r, _impl->_packageProviderPolicy );
        ret = pkgProvider.providePackageFromCache();
      }
      else if ( pi_r.isKind<Package>() )	// may make use of deltas
      {
        repo::DeltaCandidates deltas( _impl->_repos, pi_r.name() );
        repo::PackageProvider pkgProvider( _impl->_access, pi_r, deltas, _impl->_packageProviderPolicy );
        return pkgProvider.providePackage();
      }
      else	// SrcPackage or throws
      {
        repo::PackageProvider pkgProvider( _impl->_access, pi_r, _impl->_packageProviderPolicy );
        return pkgProvider.providePackage();
      }
      return ret;
    }

    ///////////////////////////////////////////////////////////////////
    //
    //	CLASS NAME : CommitPackageCache
    //
    ///////////////////////////////////////////////////////////////////

    CommitPackageCache::CommitPackageCache( Impl * pimpl_r )
    : _pimpl( pimpl_r )
    {
      assert( _pimpl );
    }

    CommitPackageCache::CommitPackageCache( PackageProvider packageProvider_r )
    {
      if ( getenv("ZYPP_COMMIT_NO_PACKAGE_CACHE") )
        {
          MIL << "$ZYPP_COMMIT_NO_PACKAGE_CACHE is set." << endl;
          _pimpl.reset( new Impl( std::move(packageProvider_r) ) ); // no cache
        }
      else
        {
          _pimpl.reset( new CommitPackageCacheReadAhead( std::move(packageProvider_r) ) );
        }
      assert( _pimpl );
    }

    CommitPackageCache::~CommitPackageCache()
    {}

    void CommitPackageCache::setCommitList( std::vector<sat::Solvable> commitList_r )
    { _pimpl->setCommitList( std::move(commitList_r) ); }

    ManagedFile CommitPackageCache::get( const PoolItem & citem_r )
    { return _pimpl->get( citem_r ); }

    bool CommitPackageCache::preloaded() const
    { return _pimpl->preloaded(); }

    void CommitPackageCache::preloaded( bool newval_r )
    { _pimpl->preloaded( newval_r ); }

    /******************************************************************
    **
    **	FUNCTION NAME : operator<<
    **	FUNCTION TYPE : std::ostream &
    */
    std::ostream & operator<<( std::ostream & str, const CommitPackageCache & obj )
    { return str << *obj._pimpl; }

    /////////////////////////////////////////////////////////////////
  } // namespace target
  ///////////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////////
} // namespace zypp
///////////////////////////////////////////////////////////////////
