/////////////////////////////////////////////////////////////////////////////
// Name:        packagecmd.h
// Purpose:     wxPackageCommand, wxPackageCommandArray, wxPackageCommandSet
// Author:      Francesco Montorsi
// Modified by:
// Created:     2006-13-07
// RCS-ID:      $Id: packagecmd.h,v 1.3 2007/01/28 15:56:11 frm Exp $
// Copyright:   (c) Julian Smart, Francesco Montorsi, Daniel J. Lauk
// Licence:     wxWidgets licence
/////////////////////////////////////////////////////////////////////////////

#ifndef _PACKAGECMD_H_
#define _PACKAGECMD_H_

// Includes
#include "wx/tokenzr.h"
#include "wx/process.h"
#include "wxp/compiler.h"
#include "wxp/packageopt.h"


class wxPackageCommand;
class wxPackageCommandSet;

extern wxPackageCommand wxEmptyPackageCommand;


// ----------------------------------------------------------------------------
// wxPackageCommand
// ----------------------------------------------------------------------------

//! A simple command which can be executed using wxExecute.
//! It can contain variables enclosed by $(...).
//! They can be evaluated using #Evaluate.
class wxPackageCommand : public wxObject
{
    DECLARE_DYNAMIC_CLASS(wxPackageCommand)

public:

    //! Default constructor does nothing.
    wxPackageCommand(const wxString &str = wxEmptyString,
                     const wxString &path = wxEmptyString,
                     const wxPackageCondition &cond = wxEmptyPackageCondition)
        : m_strCmd(str), m_strPath(path), m_cond(cond) {}

    wxPackageCommand& operator= (const wxString &cmd)
        { m_strCmd=cmd; return *this; }

public:     // keywords

    void AddKeyword(const wxString &name, const wxString &value)
        { m_hashmapKeywords[name]=value; }
    void AddKeywords(const wxArrayString &names, const wxArrayString &values)
    {
        wxASSERT(names.GetCount()==values.GetCount());
        for (size_t i=0; i<names.GetCount(); i++)
            AddKeyword(names[i], values[i]);
    }
    void AddKeywords(const wxStringHashMap &hash)
    {
        for (wxStringHashMap::const_iterator it = hash.begin(); it != hash.end(); it++)
            AddKeyword(it->first, it->second);
    }

public:     // misc

    // cast operator
    operator wxString() const
        { return m_strCmd; }

    bool IsOk() const
    {
        return !m_strCmd.IsEmpty() &&
               m_cond.IsOk();
    }

    void UpdateWorkingDirectory(const wxString &decompressionpath) const;
    long Run(wxProcess *proc = NULL) const;

public:     // getters

    wxPackageCondition &GetCondition()
        { return m_cond; }
    const wxPackageCondition &GetCondition() const
        { return m_cond; }

    wxString GetCommand() const
        { return wxDoStringSubstitution(m_strCmd, m_hashmapKeywords); }
    wxString GetWorkingPath() const
        { return wxDoStringSubstitution(m_strPath, m_hashmapKeywords); }

    wxString GetProgram() const;
    wxString GetProgramWithPath(const wxCompilerSettings &) const;
    wxString GetProgramArguments() const;

    wxStringHashMap &GetKeywords()
        { return m_hashmapKeywords; }

public:     // setters

    void SetCondition(const wxPackageCondition &cnd)
        { m_cond=cnd; }
    void SetCommand(const wxString &cmd)
        { m_strCmd=cmd; }
    void SetWorkingPath(const wxString &path)
        { m_strPath=path; }

protected:
    wxString m_strCmd;

    //! The working directory where the command should be launched.
    //! If empty is the decompression directory of the package owning *this.
    wxString m_strPath;

    //! The condition for this command.
    wxPackageCondition m_cond;

    //! A set of keywords which are substituted in the command
    //! and in its working path by #GetSubstitutedCmd.
    wxStringHashMap m_hashmapKeywords;
};

// the array
WX_DECLARE_OBJARRAY(wxPackageCommand, wxPackageCommandArrayHelper);



// ----------------------------------------------------------------------------
// wxPackageCommandArray
// ----------------------------------------------------------------------------

//! A list of commands, e.g. for building, installing, ...
//! and the associated options.
class wxPackageCommandArray : public wxPackageCommandArrayHelper
{
public:

    //! Default constructor does nothing.
    wxPackageCommandArray(wxPackageBuildSystemStage s = wxPBSS_BUILD)
        : m_nSelectedTarget(0), m_stage(s) {}


public:     // miscellaneous

    bool IsOk() const
    {
        for (size_t i=0; i<GetCount(); i++)
            if (!Item(i).IsOk())
                return false;
        return true;
    }

    //! Adds given keywords to all commands of this array.
    void AddKeywords(const wxArrayString &names, const wxArrayString &values)
    {
        for (size_t i=0; i<GetCount(); i++)
            Item(i).AddKeywords(names, values);
    }
    void AddKeywords(const wxStringHashMap &hash)
    {
        for (size_t i=0; i<GetCount(); i++)
            Item(i).AddKeywords(hash);
    }

public:     // getters

    //! Returns the targets supported by this array of commands.
    wxArrayString &GetTargets()
        { return m_arrTargets; }
    wxArrayString GetTargets() const
        { return m_arrTargets; }
    wxString GetTargetsStr() const
		{ return wxArray2String(m_arrTargets); }

    wxPackageBuildSystemStage GetStage() const
        { return m_stage; }

    //! Does the $(target) substitution and others in the n-th command and returns it.
    wxPackageCommand GetSubstitutedCmd(size_t n) const;

    //! Returns an array containing only the commands whose condition->IsValid()
    //! function returns true for the given package.
    wxPackageCommandArray GetValidCommandsFor(const wxPackage &) const;

    //! Returns the currently selected target which can be used for substitution of
    //! the $(target) keyword.
    wxString GetSelectedTarget() const
        { return m_arrTargets[m_nSelectedTarget]; }

public:     // setters

    void SetTargets(const wxString &str)
        { m_arrTargets = wxString2Array(str); }
    void SetTargets(const wxArrayString &str)
        { m_arrTargets = str; }

    void SetSelectedTarget(size_t n)
    { 
        // the || n == 0 part is when an invalid package contains no
        // targets: in that case the value zero is "valid"
        wxASSERT(n < m_arrTargets.GetCount() || n == 0); 
        m_nSelectedTarget=n; 
    }

    void CopyTargets(const wxPackageCommandArray &arr)
    {
        m_arrTargets = arr.m_arrTargets;
        m_nSelectedTarget = arr.m_nSelectedTarget;
    }

protected:

    //! The possible targets which can be invoked for this stage.
    wxArrayString m_arrTargets;

    //! The currently selected target for this array of commands.
    size_t m_nSelectedTarget;

    //! The stage of the commands of this array.
    wxPackageBuildSystemStage m_stage;
};



// ----------------------------------------------------------------------------
// wxPackageCommandSet
// ----------------------------------------------------------------------------

class wxPackageCommandSet : public wxPackageCommandArray
{
public:
    wxPackageCommandSet() {}

public:     // getters

    wxArrayString GetVars() const
        { return m_vars; }
    wxPackageBuildSystemType GetBuildSystemType() const
        { return m_buildSystemType; }

    //! Returns the description for this array of options, if any.
    wxString GetDescription() const
        { return m_strDesc; }

public:     // setters

    void SetVars(const wxString &var)
        { m_vars = wxString2Array(var); }
    void SetBuildSystemType(wxPackageBuildSystemType t)
        { m_buildSystemType=t; }
    void SetDescription(const wxString &str)
        { m_strDesc=str; }

public:     // misc

    bool IsOk() const
    {
        return m_buildSystemType != wxPBST_INVALID &&
               wxPackageCommandArray::IsOk();
    }

    //! Returns true if this command preset is used by the given command array.
    //! When returning true, the given string hashmap is filled with the values and
    //! the names of the variables to use to obtain the given array from this command preset.
    bool IsUsedBy(const wxPackageCommandArray *arrays, wxStringHashMap &touse) const;

protected:
    wxArrayString m_vars;
    wxPackageBuildSystemType m_buildSystemType;
    wxString m_strDesc;
};


#endif      // _PACKAGECMD_H_

