// -*- C++ -*-

#ifndef EPT_APT_PACKAGE_H
#define EPT_APT_PACKAGE_H

namespace ept {
namespace core {
namespace package {

struct Setup {
    typedef ept::Token Token;
    typedef package::Internal Internal;
    typedef package::PropertyId PropertyId;
    typedef package::InternalList InternalList;
};

template<> struct PropertyType< Name > { typedef std::string T; };
template<> struct PropertyType< Versions > { typedef VersionList T; };
template<> struct PropertyType< AnyVersion > { typedef Token T; };
template<> struct PropertyType< State > { typedef PackageState T; };
template<> struct PropertyType< CandidateVersion > { typedef Token T; };
template<> struct PropertyType< InstalledVersion > { typedef Token T; };

struct Source : core::Source< Source, Setup, PropertyType >
{
    AptDatabase &m_db;

    Source( AptDatabase &db ) : m_db( db ) {}

    InternalList listInternal() {
        return InternalList( m_db.cache().PkgBegin() );
    }

    Internal lookupToken( Token t ) {
        return m_db.lookupPackage( t );
    }

    Token getToken( Internal i ) {
        Token t;
        t._id = i.Name();
        return t;
    }

    bool exists( Token t ) {
        if ( t.hasVersion() )
            return !m_db.lookupVersion( t ).end();
        else
            return !lookupToken( t ).end();
    }

    Token versionToken( pkgCache::VerIterator vi ) {
        if ( vi.end() )
            return Token();
        return Token( std::string( vi.ParentPkg().Name() ) + "_" + vi.VerStr() );
    }

    template< PropertyId p >
    typename PropertyType< p >::T getInternal( Internal );

    template< typename List >
    void revertState( List l ) {
        while ( !l.empty() ) {
            PackageState s = getInternal< State >( l.head() );
            if ( !s.keep() || s.purge() ) {
                pkgDepCache::StateCache &S = db().state()[ l.head() ];
                db().state().MarkKeep( l.head(), false, false );
                S.iFlags &= ~pkgDepCache::Purge;
                S.iFlags &= ~pkgDepCache::ReInstall;
            }
            l = l.tail();
        }
    }

    void revertStates() {
        pkgDepCache::ActionGroup group( db().state() );
        revertState( listInternal() );
    }

    typedef ComposedList< State > ChangeList;

    static bool isChanged( Token t, PackageState s );
    static bool isUpgradable( Token t, PackageState s );

    PropertyFilter< State, __typeof( &isChanged ) >::T changedList() {
        return propertyFilter< State >( isChanged );
    }

    PropertyFilter< State, __typeof( &isUpgradable ) >::T upgradableList() {
        return propertyFilter< State >( isUpgradable );
    }

    AptDatabase &db() { return m_db; }
};

template<> inline std::string Source::getInternal< Name >( Internal i ) {
    return i.Name();
}

template<> inline PackageState Source::getInternal< State >( Internal i ) {
    return m_db.packageState( i );
}

template<> inline Token Source::getInternal< CandidateVersion >( Internal i ) {
    return versionToken( m_db.candidateVersion( i ) );
}

template<> inline Token Source::getInternal< AnyVersion >( Internal i ) {
    return versionToken( m_db.candidateVersion( i ) );
}

template<> inline Token Source::getInternal< InstalledVersion >( Internal i ) {
    return versionToken( m_db.installedVersion( i ) );
}

inline bool Source::isChanged( Token, PackageState s ) {
    return s.modify();
}

inline bool Source::isUpgradable( Token, PackageState s ) {
    return s.upgradable();
}

}
}
}

#endif
