/////////////////////////////////////////////////////////////////////////////
// Name:        packagedep.h
// Purpose:     wxPackageDependency, wxPackageDependencyArray
// Author:      Francesco Montorsi
// Modified by:
// Created:     2006-06-29
// RCS-ID:      $Id: packagedep.h,v 1.1.1.1 2006/12/12 09:40:57 frm Exp $
// Copyright:   (c) Francesco Montorsi
// Licence:     wxWidgets licence
/////////////////////////////////////////////////////////////////////////////

#ifndef _PACKAGEDEP_H_
#define _PACKAGEDEP_H_

// Includes
#include "wx/tokenzr.h"
#include "wxp/wxputils.h"
#include "wxp/compiler.h"
#include "wxp/wxbuild.h"
#include "wxp/packageutils.h"

class wxPackageId;
class wxPackageIdArray;
class wxPackageDependency;
class wxPackageDependencyArray;

extern wxPackageDependency wxEmptyPackageDependency;
extern wxPackageDependencyArray wxEmptyPackageDependencyArray;


// ----------------------------------------------------------------------------
// enums
// ----------------------------------------------------------------------------

//! The possible types of dependencies for a wxPackage...
enum wxPackageDependencyType
{
    wxPDT_INVALID = -1,

    wxPDT_REQUIRED,
    wxPDT_SUGGESTED,

    wxPDT_MAX
};

wxDEFINE_STRING2ENUM(PackageDependencyType)



// ----------------------------------------------------------------------------
// wxPackageDependency
// ----------------------------------------------------------------------------

//! A generic depedency for the build system of a wxPackage.
//! Mainly used by bakefile build system API.
class wxPackageDependency : public wxObject
{
    friend class wxPackageDependencyArray;
    DECLARE_DYNAMIC_CLASS(wxPackageDependency)

public:
    wxPackageDependency() { m_nType=wxPDT_INVALID; }
    wxPackageDependency(
             const wxString &name,
             const wxVersionRange &version,
             const wxString &href = wxEmptyString,
             wxPackageDependencyType type = wxPDT_REQUIRED,
             const wxPackageIdArray &owners = wxEmptyPackageIdArray)
             : m_nType(type),
               m_strResolutionHref(href),
               m_strName(name), m_version(version),
               m_owners(owners) {}
    virtual ~wxPackageDependency() {}


    bool operator==(const wxPackageDependency &dep) const
    {
        return m_strName.CmpNoCase(dep.m_strName) == 0 &&
               m_strResolutionHref == dep.m_strResolutionHref &&
               m_nType == dep.m_nType &&
               m_version == dep.m_version;
    }

    bool operator!=(const wxPackageDependency &dep) const
        { return !(*this == dep); }


public:     // getters

    wxString GetName() const
        { return m_strName; }
    wxVersionRange GetVersion() const
        { return m_version; }
    wxString GetResolutionHref() const
        { return m_strResolutionHref; }

    wxPackageDependencyType GetType() const
        { return m_nType; }
    wxString GetTypeStr() const
        { return wxPackageDependencyType2String(GetType()); }

    wxPackageIdArray GetOwnersId() const
        { return m_owners; }

    wxString GetOwnersIdStr() const
    {
        wxString own;
        for (size_t j=0; j<m_owners.GetCount(); j++)
            own += m_owners[j].GetName() + wxT(",");
        own.RemoveLast();
        return own;
    }

public:     // setters

    void SetName(const wxString &name)
        { m_strName=name; }
    void SetVersion(const wxVersionRange &ver)
        { m_version=ver; }
    void SetResolutionHref(const wxString &href)
        { m_strResolutionHref=href; }
    void SetType(wxPackageDependencyType t)
        { m_nType=t; }
    void SetOwnersId(const wxPackageIdArray &id)
        { m_owners=id; }

    void AddOwnerId(const wxPackageId &id)
        { m_owners.Add(id); }
    void SetOwnerId(const wxPackageId &id)
        { m_owners.Clear(); m_owners.Add(id); }

public:    // misc

    bool IsOk() const
    {
        return m_nType != wxPDT_INVALID &&
               !m_strName.IsEmpty() &&
               !m_strName.Contains(wxT(' ')) &&
               m_version.IsOk();
    }

    bool IsPartiallySatisfiedBy(const wxString &pkgname) const
        { return GetName().CmpNoCase(pkgname) == 0; }

    bool IsSatisfiedBy(const wxPackageId &pkg) const;
    bool IsSatisfiedByOneOf(const wxPackageArray &arr) const;

    //! Returns the package index which "best" matches this dependency,
    //! i.e. the package with the higher version number compatible
    //! with this dependency. Returns wxNOT_FOUND if the given array
    //! does not contain any package which satisfy this dependency.
    //! NOTE: we make the assumption that Software evolves in
    //!       something better as the time passes.
    //!       This is yet to be proved :)
    int GetBestMatch(const wxPackageArray &arr) const;

protected:          // internal utilities

    //! Returns the array with all recursive dependencies required by this
    //! dependency.
    bool DoGetRecursiveDependencies(
                    wxPackageDependencyArray *ret,
                    const wxPackageArray &arr,
                    wxPackageDependencyType type,
                    wxPackageDependencyArray *notfound,
                    wxPackageIdArray *alreadyprocessed) const;

protected:
    wxPackageDependencyType m_nType;
    wxString m_strResolutionHref;

    // cannot use a wxPackageId here as we need a wxVersionRange here
    wxString m_strName;
    wxVersionRange m_version;

    //! The wxPackageIdArray of the owners of this dependency.
    //! NB: while this is not required by wxPackageDependency itself
    //!     it's very useful in other contexts to know which package
    //!     is requiring this dependency.
    wxPackageIdArray m_owners;
};

// the array
WX_DECLARE_OBJARRAY(wxPackageDependency, wxPackageDependencyArrayHelper);



// ----------------------------------------------------------------------------
// wxPackageDependencyArray
// ----------------------------------------------------------------------------

class wxPackageDependencyArray : public wxPackageDependencyArrayHelper
{
    // required to get access to DoGetRecursiveDependency
    friend class wxPackage;

public:

    //! Default constructor does nothing.
    wxPackageDependencyArray() {}

public:

    //! Returns true if all options are valid.
    bool IsOk() const
    {
        for (size_t i=0; i<GetCount(); i++)
            if (!Item(i).IsOk())
                return false;
        return true;
    }

    //! Returns the index of the first dependency with the given ID or wxNOT_FOUND.
    int IndexById(const wxPackageId &id) const
    {
        for (size_t i=0; i<GetCount(); i++)
            if (Item(i).IsSatisfiedBy(id))
                return i;
        return wxNOT_FOUND;
    }

    wxPackageDependency &ItemById(const wxPackageId &id)
    {
        int n = IndexById(id);
        if (n != wxNOT_FOUND)
            return wxPackageDependencyArrayHelper::Item(n);
        return wxEmptyPackageDependency;
    }

    //! Returns the index of the first dependency with the given name or wxNOT_FOUND.
    int IndexByName(const wxString &id) const
    {
        for (size_t i=0; i<GetCount(); i++)
            if (Item(i).IsPartiallySatisfiedBy(id))
                return i;
        return wxNOT_FOUND;
    }

    wxPackageDependency &ItemByName(const wxString &id)
    {
        int n = IndexByName(id);
        if (n != wxNOT_FOUND)
            return wxPackageDependencyArrayHelper::Item(n);
        return wxEmptyPackageDependency;
    }

    // need to redefine Index() so that it uses the operator== of our items
    // (NB: wxObjArray never uses the item's comparison operator!)
    int Index(const wxPackageDependency &dep) const
    {
        for (size_t i=0; i<GetCount(); i++)
            if (Item(i) == dep)
                return i;
        return wxNOT_FOUND;
    }

    bool Contains(const wxPackageDependency &dep) const
        { return Index(dep) != wxNOT_FOUND; }
    bool ContainsDependencyFrom(const wxPackageId &id) const
        { return IndexById(id) != wxNOT_FOUND; }
    bool ContainsDependencyNamed(const wxString &pkgname) const
        { return IndexByName(pkgname) != wxNOT_FOUND; }

    void Dump()
    {
        for (size_t i=0; i<GetCount(); i++)
            wxLogDebug(wxT("%s %s"), Item(i).GetName().c_str(),
                       Item(i).GetVersion().GetAsString().c_str());
    }
/*
    void MergeWith(const wxPackageDependencyArray &arr)
    {
        for (size_t i=0; i<arr.GetCount(); i++)
            MergeWith(arr[i]);
    }

    void MergeWith(const wxPackageDependency &dep)
    {
        if (Contains(dep))
            return;
        Add(dep);
    }

    TOREMOVE
*/
public:     // getters

    //! Returns the dependencies of the given type contained in this array.
    wxPackageDependencyArray GetDependenciesOfType(wxPackageDependencyType) const;

    //! Returns the dependencies which can be satisfied using the given array.
    wxPackageDependencyArray GetDependenciesAvailableIn(const wxPackageArray &arr) const;

    //! Returns the dependencies which can NOT be satisfied using the given array.
    wxPackageDependencyArray GetDependenciesNotAvailableIn(const wxPackageArray &arr) const;

    //! Returns the dependencies which are not compatible among themselves.
    wxPackageDependencyArray GetConflictingDependencies() const;

protected:          // internal utilities

    //! FIXME
    bool DoGetRecursiveDependencies(
                    wxPackageDependencyArray *ret,
                    const wxPackageArray &arr,
                    wxPackageDependencyType type,
                    wxPackageDependencyArray *notfound,
                    wxPackageIdArray *alreadyprocessed) const;
};


#endif      // _PACKAGEDEP_H_

