// Parameter storage class definition.
//
// Copyright 2001, KUN
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

// $Id: paramtab.h,v 1.11 2003/11/26 22:15:14 pspiertz Exp $

#ifndef PARAMTAB_H
#define PARAMTAB_H

#include <string>
#include <iostream>
#include <assert.h>
#include "insout.h"
#include "id.h"
#include "affixtab.h"

typedef ID ParamID;

//------------------------------------------------------------------------------
// enum ParamType
//
// Description:
//	Possible types of a parameter for strorage. The real type of
//	an id may not be known.
//------------------------------------------------------------------------------

typedef enum
{
    IdType,		// abstract name for SET, TEXT, or INT type
    SetType,		// set denotation
    TextType,		// text denotation
    IntType,		// integral denotation
    AnyText,		// unspecified TEXT affix
    AnyInt		// unspecified INT affix
} ParamType;

//------------------------------------------------------------------------------
// struct Param
//
// Description:
//	A parameter has a type and a value. The value of a parameter
//	is either a set, a string (id or text) or a number.
//------------------------------------------------------------------------------

struct Param
{
    // Constructors:
    Param(void) {}
    Param(pAffixSet set)			    // SetType
	{ type = SetType; value.set = set; }
    Param(ParamType param_type, ParamID param_id)   // TextType or IdType
	{ type = param_type; value.id = param_id; }
    Param(long number)				    // IntType
	{ type = IntType; value.number = number; }
    Param(ParamType param_type)			    // AnyText or AnyInt
	{ type = param_type; }

    ParamType	type;
    union
    {
        pAffixSet set;
        ParamID id;
        long number;
    } value;

    string to_string() const;
    void print(ostream& os) const
	{ os << to_string(); }
};

inline ostream&
operator <<(ostream& os, const Param& param)
{
    param.print(os);
    return os;
}

Param* merge(const Param& p1, const Param& p2);

inline bool
operator ==(const Param& p1, const Param& p2)
{
    if (p1.type != p2.type) {
        return false;
    }

    switch (p1.type) {
        case TextType:
        case IdType:
            return (p1.value.id == p2.value.id);
        case SetType:
            return (*(p1.value.set) == *(p2.value.set));
        case IntType:
            return (p1.value.number == p2.value.number);
        case AnyInt:
        case AnyText:
            return true;
        default:
            assert(0);
            return false;
    }
}

//------------------------------------------------------------------------------
// Function:
//	inline bool
//	operator <(const Param& param1, const Param& param2) const
//
// Description:
//	Less than operator for Param. First, the types of param1 and
//	param2 are compared. If the types are equal, the values are
//	compared.
//
// Note:
//	We use the number values of parameters for comparing, even
//	if the types are not IntType. Therefore, Param should not
//	contain any wider value.
//------------------------------------------------------------------------------

inline bool
operator <(const Param& param1, const Param& param2)
{
    if (param1.type < param2.type)
        return true;
    if (param1.type > param2.type)
        return false;
    else
        return param1.value.number < param2.value.number;
}

//------------------------------------------------------------------------------
// class ParamTable
//
// Description:
//	Table for inside out entering of lists of parameters. Equal lists
//	are stored only once.
//------------------------------------------------------------------------------

typedef const InsOutNode<Param>* pParam;
typedef InsOutTable<Param, Param*> ParamTableBase;

class ParamTable: public ParamTableBase
{
    public:
	pParam enter(const Param& param, pParam next = 0)
		{ return ParamTableBase::enter(param, next); }
	unsigned requested(void) const
		{ return ParamTableBase::requested(); }
	unsigned allocated(void) const
		{ return ParamTableBase::allocated(); }
        pParam merge(const pParam& p1, const pParam& p2);
};

#endif // PARAMTAB_H
