/////////////////////////////////////////////////////////////////////////////
// Name:        wxputils.h
// Purpose:     wxPackage API utilities
// Author:      Francesco Montorsi
// Modified by:
// Created:     2006-11-07
// RCS-ID:      $Id: wxputils.h,v 1.6 2007/01/23 18:25:31 frm Exp $
// Copyright:   (c) Francesco Montorsi
// Licence:     wxWidgets licence
/////////////////////////////////////////////////////////////////////////////

#ifndef _WXPUTILS_H_
#define _WXPUTILS_H_

// Includes
#include <wx/tokenzr.h>
#include <wx/hashmap.h>

//! The delimiters used for lists in all the WXP API.
#define wxPACKAGE_DELIMITERS                wxT(", ")


// these are used by wxIMPLEMENT_STRING2COMBINEABLE_ENUM
extern double log(double);


// A macro which helps defines the wxString2* functions for wxPackage API.
// VERY IMPORTANT: this assumes that the vaid values of the enum start at
//                 value zero and ends at the given 'max' value and that
//                 all values in zero-max range are valid
#define wxDEFINE_STRING2ENUM(enumname)                       \
    extern wxString wx##enumname##Name[];                    \
    wx##enumname wxString2##enumname(const wxString &str);   \
    wxString wx##enumname##2String(wx##enumname value);

// A macro which helps defines the wxString2* functions for wxPackage API.
// VERY IMPORTANT: this assumes that the vaid values of the enum start at
//                 value zero and ends at the 2^'max' value and that
//                 all values are powers of two.
#define wxDEFINE_STRING2COMBINEABLE_ENUM(enumname)           \
    wxDEFINE_STRING2ENUM(enumname);                          \
    wx##enumname wxIdx2##enumname(size_t n);                 \
    size_t wx##enumname##2Idx(wx##enumname value);           \
    wxString wx##enumname##List2String(long n);              \
    long wxString2##enumname##List(const wxString &str);     \
    long wxGetFull##enumname##List();


// A macro which implements the wxString2* functions for wxPackage API.
// VERY IMPORTANT: this assumes that the vaid values of the enum start at
//                 value zero and ends at the given 'max' value and that
//                 all values in zero-max range are valid
#define wxIMPLEMENT_STRING2ENUM(enumname, max)                  \
    wx##enumname wxString2##enumname (const wxString &str)      \
    {                                                           \
        for (size_t i=0; i < max; i++)                          \
            if (wx##enumname##Name[i].IsSameAs(str, false))     \
                return (wx##enumname)i;                         \
        return (wx##enumname)wxNOT_FOUND;                       \
    }                                                           \
                                                                \
    wxString wx##enumname##2String(wx##enumname value)          \
    {                                                           \
        wxASSERT(value >= 0 && value < max);                    \
        return wx##enumname##Name[(size_t)value];               \
    }

// Like wxIMPLEMENT_STRING2ENUM except that this works for enumerations
// which have values which are power of 2.
// The first valid value is supposed to be 1 and the last is 2^(max-1).
#define wxIMPLEMENT_STRING2COMBINEABLE_ENUM(enumname, max)      \
                                                                \
    /* linear index <-> enum value conversions */               \
    wx##enumname wxIdx2##enumname(size_t n)                     \
    {                                                           \
        wxASSERT(n >= 0 && n < max);                            \
        return (wx##enumname)(1 << n);                          \
    }                                                           \
                                                                \
    size_t wx##enumname##2Idx(wx##enumname value)               \
    {                                                           \
        wxASSERT(value >= 0 && value <= (1 << (max-1)));        \
        return (int)wxRound(log((double)value)/log((double)2.));\
    }                                                           \
                                                                \
    /* string <-> enum value conversions */                     \
    wx##enumname wxString2##enumname (const wxString &str)      \
    {                                                           \
        for (size_t i=0; i < max; i++)                          \
            if (wx##enumname##Name[i].CmpNoCase(str) == 0)      \
                return (wx##enumname)(1 << i);                  \
        return (wx##enumname)wxNOT_FOUND;                       \
    }                                                           \
                                                                \
    wxString wx##enumname##2String(wx##enumname value)          \
    {                                                           \
        size_t n = wx##enumname##2Idx(value);                   \
        return wx##enumname##Name[n];                           \
    }                                                           \
                                                                \
    /* combined list <-> string conversions */                  \
    wxString wx##enumname##List2String(long n)                  \
    {                                                           \
        wxString ret;                                           \
        for (size_t i=0; i < max; i++)                          \
        {                                                       \
            wx##enumname cur = wxIdx2##enumname(i);             \
            if ((n & cur) != 0)                                 \
                ret += wx##enumname##2String(cur) + wxT(",");   \
        }                                                       \
        if (ret.EndsWith(wxT(",")))                             \
            ret.RemoveLast();                                   \
        return ret;                                             \
    }                                                           \
                                                                \
    long wxString2##enumname##List(const wxString &str)         \
    {                                                           \
        wxArrayString temp = wxString2Array(str);               \
        long ret = 0;                                           \
        for (size_t i=0; i<temp.GetCount(); i++)                \
        {                                                       \
            wx##enumname t = wxString2##enumname(temp[i]);      \
            if (t != (wx##enumname)-1)                          \
                ret |= t;                                       \
        }                                                       \
        return ret;                                             \
    }                                                           \
                                                                \
    long wxGetFull##enumname##List()                            \
        { return (1 << max) - 1; }


#define WX_DECLARE_STD_OBJARRAY_HELPERS(T, emptyT)              \
    int IndexByName(const wxString &name) const                 \
    {                                                           \
        for (size_t i=0; i<GetCount(); i++)                     \
            if (Item(i).GetName().CmpNoCase(name) == 0)         \
                return i;                                       \
        return wxNOT_FOUND;                                     \
    }                                                           \
                                                                \
    T &ItemByName(const wxString &name)                         \
    {                                                           \
        int n = IndexByName(name);                              \
        if (n != wxNOT_FOUND)                                   \
            return Item(n);                                     \
        return emptyT;                                          \
    }                                                           \
                                                                \
    bool IsOk() const                                           \
    {                                                           \
        for (size_t i=0; i<GetCount(); i++)                     \
            if (!Item(i).IsOk())                                \
                return false;                                   \
        return true;                                            \
    }                                                           \
                                                                \
    bool Contains(const T &p) const                             \
        { return Index(p) != wxNOT_FOUND; }                     \
    bool ContainsItemNamed(const wxString &name) const          \
        { return IndexByName(name) != wxNOT_FOUND; }            \
                                                                \
    /* need to redefine Index() so that it uses the */          \
    /* operator== of our items as wxObjArray never uses */      \
    /* the item's comparison operator! */                       \
    int Index(const T &item) const                              \
    {                                                           \
        for (size_t i=0; i<GetCount(); i++)                     \
            if (Item(i) == item)                                \
                return i;                                       \
        return wxNOT_FOUND;                                     \
    }


// a string hashmap
// FIXME: maybe this could be moved in wx directly ??
WX_DECLARE_STRING_HASH_MAP( wxString,
                            wxStringHashMap );

// this helps checking that the user input is valid
bool wxIsPlainWord(const wxString &tocheck);
wxString wxGetPlainWordAllowedCharacters();


// substitution helpers

#define wxWPM_SUBSTITUTION_START_MARKER     wxT("$(")
#define wxWPM_SUBSTITUTION_END_MARKER       wxT(")")

wxString wxDoStringSubstitution(const wxString &str,
                                const wxStringHashMap &hash);

//! Merges 'tomerge' into 'out'.
void wxMergeHashMap(wxStringHashMap &out, 
                    const wxStringHashMap &tomerge);

//! Normalizes the given hash map: i.e. makes sure that the hashmap's values
//! do not contains $(strings) themselves.
//! Returns true if the hashmap could be successfully normalized.
bool wxNormalizeSubstitutionHashMap(wxStringHashMap &out);



// string lists <-> wxArrayString

wxString wxArray2String(const wxArrayString &, const wxString &sep = wxT(","));
wxArrayString wxString2Array(const wxString &, const wxString &sep = wxPACKAGE_DELIMITERS);


// HTML -> plain text

wxString wxStripOutHTML(const wxString &str);


// helpers for wxPORT_* flags
#define wxPORT_MAX      11
long wxGetFullPortIdList();
wxString wxPortIdList2String(long n);
long wxString2PortIdList(const wxString &str);

//wxDEFINE_STRING2COMBINEABLE_ENUM(PortId);


#endif      // _WXPUTILS_H_

