/////////////////////////////////////////////////////////////////////////////
// Name:        wxp.h
// Purpose:     wxPackageXML, wxIfNodeListManager, wxPresetXMLDescriptor,
//              wxPackageRepositoryXMLDescriptor
// Author:      Francesco Montorsi
// Modified by:
// Created:     2006-06-29
// RCS-ID:      $Id: wxp.h,v 1.4 2007/01/31 13:27:46 frm Exp $
// Copyright:   (c) Francesco Montorsi
// Licence:     wxWidgets licence
/////////////////////////////////////////////////////////////////////////////

#ifndef _WXP_H_
#define _WXP_H_

// Includes
#include <wx/xml/xml.h>
#include <wx/wfstream.h>
#include "wxp/package.h"


// the hashmap for storing OPTION presets
WX_DECLARE_STRING_HASH_MAP( wxPackageCommandOptionArray,
                            wxPackageCommandOptionArrayHashMap );

// the hashmap for storing COMMAND presets
WX_DECLARE_STRING_HASH_MAP( wxPackageCommandSet,
                            wxPackageCommandSetHashMap );


// ----------------------------------------------------------------------------
// wxPackageXML
// ----------------------------------------------------------------------------

//! A base class to load those tags which are common to both presets
//! and WXP files.
class wxPackageXML : public wxXmlDocument
{
    DECLARE_DYNAMIC_CLASS(wxPackageXML)

public:

    // -1 for m_nIndentationStep means "no indentation"
    wxPackageXML() { m_nIndentationStep=-1; }
    virtual ~wxPackageXML() {}


public:     // indentation step (makes sense only in wxPackageXMLDescriptor currently!)

    int GetIndentationStep() const
        { return m_nIndentationStep; }
    void SetIndentationStep(int n)
        { m_nIndentationStep=n; }

public:         // load helpers

    //! To be called when an unknown tag is found.
    void HandleUnknownTag(wxXmlNode *node);

    //! Loads an <option-set> or <options> from the given node and returns it.
    wxPackageCommandOptionArray LoadOptions(const wxXmlNode *n);

    //! Loads an <option> from the given node and returns it.
    wxPackageCommandOption LoadOption(const wxXmlNode *n);

    //! Loads an <if> from the given node and returns it.
    wxPackageCondition LoadCondition(const wxXmlNode *n);

    //! Loads a <cmd> from the given node and returns it.
    wxPackageCommand LoadCommand(const wxXmlNode *n);

    //! Returns the contents of the given node with all standard substitutions.
    wxString GetStrippedNodeContent(const wxXmlNode *n) const;

public:         // save helpers

    //! Appends a child text node to the given node containing a newline
    //! followed by a number of spaces determined by the level multiplied by
    //! the indentation step width.
    wxXmlNode *AddChildIndentation(wxXmlNode *node, int level);

    //! Appends a sibling text node to the given node containing a newline
    //! followed by a number of spaces determined by the level multiplied by 
    //! the indentation step width.
    wxXmlNode *AddSiblingIndentation(wxXmlNode *node, int level);

    //! Inserts an indentation child.
    wxXmlNode *InsertChildIndentation(wxXmlNode *node, wxXmlNode *before_node, int level);

    // NOTE: all the following functions create nodes which are then returned
    //       and not attached anywhere. They still take a "level" indentation 
    //       parameter because when creating nodes with subnodes, they need
    //       to indent the subnodes and thus need to know how many spaces to leave.

    //! Saves given <option> in a wxXmlNode and returns it.
    wxXmlNode *SaveOption(const wxPackageCommandOption &opt, int level);

    //! Saves given <cmd> in a wxXmlNode and returns it.
    wxXmlNode *SaveCommand(const wxPackageCommand &cmd, int level);

    //! Saves given <if> in a wxXmlNode and returns it.
    wxXmlNode *SaveCondition(const wxPackageCondition &cond, int level);

protected:

    //! How much spaces is a single indentation ?
    int m_nIndentationStep;
};



// ----------------------------------------------------------------------------
// wxIfNodeListManager
// ----------------------------------------------------------------------------

//! A little class which helps managing lists of <if> tags.
//! Create it and then use its #SmartAppend function to create an "optimized"
//! list of <if> nodes: adiacent nodes with same condition will be merged.
class wxIfNodeListManager
{
public:
    wxIfNodeListManager(wxPackageXML *xmldoc, wxXmlNode *parent)
        : m_parent(parent), m_doc(xmldoc) { m_previousif=NULL; }

    void SmartAppend(wxXmlNode *n, const wxPackageCondition &cnd, int level = 0);
    void SaveOptions(const wxPackageCommandOptionArray &arr, int level = 0);
    void SaveCommands(const wxPackageCommandArray &arr, int level = 0);


protected:      // not changed anymore after initialization

    // the parent of all nodes appended
    wxXmlNode *m_parent;

    // the instance of the class which owns m_parent
    wxPackageXML *m_doc;

protected:

    // the previous <if> node or NULL if previous node does not exist
    // or has a wxEmptyPackageCondition
    wxXmlNode *m_previousif;

    // the previous condition or wxEmptyPackageCondition if previous node
    // does not exist or has a wxEmptyPackageCondition
    wxPackageCondition m_previouscond;
};



// ----------------------------------------------------------------------------
// wxPresetXMLDescriptor
// ----------------------------------------------------------------------------

//! An XML document which describes presets (of options only currently).
class wxPresetXMLDescriptor : public wxPackageXML
{
    DECLARE_DYNAMIC_CLASS(wxPresetXMLDescriptor)

public:
    wxPresetXMLDescriptor() {}
    virtual ~wxPresetXMLDescriptor() {}


public:         // static

    //! The option presets loaded so far.
    static wxPackageCommandOptionArrayHashMap s_hashmapOptions;

    //! The command presets loaded so far.
    static wxPackageCommandSetHashMap s_hashmapCommands;

    //! TODO
    static wxArrayString GetCommandPresetNamesFor(wxPackageBuildSystemType type)
    {
        wxArrayString ret;
        wxPackageCommandSetHashMap::const_iterator it;
        for ( it = s_hashmapCommands.begin();
              it != s_hashmapCommands.end();
              it++ )
            if (it->second.GetBuildSystemType() == type)
                ret.Add(it->first);

        return ret;
    }

    //! TODO
    static wxArrayString GetOptionPresetNamesFor(wxPackageBuildSystemType type)
    {
        wxArrayString ret;
        wxPackageCommandOptionArrayHashMap::const_iterator it;
        for ( it = s_hashmapOptions.begin();
              it != s_hashmapOptions.end();
              it++ )
            if (it->second.GetCommonCondition().IsValidForBuildSys(type))
                ret.Add(it->first);

        return ret;
    }


#ifdef __WXDEBUG__
    static void Dump();
#else
    static void Dump() {}
#endif

public:         // load & save

    //! Loads an XML preset descriptor stream and adds the presets to the
    //! #s_presetHashMap.
    bool Load(wxInputStream &stream);

    //! Like other #Load overload.
    static bool Load(const wxString &filename);


    // NB: for these functions the "Save" name cannot be used as it is
    //     the name of a virtual function in the base class

    //! Saves the #s_presetHashMap presets in the given output stream.
    bool SavePresets(wxOutputStream &stream);

    //! Like other #Save overload.
    static bool SavePresets(const wxString &filename);

public:         // load helpers

    //! Loads a <command-set> from the given node
    wxPackageCommandSet LoadCommandSet(const wxXmlNode *n);
};


// ----------------------------------------------------------------------------
// wxPackageRepositoryXMLDescriptor
// ----------------------------------------------------------------------------

//! An XML document which describes a repository of wx packages.
//! This document usually has the .WXL extension (and is saved into gzipped files).
class wxPackageRepositoryXMLDescriptor : public wxPackageXML
{
    DECLARE_DYNAMIC_CLASS(wxPackageRepositoryXMLDescriptor)

public:
    wxPackageRepositoryXMLDescriptor() {}
    virtual ~wxPackageRepositoryXMLDescriptor() {}

    // loads the given gzipped WXL file:
    bool Load(const wxString &filename);

    // loads the WXL from the given input stream (which is supposed decompressed):
    bool Load(wxInputStream &stream)
        { return wxPackageXML::Load(stream); }

public:     // setters

    bool AddPackage(const wxString &pkgfile);

public:     // getters

    //! Returns an array of wxPackages with status == wxPS_NONE.
    //! The 'repourl' parameter is necessary to set the the repository download
    //! link in the wxPackage objects returned (see wxPackageInfo::GetRepoDownloadLink).
    wxPackageArray GetPackageArray(const wxString &repourl);
};


#endif      // _WXP_H_

