/*

    Copyright (C) 1999-2000 Stefan Westerfeld
                       stefan@space.twc.de

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.
  
    This library 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 Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

module Arts {
// MCOP protocol

enum HeaderMagic { MCOP_MAGIC = 0x4d434f50 }; /* gets marshalled as "MCOP" */
											  /* decimal 1296256848 */                                                                                    
enum MessageType {
 mcopMessageInvalid		= 0,				  /* never send this */
 mcopServerHello		= 1,
 mcopClientHello		= 2,
 mcopAuthAccept			= 3,
 mcopInvocation			= 4,
 mcopReturn				= 5,
 mcopOnewayInvocation   = 6
};

/**
 * This type is sent as header of each MCOP message.
 */
struct Header {
	/**
	 * the value 0x504f434d, which is marshalled as MCOP
	 */
    HeaderMagic magic;
    long messageLength;
    MessageType messageType;
};

/**
 * This is sent as start of each normal (twoway) invocation
 */
struct Invocation {
	/**
	 * The ID of the object receiving the request
	 */
    long objectID;
	/**
	 * The ID of the method that is to be invoked
	 */
    long methodID;
	/**
	 * A unique number of the request (needed to send the return code back)
	 */
    long requestID;
};

/**
 * This is sent as start of each oneway invocation
 */
struct OnewayInvocation {
	/**
	 * The ID of the object receiving the request
	 */
    long objectID;
	/**
	 * The ID of the method that is to be invoked
	 */
    long methodID;
};

/**
 * Body of the mcopServerHello MCOP message
 */
struct ServerHello {
	string mcopVersion;
	string serverID;
	sequence<string> authProtocols;
	string authSeed;
};

/**
 * Body of the mcopClientHello MCOP message
 */
struct ClientHello {
	string serverID;
	string authProtocol;
	string authData;
};

/**
 * The message you get when you connect a MCOP server. The MCOP server can
 * send you some useful information here. Usually, it will send you
 *
 *   GlobalComm=<object reference of a global comm interface>
 *   InterfaceRepo=<object reference of an interface repository>
 *
 * But as this is called "hints" it doesn't necessarily need to happen.
 */
struct AuthAccept {
	sequence<string> hints;
};

/**
 * An object reference
 */
struct ObjectReference {
	/**
	 * A unique ID for the server the object is located on, (a server ID may
	 * i.e. be composed of start time, hostname, and pid)
	 */
	string serverID;

	/**
	 * The number of the object under that server
	 */
	long objectID;

	/**
	 * where the server holding object can be reached
	 */
	sequence<string> urls;
};

// Interface definitions

/**
 * The definition of a parameter of a method
 *
 * hints is reserved for future extensions, such as default, min and maxvalues
 */
struct ParamDef {
	string type;
	string name;
	sequence<string> hints;
};

/**
 * Twoway methods are such where the calling process does a call and is
 * suspended until some result (maybe even a void result) gets back.
 *
 * Oneway methods are one shot and forget methods: you send the invocation,
 * and continue. Maybe it will be received, maybe executed later. You will
 * never hear the result.
 */
enum MethodType {
	methodOneway = 1,
	methodTwoway = 2
};

/**
 * The definition of a method.
 *
 * hints is reserved for future extensions, such as default, min and maxvalues
 */
struct MethodDef {
	string     name;
	string     type;
	MethodType flags;

	sequence<ParamDef> signature;
	sequence<string>   hints;
};

/**
 * an attribute
 *
 * flags should contain things like
 *
 * @li attribute is readonly/writeonly/readwrite
 * @li attribute is incoming/outgoing stream
 * @li if it's a stream, it also should contain the information whether it is
 *     asynchronous or synchronous
 * @li NB20000320: see InterfaceDef for the meaning of streamDefault
 */
enum AttributeType {
  streamIn    = 1,
  streamOut   = 2,
  streamMulti = 4,
  attributeStream    = 8,
  attributeAttribute = 16,
  streamAsync = 32,
  streamDefault = 64
};

/**
 * The definition of an attribute and/or stream
 *
 * hints is reserved for future extensions, such as default, min and maxvalues
 */
struct AttributeDef {
	string  name;
	string  type;
	AttributeType flags;
	sequence<string>   hints;
};

/**
 * InterfaceDef - interface definition structure
 *
 * defines what methods/attributes a particular interface supports: these
 * do not contain the methods/attributes of inherited interfaces.
 *
 * inheritedInterfaces only contains the names of Interfaces that this one
 * inherits in exactly one step. So to see if interface XYZ is inherited
 * from ABC, you need to check the "inheritedInterfaces" of XYZ, and their
 * "inheritedInterfaces" and their "inheritedInterfaces" and so on.
 *
 * - NB20000320: defaultPorts allows to connect to those port by default if
 *               connection is made in the corresponding direction.
 *               It cannot be just an attribute flag because of the syntax
 *               on a separate line.
 *
 * hints is reserved for future extensions, such as default, min and maxvalues
 */

struct InterfaceDef {
	string name;

	sequence<string> inheritedInterfaces;
	sequence<MethodDef> methods;
	sequence<AttributeDef> attributes;
	
	sequence<string> defaultPorts;
	sequence<string> hints;
};

// Type definitions (struct's and such)

/**
 * One component of a struct
 *
 * hints is reserved for future extensions, such as default, min and maxvalues
 */
struct TypeComponent {
	string type;
	string name;
	sequence<string> hints;
};

/**
 * The definition of a struct
 *
 * hints is reserved for future extensions, such as default, min and maxvalues
 */
struct TypeDef {
	string name;

	sequence<TypeComponent> contents;
	sequence<string> hints;
};

/**
 * One item of an enum value
 *
 * hints is reserved for future extensions, such as default, min and maxvalues
 */
struct EnumComponent {
	string name;

	long value;
	sequence<string> hints;
};

/**
 * The definition of an enum
 *
 * hints is reserved for future extensions, such as default, min and maxvalues
 */
struct EnumDef {
	/**
	 * name if the enum, "_anonymous_" for anonymous enum - of course, when
	 * using namespaces, this can also lead to things like "Arts::_anonymous_",
	 * which would mean an anonymous enum in the Arts namespace
	 */
	string name;	

	sequence<EnumComponent> contents;
	sequence<string> hints;
};

/**
 * The contents of an idl file
 *
 * hints is reserved for future extensions, such as default, min and maxvalues
 */
struct ModuleDef {
	string moduleName;

	sequence<EnumDef> enums;
	sequence<TypeDef> types;
	sequence<InterfaceDef> interfaces;
	sequence<string> hints;
};

/**
 * The interface repository
 */
interface InterfaceRepo {
	/**
	 * inserts the contents of a module into the interface repository
	 *
	 * @returns an ID which can be used to remove the entry again
	 */
	long insertModule(ModuleDef newModule);

	/**
	 * removes the contents of a module from the interface repository
	 */
	void removeModule(long moduleID);

	/**
	 * queries the definition of an interface
	 */
	InterfaceDef queryInterface(string name);

	/**
	 * queries the definition of a type
	 */
	TypeDef queryType(string name);

	/**
	 * queries the definition of an enum value
	 */
	EnumDef queryEnum(string name);

	/**
	 * queries all interfaces that inherit a given interface
	 */
	sequence<string> queryChildren(string name);

	/**
	 * queries all interfaces
	 */
	sequence<string> queryInterfaces();

	/**
	 * queries all types
	 */
	sequence<string> queryTypes();

	/**
	 * queries all enums
	 */
	sequence<string> queryEnums();
};

enum TypeIdentification {
	tiUnknown = 0,
	tiVoid = 1,
	tiLong = 2,
	tiByte = 3,
	tiString = 4,
	tiBoolean = 5,
	tiFloat = 6,
	tiEnum = 128,
	tiType = 129,
	tiInterface = 130
};

interface InterfaceRepoV2 : InterfaceRepo {
	/**
	 * identifies whether a type is a primitive, enum, type or interface,
	 * or not known at all
	 */
	TypeIdentification identifyType(string name);
};

/**
 * Flow System interface
 */

/**
 * Internal use: implement distributed asynchronous streams.
 *
 * The FlowSystemSender object transmits the packets that should be sent
 * over the stream via _allocCustomMessage (Object_base).
 */
interface FlowSystemSender {
	/**
	 * This method is invoked whenever the receiver has finished processing
	 * a packet of the stream
	 */
	oneway void processed();

	/**
	 * This method is for telling the local FlowSystemSender to break the
	 * connection to the remote Receiver (it's not intended to be called
	 * remotely)
	 */
	void disconnect();
};

/**
 * Internal use: implement distributed asynchronous streams.
 *
 * The FlowSystemReceiver object receives and extracts the packets sent by
 * the sender object and injects them in the notification system again.
 */
interface FlowSystemReceiver {
	/**
	 * The custom message ID which should be used to send the stream packets
	 */
	readonly attribute long receiveHandlerID;

	/**
	 * This method is for telling the local FlowSystemReceiver to break the
	 * connection to the remote Sender (it's not intended to be called
	 * remotely)
	 */
	void disconnect();
};

/**
 * A flow system.
 *
 * Flow systems handle the streaming between MCOP objects. As this streaming
 * is network transparent (at least for asynchronous streams) they have this
 * remote interface.
 */
interface FlowSystem {
	/**
	 * This starts a scheduling node
	 *
	 * Don't use this manually. Use object->_node()->connect(...) instead.
	 */
	void startObject(object node);

	/**
	 * This stops a scheduling node
	 *
	 * Don't use this manually. Use object->_node()->connect(...) instead.
	 */
	void stopObject(object node);

	/**
	 * This connects two objects, maybe even remote
	 *
	 * it is important that
	 *  - sourceObject/sourcePort points to the node the signal flow is
	 *    coming from
	 *  - destObject/destPort points to the node/port the signal flow is
	 *    going to
	 *
	 * Don't use this manually. Use object->_node()->connect(...) instead.
	 */
	void connectObject(object sourceObject, string sourcePort,
						object destObject, string destPort);

	/**
	 * This disconnects two objects, maybe even remote
	 *
	 * it is important that
	 * @li sourceObject/sourcePort points to the node the signal flow is
	 *     coming from
	 * @li destObject/destPort points to the node/port the signal flow is
	 *     going to
	 *
	 * Don't use this manually. Use object->_node()->connect(...) instead.
	 */
	void disconnectObject(object sourceObject, string sourcePort,
		 					object destObject, string destPort);

	/**
	 * queries the stream flags - returns 0 when such a stream isn't
	 * present
	 */
	AttributeType queryFlags(object node, string port);

	/**
	 * directly sets an audio port to a fixed value
	 */
	void setFloatValue(object node, string port, float value);

	/**
	 * network transparent connections
	 */
	FlowSystemReceiver createReceiver(object destObject, string destPort,
												FlowSystemSender sender);
};

/**
 * A global communication space used to obtain initial object references
 *
 * MCOP needs a way to connect to initial (global) object references. This
 * is done by these global communication spaces.
 */
interface GlobalComm {
	/**
	 * puts a variable/value pair into the global communication
	 * space - it will not change the value of the variable if it is
	 * already present. Returns true if success, false if the variable
	 * was already there.
	 */
	boolean put(string variable, string value);

	/**
	 * gets the value of a variable out of the global communication
	 * space - it returns an empty string when the variable isn't there
	 */
	string get(string variable);

	/**
	 * removes a variable from the global communication space
	 */
	void erase(string variable);
};

/**
 * global communication based on the /tmp/mcop-<username> directory
 */
interface TmpGlobalComm : GlobalComm {
};

/*
 * Trading interfaces follow - trading is used to locate objects with certain
 * properties. This is especially recommended, if you want to allow that after
 * your code has been released, people can extend it, without changing your
 * code, by adding new components.
 */

/**
 * TraderOffer - this contains an offer of an object (which is usually returned
 * as result of a query.
 */
interface TraderOffer {
	/**
	 * You can use this interface name to create one of the objects that
	 * fulfill your query
	 */
	readonly attribute string interfaceName;

	/**
	 * This allows you to query additional information about the offer,
	 * such as the author of the plugin, the name of the library that
	 * implements it (if it is a library) or similar.
	 *
	 * Since some properties support having multiple values, this always
	 * returns a sequence<string>, which may be empty if the property isn't
	 * present at all.
	 */
	sequence<string> getProperty(string name);
};

/**
 * TraderQuery - this is a query against the trader. The idea is simple: you
 * say what you need, and the trader offers you components that do what you
 * want.
 */
interface TraderQuery {
	/**
	 * This restricts the query to only objects which support a "property"
	 * with the value "value". For instance, you could say
	 *
	 *   aquery.supports("Interface","Arts::PlayObject");
     *
	 * to restrict the matching objects to only those that support the
	 * interface Arts::PlayObject
	 */
	void supports(string property, string value);

	/**
	 * This performs the query, and returns a set of results
	 */
	sequence<TraderOffer> query();
};

/**
 * Arts::Object is the base object that every interface implicitely inherits
 *
 * it is also the source for generation of the Object_stub stuff
 * (use mcopidl -e Arts::Object to avoid code generation for this interface)
 */
interface Object {
	/**
	 * access to the flow system this object is running in
	 */
	readonly attribute FlowSystem _flowSystem;

	/**  <interface description>
	 * returns the ID for methodinvocations to this specific method
	 * methodID = 0  =>  _lookupMethod (always)
	 */
	long _lookupMethod(MethodDef methodDef);

	/**  <interface description>
	 * returns the name of the interface
	 * methodID = 1  =>  _interfaceName (always)
	 */
	string _interfaceName();

	/**  <interface description>
	 * returns the interface description to a given interface
	 * methodID = 2  =>  _queryInterface (always)
	 */
	InterfaceDef _queryInterface(string name);

	/**  <interface description>
	 * returns the type description to a given type
	 * methodID = 3  =>  _queryType (always)
	 */
	TypeDef _queryType(string name);

	/**  <interface description>
	 * returns the enum description to a given enum
	 * methodID = 4  =>  _queryEnum (always)
	 */
	EnumDef _queryEnum(string name);

	/**
	 * stringifies the object to one string
	 */
	string _toString();
	
	/**  <interface description>
	 * Run-time type compatibility check
	 */
	boolean _isCompatibleWith(string interfacename);

	/**  <reference counting>
	 * prepares object for remote transmission (so that it will not be freed
	 * soon, since the remote receiver expects it to be there after receiving
	 * it)
	 */
	void _copyRemote();

	/**  <reference counting>
	 * declares that the object is used remotely now (do that only after
	 * _copyRemote)
	 */
	void _useRemote();

	/**  <reference counting>
	 * declares that the object is no longer used remotely
	 */
	void _releaseRemote();

	/**  <aggregation>
	 * add a child object - this makes this object hold a strong reference to
	 * the child object (i.e. the child object will stay alive at least as
	 * long as the object does)
	 *
	 * if there is already a child with the same name, a postfix will be added
	 * automatically (i.e. if you add an object named "view" twice, the first
	 * will be called view, the second view1).
	 */
	string _addChild(object child, string name);

	/**  <aggregation>
	 * removes a child object 
	 */
	boolean _removeChild(string name);

	/**  <aggregation>
	 * gets a child object
	 */
	object _getChild(string name);

	/**  <aggregation>
	 * lists all children
	 */
	sequence<string> _queryChildren();
};

/**
 * a simple struct which can hold any other type
 */
struct Any {
	string type;
	sequence<byte> value;
};

/**
 * TraderEntries as produced by the loader
 */

struct TraderEntry {
	string interfaceName;
	sequence<string> lines;
};

/**
 * loader to load plugins (implemented in some language/binary format)
 */
interface Loader {
	object loadObject(TraderOffer offer);

	/*
	 * this is used for the type system to cache your trader data and
	 * module data as long as it stays unchanged
	 */
	readonly attribute string dataVersion;

	/*
	 * the trader entries of the components that can be loaded
	 */
	readonly attribute sequence<TraderEntry> traderEntries;

	/*
	 * the interface information of the components that can be loaded
	 */
	readonly attribute sequence<ModuleDef> modules;
};
 
};
