// -*- C++ -*-
//
//  This file is part of Siena, a wide-area event notification system.
//  See http://www.cs.colorado.edu/serl/dot/siena.html
//
//  Author: Antonio Carzaniga <carzanig@cs.colorado.edu>
//  See the file AUTHORS for full details. 
//
//  Copyright (C) 1998-1999 University of Colorado
//
//  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 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, or send email to serl@cs.colorado.edu.
//
//
// $Id: Siena.h,v 1.11 2000/02/29 23:10:47 carzanig Exp $
// 
#ifndef _Siena_h
#define _Siena_h

#include <iostream.h>

#include <string>
#include <map.h>
#include <multimap.h>
#include <list.h>

#include <exception>

#ifdef HAVE_CXX_NAMESPACE
namespace Siena {
#endif

class Siena;
class Notifiable;
class Request;
class AttributeValue;
class Event;
class AttributeConstraint;
class Filter;
class Pattern;

/** @memo Interface of the event service.
    @author <a href="mailto:carzanig@cs.colorado.edu">Antonio Carzaniga</a>
    @version 3.1415
    @see SimpleSiena
    @doc
    A <code>Siena</code> object represents the access point to the
    <em>Siena</em> event service. Clients can publish and subscribe
    by calling the corresponding methods on a <code>Siena</code>
    object. 
    <p>
    <i>Example</i>:
    <pre>
    Siena * S = new SimpleSiena();

    Event e;

    e["price"] = 500;
    e["airline"] = "UA";
    e["dest"] = "MXP";

    S->publish(e);
    </pre>
*/
class Siena {
 public:
    /** @memo Version identifier for the Siena interface */ 
    static const char * Version;

    /** @memo publish an event
	@param e event to be published
	@exception SienaException
	@doc 
	injects event <code>e</code> into the event service. 
	A copy of <code>e</code> will be delivered to all those 
	interested parties that subscribed for matching filters. 
	<p>
	<i>Example</i>:
	<pre>
	Siena * S;
	// ...
        Event e;
	
	e["price"] = 500;
	e["airline"] = "UA";
	e["dest"] = "MXP";
	
	S->publish(e);
	</pre>
    */
    virtual void	publish(const Event &e)				= 0;
    /** @memo subscribes for a given <em>filter</em>.
	@see unsubscribe
	@param f filter that matches events of interest
	@param n subscriber
	@exception SienaException
	@doc
	subscribes for a given <em>filter</em>.  interested party
	<code>n</code> will receive notifications matching filter
	<code>f</code>. 
	<p>
	<i>Example</i>:
	<pre>
	Siena * S;
	Notifiable * n;
	// ...
	Filter f;
	f.add_constraint("price", Siena_lt, 700); 
	f.add_constraint("dest", Siena_eq, "MXP"); 
	
	S->subscribe(f,n);
	</pre>
    */
    virtual void	subscribe(const Filter &f, Notifiable *n)	= 0;
    /** @memo subscribes for a given <em>pattern</em>.
	@see unsubscribe
	@param p pattern of sequences of events of interest
	@param n subscriber */
    virtual void	subscribe(const Pattern &p, Notifiable *n)	= 0;
    /** @memo cancels previous subcriptions.
	@param f expresses filters to be cancelled
	@param n subscriber
	@see subscribe
	@doc
	cancel all previous subscriptions from interested party
	<code>n</code> with a filter <em>g</em> that is <em>covered</em>
	by filter <code>f</code>.
	<p>
	<i>Example</i>:
	<pre>
	Siena * S;
	Notifiable * n;
	// ...
	Filter f;
	
	f.add_constraint("dest", Siena_xx, 0);
	
	S->unsubscribe(f,n);
	</pre>

	Note that a filter [dest <i>any</i>] covers the filter of the
	previous example [price &lt; 700, dest == "MXP"] */
    virtual void	unsubscribe(const Filter &f, Notifiable *n)	= 0;
    /** @memo cancels previous subcriptions.
	@param p expresses patterns to be cancelled
	@param n subscriber

	@doc
	cancel all previous subscriptions from interested party
	<code>n</code> with a pattern <em>q</em> that is <em>covered</em>
	by pattern <code>p</code>.
    */
    virtual void	unsubscribe(const Pattern &p, Notifiable *n)	= 0;

    /** @memo announces the intention to notify a class of events
	@doc
	<b>not yet implemented!</b>
    */
    virtual void	advertise(const Filter &f)			= 0;
    /** @memo cancels previous advertisements
	@doc
	<b>not yet implemented!</b>
    */
    virtual void	unadvertise(const Filter &)			= 0;

    /** @memo cancels all previous subcriptions from a given subscriber.
	@param n subscriber
	@doc
	cancel all previous subscriptions from interested party
	<code>n</code>.
    */
    virtual void	disconnect(Notifiable *)			= 0;

    /** @memo temporarily suspend the delivery of notifications 
	to a given subscriber.
	@param n subscriber 
	@doc
	<b>not yet implemented!</b>
    */
    virtual void	suspend(Notifiable *n)				= 0;
    /** @memo resume the delivery of notifications to a previously suspended subscriber.
	@param n subscriber 
	@doc
	<b>not yet implemented!</b>
    */
    virtual void	resume(Notifiable *)				= 0;
};

/** @memo Interested party
    @doc 

    A <code>Notifiable</code> represents an event consumer.  Events
    are delivered to a <code>Notifiable</code> by calling their
    <code>notify</code> method.  A <code>Notifiable</code> must
    specialize <code>notify</code> to implement its specific response
    to event notifications.
    <i>Example</i>:
    <pre>
    class Ticker : public Notifiable {
    virtual void notify(Event &e) { cout << e["price"].int_value() << endl; };
    }
    // ...
    Filter f;
    Ticker t;
    f.add_constraint("price", Siena_lt, 500);
    S->subscribe(f, t);
    // ...
    </pre>
*/
class Notifiable {
 public:
    /** @memo response to a notification
	@param e notified event
	@doc
	The event service calls this method to notify the interested
	party. The interested party specializes this method to
	implement its response to the event notification.
    */
    virtual void	notify(Event &e)				= 0;
};

/** @memo Type identifier for <em>Siena</em>
    @doc
    <em>Siena</em> has some of the most common data
    types. <code>SienaType</code> enumerates the available types in
    <em>Siena</em>.
    <p>
    <i>Example</i>:
    <pre>
    Event e;
    // ...
    SienaType t;
    t = e["quantity"].type();
    switch(t) {
    case Siena_integer: 
    // ...
    case Siena_string:
    // ...
    }
    </pre>
*/
enum SienaType {
//
// It might
// be better to program this as a class. This class would implement
// part of the ``matching'' functions as (possibly polymorphic)
// methods. The textual description would also be included in the
// ``type'' class.
//
// ...design choice...
// 

    /** undefined null type */
    Siena_null		= 0,
    /** string */
    Siena_string	= 1,
    /** signed integer number  */
    Siena_integer	= 2,
    /** boolean value */
    Siena_bool		= 3,
    /** time/date (<b><em>not yet implemented!</em></b>) */
    Siena_date		= 4,
    /** floating point number */
    Siena_double 	= 5,
    /** binary object (<b><em>not yet implemented!</em></b>) */
    Siena_binary	= 6
};

/** @memo Textual representation of <em>Siena</em> types identifiers 
    @doc
    strings representing type identifiers. Its values are
    <code>null</code>, <code>string</code>, <code>integer</code>,
    <code>boolean</code>, <code>data</code>, <code>float</code>, and
    <code>binary</code>. The mappings are obvious with respect to the
    values of <code>SienaType</code>, for example
    <code>SienaTypeDescription[Siena_bool] == "boolean"</code>.  */
extern const string	SienaTypeDescription[];

/** @memo value of an attribute in a notification
    @see Event SienaType

    @doc
    An <code>AttributeValue</code> stores the value of an
    attribute. Attributes can be of a pre-defined set of types
    (SienaType).  <code>AttributeValue</code> provides methods for
    accessing and assigning values in the form of C++ types.  In
    particular, an <code>AttributeValue</code> of type
    <code>Siena_integer</code> can be assigned to and from an
    <code>int</code>, an <code>AttributeValue</code> of type
    <code>Siena_string</code> can be assigned to and from a C++
    standard <code>string</code>, etc. 
    <p>

    <i>Example</i>:
    <pre>
    AttributeValue x, y;
    //
    // now x.type() == y.type() == Siena_null
    //
    x = true;
    y = x;
    //
    // now x.type() == y.type() == Siena_bool
    //
    int i = 10;
    if (x.bool_value()) y = i + 10;
    x = i + 20;
    cout &lt;&lt; x.int_value() + y.int_value() &lt;&lt; endl;
    i = x;
    y = "ciao";
    cout &lt;&lt; y.string_value() &lt;&lt; endl;
    </pre>
*/
class AttributeValue {
 public:
    
    /**@name Constructors */
    //@{
    /** <em>null</em> value */
			AttributeValue();
    /** copy constructor */
			AttributeValue(const AttributeValue &v);
    /** construct from a string */
			AttributeValue(const string &);
    /** construct from a C-style string */
			AttributeValue(const char *);
    /** construct from an <code>int</code> */
			AttributeValue(int);
    /** construct from a <code>bool</code> */
			AttributeValue(bool);
    /** construct from a <code>double</code> */
			AttributeValue(double);
    //@}
    //
    // more constructors here with the specific types
    // ... work in progress ... 
    //
		~AttributeValue();
    /**@name Access functions */
    //@{
    /** returns the actual type of this value */
    SienaType		type()					const;

    /** @memo returns a reference to the value as an integer
	@exception BadType exception is generated when
	           <code>type() != Siena_integer</code> 
	@doc 

	returns a reference to the value as an integer
	<p>
	<i>Example</i>:
	<pre>
	AttributeValue x = 20;
	cout << x.int_value();
	x.int_value()++;
	cout << x.int_value();
	</pre>
    */
    int	&		int_value();

    /** @memo returns a reference to the value as a boolean 
	@doc returns a reference to the value as a boolean 
	@exception BadType exception is generated when
	           <code>type() != Siena_bool</code> */
    bool &		bool_value();

    /** @memo returns a reference to the value as a string 
	@exception BadType exception is generated when
	           <code>type() != Siena_string</code>
		   
        @doc 
	returns a reference to the value as a string 
	<p>
	<i>Example</i>:
	<pre>
	AttributeValue x = "ciao";
	cout << x.string_value();
	x.string_value() += " ciao";
	cout << x.string_value();
	</pre>
    */
    string &		string_value();

    /** @memo returns a reference to the value as a double 
	@doc returns a reference to the value as a double 
	@exception BadType exception is generated when
	           <code>type() != Siena_double</code> */
    double &		double_value();
    /** @memo returns a reference to the value as an integer
	@doc returns a reference to the value as an integer
	@exception BadType exception is generated when
	           <code>type() != Siena_integer</code> */
    const int &		int_value()				const;
    /** @memo returns a copy of the value as a boolean 
	@doc returns a copy of the value as a boolean 
        @exception BadType exception is generated when
	           <code>type() != Siena_bool</code>  */
    const bool &	bool_value()				const;
    /** @memo returns a copy of the value as a boolean 
	@doc returns a copy of the value as a boolean 
        @exception BadType exception is generated when
	           <code>type() != Siena_bool</code>  */
    const string &	string_value()				const;
    /** @memo returns a copy of the value as a boolean 
	@doc returns a copy of the value as a boolean 
        @exception BadType exception is generated when
	           <code>type() != Siena_bool</code>  */
    const double &	double_value()				const;

    /** @memo conversion operator to <code>int</code>
        @exception BadType exception is generated when
	           <code>type() != Siena_int</code> 

	@doc 

	returns a copy of the value as an integer whenever the
	<code>AttributeValue</code> is used in place of an
	<code>int</code>. 
	<p>
	<i>Example</i>:
	<pre>
	AttributeValue x = 20;
	int i = x;
	</pre>
    */
			operator int ()				const;
    /** @memo conversion operator to <code>int</code>
        @exception BadType exception is generated when
	           <code>type() != Siena_string</code> 

	@doc 

	returns a copy of the value as a boolean whenever the
	<code>AttributeValue</code> is used in place of an
	<code>int</code>. 
	<p>
	<i>Example</i>:
	<pre>
	AttributeValue x = "Siena";
	string s = x;
	</pre>
    */
			operator string ()			const;
    /** @memo conversion operator to <code>bool</code>
        @exception BadType exception is generated when
	           <code>type() != Siena_bool</code> 

	@doc conversion operator to <code>bool</code>
    */
			operator bool ()			const;
    /** @memo conversion operator to <code>double</code>
        @exception BadType exception is generated when
	           <code>type() != Siena_double</code> 

	@doc conversion operator to <code>double</code>
    */
			operator double ()			const;
    //@}
    //
    // to be continued with other types ...
    //
    // usual operators implementing some or all of the operators defined
    // by the event service (subscription language)
    //
    /**@name Assignment operators */
    //@{
    /** copy */
    AttributeValue &	operator = (const AttributeValue &);
    /** from string */
    AttributeValue &	operator = (const string &);
    /** from C-style string */
    AttributeValue &	operator = (const char *);
    /** from int */
    AttributeValue &	operator = (int);
    /** from bool */
    AttributeValue &	operator = (bool);
    /** from double */
    AttributeValue &	operator = (double);
    //@}

    bool		operator == (const AttributeValue &)	const;
    bool		operator < (const AttributeValue &)	const;

 protected:
    SienaType		_type;
    union {
	string *	str;
	int		num;
	bool		bln;
	double		dbl;
	//
	// to be completed with all the `physical' representation of the
	// various data types defined by the event service, e.g.:
	// Date *	date;
	// ... work in progress ... 
	//
    };
};

//
// primitive representation of a notification and of a Siena
//
typedef map<string, AttributeValue> AttributeSet;

/** @memo service parameters for a Siena request
    @doc

    A <code>Request</code> serves as a specification of service
    parameters for subscriptions, publications etc.  Just like an
    <code>Event</code>, it is implemented as a set of named attributes
    (a standard C++ <code>map</code>). <p>

    <em>Siena</em> uses some well-known attributes from a
    <code>Request</code>. See SENP. */
class Request: public AttributeSet {
    //
    // this might include specific methods to set well-defined
    // parameters (such as priority, encryption, etc.). This stuff is
    // still future work. ...work in progress...
    //
};

/** @memo event notification
    @see AttributeSet
    @doc

    A notification in <em>Siena</em> is a set of named attributes.
    <code>Event</code> represents an event notification. Attribute
    <em>names</em> are standard C++ <code>string</code>s while
    attribute <em>values</em> are <code>AttributeValue</code>s. A
    <em>name</em> uniquely identifies an attribute in an
    <code>Event</code>.
    <p>

    An <code>Event</code> is implemented as a <code>map&lt;string,
    AttributeValue&gt;</code>, therefore All the functions of the
    standard <code>map</code> template can be used to manipulate an
    <code>Event</code>. For instance:
    
    <pre>
    Event e;
    // ...
    // prints out attribute names of e
    //
    for(Event::iterator i = e.begin(); i != e.end(); ++i) cout &lt;&lt; (*i).first;
    </pre>

    Of course, every operation on an <code>Event</code> can take
    advantage of the access functions and assignment operators of
    <code>AttributeValue</code>.

    <pre>
    Event e;

    e["stock"] = "XYZ";
    e["price"] = 12.34
    e["quantity"] = 567;

    int q = e["quantity"];
    </pre>

    The structure of names and types of an <code>Event</code> is
    completely arbitrary for <em>Siena</em>. In other words,
    <em>Siena</em> does not require any pre-defined attribute. It is
    up to applications to agree on sets of names, types, and semantics
    of attributes. */
class Event : public AttributeSet {
 public:
			Event();
			Event(const Event &);
};

/** @memo operator identifier for <em>Siena</em>

    @doc

    <em>Siena</em> defines some of the most common operators (or
    binary relations). <code>SienaOperator</code> is the type of
    operator identifiers.
*/
enum SienaOperator {
    /** equals */ 
    Siena_eq		= 1, 
    /** suffix
	@doc
	<em>x</em> <code>Siena_sf</code> <em>y</em> is true if <em>y</em> is a
	suffix of <em>x</em>.  For example, <code>"software" Siena_sf "ware" ==
	true</code>, while <code>"software" Siena_sf "w" ==
	false</code>. <code>Siena_sf</code> is defined for strings
	only. */
    Siena_sf		= 2,
    /** @memo prefix
	@doc prefix.
	<em>x</em> <code>Siena_pf</code> <em>y</em> is true if <em>y</em> is
	a prefix of <em>x</em>.  For example, <code>"software" Siena_pf
	"soft" == true</code>, while <code>"software" Siena_pf "of"
	== false</code>. <code>Siena_pf</code> is defined for strings
	only. */
    Siena_pf		= 3,
    /** @memo less than.
	@doc less than.
	Integers and doubles are ordered as usual, strings are sorted
	in lexicographical order. For booleans, <code>false</code>
	&lt; <code>true</code>.  */
    Siena_lt		= 4, 
    /** greater than */
    Siena_gt		= 5, 
    /** less or equal */
    Siena_le		= 6, 
    /** greater or equal */
    Siena_ge		= 7, 
    /** @memo <em>any</em> (don't care)
	@doc <em>any</em> (don't care) always <code>true</code>.
     */
    Siena_xx		= 8, 
    /** not equal */
    Siena_ne		= 9, 
    /** @memo contains substring
	@doc contains substring.
	<em>x</em> <code>Siena_ss</code> <em>y</em> is true if <em>y</em> is
	a substring of <em>x</em>.  For example, <code>"software"
	Siena_ss "war" == true</code>, while <code>"software"
	Siena_ss "hard" == false</code>. <code>Siena_ss</code> is
	defined for strings only. */
    Siena_ss		= 10 
};

extern const string	SienaOperatorDescription[];

/** @memo semantics of Siena operators: applies an operator to two values.

    @doc
    Applies an operator to two values.
    Note that Siena operators are all binary relations.
    Operands are applied in the given order, so
    <code>apply_operator(op, x, y)</code> evaluates <em>x op y</em>. For example:
    <code>apply_operator(Siena_lt, x, y)</code> corresponds to <em>x &lt; y</em>
    <p>

    This function implements some minimal type-conversion (or type
    compatibility). In practice, integers are always compatible to
    doubles.  The result in case of incompatible types does not depend
    on the actual values of <code>x</code> and <code>y</code>.
    Specifically, it is always <code>true</code> if <code>op ==
    Siena_xx</code> (don't care) or <code>op == Siena_ne</code> (not
    equal). Otherwise it's <code>false</code>. 

    Note also that some operators (relations) are defined over a
    limited set of types. In particular <code>Siena_pf</code>,
    <code>Siena_sf</code>, and <code>Siena_ss</code> are defined for
    strings (<code>Siena_string</code>) operators only.
 */
extern bool		apply_operator(SienaOperator op, 
				       const AttributeValue & x, 
				       const AttributeValue & y);

/** @memo attribute constraint
    @see AttributeValue
    @doc
    An <code>AttributeConstraint</code> represents a condition posed on
    an attribute value. It stores an operator plus a comparison value.  */
class AttributeConstraint: public AttributeValue {
 public:
    /** the constraint operator */
    SienaOperator	op;

    /** @memo default constructor

	@doc <code>op</code> defaults to <code>Siena_eq</code>, the
	comparison value is <em>null</em>. */
			AttributeConstraint();
    /** @memo construct from an <code>AttributeValue</code>
	@param v initializes the comparison value
	@doc <code>op</code> defaults to <code>Siena_eq</code>, the
	comparison value is initialized with <code>v</code>. 
    */
			AttributeConstraint(const AttributeValue & v);

    /** @memo construct from an <code>AttributeValue</code> and 
	a <code>SienaOperator</code>
	@param v initializes the comparison value
	@param o initializes the operator <code>op</code>
    */
			AttributeConstraint(const AttributeValue & v, 
					    SienaOperator o);
    /** copy constructor */
			AttributeConstraint(const AttributeConstraint & c);

    /** copy assignment */
    AttributeConstraint &	operator = (const AttributeConstraint & c);
    /** @memo assignment from an <code>AttributeValue</code> 
	@param v comparison value
	@doc assigns the comparison value using <code>Siena_eq</code>
	as the comparison operator */

    AttributeConstraint &	operator = (const AttributeValue & v);
    bool		operator == (const AttributeConstraint & c) const;

    /** @memo applies <code>this</code> constraint to an attribute value
	@param v value to verify against <code>this</code> constraint
	@doc applies <code>this</code> constraint to an attribute value
    */

    bool		apply_to(const AttributeValue & v);
};


/** @memo primitive representation of a filter */
typedef multimap<string, AttributeConstraint> ConstraintSet;

/** @memo expression filtering notifications
    @see AttributeConstraint
    @doc  

    A <code>Filter</code> represents a boolean expression to be
    evaluated against an <code>Event</code>. It consists of a set of
    constraints. Each constraint poses a condition on an attribute of
    the <code>Event</code>. A <code>Filter</code> can pose multiple
    constraints on the same attribute.
    <p>

    A <code>Filter</code> is implemented by means of a
    <code>multimap&lt;string, AttributeConstraint&gt;</code>,
    therefore a <code>Filter</code> can be manipulated using all the
    methods of a standard <code>multimap</code>. Two additional
    utility methods are provided to add constraints.  
*/
class Filter : public ConstraintSet {
 public:
			Filter();
			Filter(const Filter &);

			Filter &		reduce();

    Filter &		operator = (const Filter &);
    bool		operator == (const Filter &)		const;

    /** @memo adds a constraint to the <code>Filter</code> */
    iterator		add_constraint(const string &, 
				       SienaOperator, const AttributeValue &);

    /** @memo adds a constraint to the <code>Filter</code> */
    iterator		add_constraint(const string &, 
				       const AttributeConstraint &);
};

/** expression of filters matching a sequence of notifications 
    (<b>not yet implemented!</b>). */
class Pattern: public list<Filter> {
//
// a Pattern is simply a list of (event) filters. This might be
// changed in the future, requiring a more complex data structure
//
 public:
			Pattern();
			Pattern(const Pattern &);
};

/** generic exception */
class SienaException: public exception {
    /** C-style string representation of what went wrong */
    virtual const char *	what()				const;
};

/** exception: service unavailable */
class ServiceUnavailable: public exception {
    /** C-style string representation of what went wrong */
    virtual const char *	what()				const;
};

/** model exception */
class EventModelException: public SienaException {
    /** C-style string representation of what went wrong */
    virtual const char *	what()				const;
};

/** exception: attribute type mismatch */
class BadType: public EventModelException {
 public:
    /** wrong type */
    SienaType			type;

				BadType(SienaType);

    /** C-style string representation of what went wrong */
    virtual const char *	what()				const;
    virtual ostream &		printout(ostream &)		const;
};

/** exception operator mismatch */
class BadOperator: virtual public EventModelException {
public:
    /** wrong operator */
    SienaOperator		op;

				BadOperator(SienaOperator); 

    /** C-style string representation of what went wrong */
    virtual const char *	what()				const;
    virtual ostream &		printout(ostream &)		const;
};

/** exception: false filter (defines an empty set of events) */
class NullFilter: virtual public EventModelException {
public:
    /** attribute name */
    string			name;
    /** conflicting constraint */
    AttributeConstraint		af1;
    /** conflicting constraint */
    AttributeConstraint		af2;

				NullFilter(const AttributeConstraint &,
					   const AttributeConstraint &);
				NullFilter(const string &,
					   const AttributeConstraint &,
					   const AttributeConstraint &);

    /** C-style string representation of what went wrong */
    virtual const char *	what()				const;
    virtual ostream &		printout(ostream &)		const;
};

#ifndef NO_INLINE
#include <siena/Siena.icc>
#endif

#ifdef HAVE_CXX_NAMESPACE
};
#endif

#endif
