// -*- C++ -*-
#ifndef EPT_CORE_APT_VERSION_H
#define EPT_CORE_APT_VERSION_H

namespace ept {
namespace core {
namespace version {

struct InternalList {
    package::Internal m_pkg;
    Internal m_ver;

    typedef Internal Type;

    InternalList tail() const {
        InternalList t = *this;
        t.m_ver ++;
        t.seek();
        return t;
    }

    const Internal head() const {
        return m_ver;
    }

    Internal head() {
        return m_ver;
    }

    bool empty() const {
        return m_pkg.end();
    }

    void seek()
    {
        while ( m_ver.end() && !m_pkg.end() ) {
            m_pkg ++;
            m_ver = m_pkg.VersionList();
        }
    }

    InternalList( package::Internal i )
        : m_pkg( i )
    {
        m_ver = m_pkg.VersionList();
        seek();
    }
};

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

struct Source : core::Source< Source, Setup, PropertyType >
{
    AptDatabase &m_db;
    Source( AptDatabase &db ) : m_db( db ) {}

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

    Token getToken( Internal i ) {
        Token t;
        t._id = std::string( i.ParentPkg().Name() ) + "_" + i.VerStr();
        return t;
    }

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

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

template<> struct PropertyType< Package > { typedef Token T; };

template<> inline Token Source::getInternal< Package >( Internal i ) {
    assert( !i.end() );
    Token t;
    t._id = i.ParentPkg().Name();
    return t;
}

}
}
}

#endif
