text: //*******************************************************************
  // Copyright (C) 2000 ImageLinks Inc. 
  //
  // License:  See top level LICENSE.txt file.
  //
  // Author: Garrett Potts
  //
  // Description:
  // 
  // Contains class declaration for ossimConnectableObject the base class for
  // all connectable objects.
  //
  //*************************************************************************
  // $Id$
  
  #ifndef ossimConnectableObject_HEADER
  #define ossimConnectableObject_HEADER 1
  
  #include <ossim/base/ossimConstants.h>
  #include <ossim/base/ossimObject.h>
  #include <ossim/base/ossimId.h>
  #include <ossim/base/ossimListenerManager.h>
  #include <ossim/base/ossimPropertyInterface.h>
  #include <ossim/base/ossimRefPtr.h>
  #include <vector>
  
  class ossimVisitor;
  class ossimConnectableContainer;
  
  class  OSSIMDLLEXPORT  ossimConnectableObject : public ossimObject,
                                                  public ossimListenerManager,
                                                  public ossimPropertyInterface
  {
  public:
     typedef std::vector<ossimRefPtr<ossimConnectableObject> > ConnectableObjectList;
     enum ossimConnectableObjectDirectionType
     {
        CONNECTABLE_DIRECTION_NONE   = 0,
        CONNECTABLE_DIRECTION_INPUT  = 1,
        CONNECTABLE_DIRECTION_OUTPUT = 2
     };
     /**
      * Base constructor of this object.
      */
     ossimConnectableObject(ossimObject* owner=0);
     ossimConnectableObject(ossimObject* owner,
                            ossim_int32 inputListSize,
                            ossim_int32 outputListSize,
                            bool inputListIsFixedFlag=true,
                            bool outputListIsFixedFlag=true);
  
     virtual ~ossimConnectableObject();
     /**
      * All connectable objects will have id's.  This allows us to
      * set the id of this object.
      */
     void setId(const ossimId& id);
  
     /**
      * Will allow us to get this object's id.
      */
     const ossimId& getId()const;
     
     /**
      * Fetches the current owner, most likely a container but not limited to one.
      */
     const ossimObject* getOwner() const;
  
     /**
      * Permits changing the object's owner.
      */
     virtual void changeOwner(ossimObject* owner);
  
     virtual void setDescription(const ossimString& description);
     virtual ossimString getDescription()const;
     
     /**
      * will check the direction specified to see if all slots are full.
      * If any slot is null then false is returned.
      * If a filter requires options testing they
      * need to override this method.  The argument can be ored together. If you
      * want both checked then pass
      * CONNECTABLE_DIRECTION_INPUT | CONNECTABLE_DIRECTION_OUTPUT
      */
     virtual bool isConnected(
        ossimConnectableObjectDirectionType direction = CONNECTABLE_DIRECTION_INPUT)const;
  
  
     /*!
      * These methods are now deprecated.  You can achieve the same thing by
      * using the new visitor design pattern.  If this does not achieve exactly
      * what you want then you can derive new rules by overriding the virtual
      * visit method in ossimVisitor
      *
      * <pre>
      *    ossimIdVisitor visitor(id, false, ossimVisitor::VISIT_CHILDREN |
      *    ossimVisitor::VISIT_INPUTS);
      *    connectableObject->accept(visitor);
      *    ossimRefPtr<ossimConnectableObject> object = visitor.getObject();
      * </pre>
      */
     OSSIM_DEPRECATE_METHOD(virtual ossimConnectableObject* findConnectableObject(
                               const ossimId& id));
  
     /*!
      * These methods are now deprecated.  You can achieve the same thing by
      * using the new visitor design pattern.  If this does not achieve exactly
      * what you want then you can derive new rules by overriding the virtual
      * visit method in ossimVisitor
      *
      * <pre>
      *    ossimTypeIdVisitor visitor(typeId, true, ossimVisitor::VISIT_CHILDREN |
      *    ossimVisitor::VISIT_INPUTS);
      *    connectableObject->accept(visitor);
      *    ossimRefPtr<ossimConnectableObject> object = visitor.getObject();
      * </pre>
      */
     OSSIM_DEPRECATE_METHOD(virtual ossimConnectableObject* findObjectOfType(
                               RTTItypeid typeId,
                               ossimConnectableObjectDirectionType directionType,
                               bool recurse = true));
  
     /*!
      * These methods are now deprecated.  You can achieve the same thing by
      * using the new visitor design pattern.  If this does not 
      * achieve exactly what you want then you can derive new rules by overriding
      * the virtual visit method in ossimVisitor
      *
      * <pre>
      *    ossimTypeNameVisitor visitor(typeName, true,
      *    ossimVisitor::VISIT_CHILDREN | ossimVisitor::VISIT_INPUTS);
      *    connectableObject->accept(visitor);
      *    ossimRefPtr<ossimConnectableObject> object = visitor.getObject();
      * </pre>
      */
     OSSIM_DEPRECATE_METHOD(virtual ossimConnectableObject* findObjectOfType(
                               const ossimString& obj,
                               ossimConnectableObjectDirectionType directionType,
                               bool recurse = true));
     
     /*!
      * These methods are now deprecated.  You can achieve the same thing by
      * using the new visitor design pattern.  If this does not 
      * achieve exactly what you want then you can derive new rules by overriding
      * the virtual visit method in ossimVisitor
      *
      * <pre>
      *    ossimTypeNameVisitor visitor(typeName, true,
      *    ossimVisitor::VISIT_CHILDREN | ossimVisitor::VISIT_INPUTS);
      *    connectableObject->accept(visitor);
      *    ossimRefPtr<ossimConnectableObject> object = visitor.getObject();
      * </pre>
      */
     OSSIM_DEPRECATE_METHOD(virtual ossimConnectableObject* findInputObjectOfType(
                               const ossimString& className));
     
     /**
      * Return a valid index of the input list if the passed in object
      * is found else return -1.
      */
     virtual ossim_int32 findInputIndex(const ossimConnectableObject* object);
  
     /**
      * Return a valid index of the input list if the passed id
      * is found else return -1.
      */
     virtual ossim_int32 findInputIndex(const ossimId& id);
  
     /**
      * Return a valid index of the output list if the passed in object
      * is found else return -1.
      */
     virtual ossim_int32 findOutputIndex(const ossimConnectableObject* object);
  
     /**
      * Return a valid index of the output list if the passed in object
      * is found else return -1.
      */   
     virtual ossim_int32 findOutputIndex(const ossimId& id);
     
     /**
      * Should return the first available index to connect to.  The
      * connectMyInputTo that just takes another ossimConnectableObject as input
      * and not an index will call this method.  By default this method will find
      * the first open slot (not null) or append o the list if it's dynamic. If
      * the list is dynamic it calls conConnectMyInputTo(index, object) on an
      * index = to listSize.
      */
     virtual ossim_int32 getMyInputIndexToConnectTo(
        ossimConnectableObject* object)const;
     
  
     /**
      * Should return the first available index to connect to.  The
      * connectMyOutputTo that just takes another ossimConnectableObject as input\
      * and not an index will call this method.  By default this method will find
      * the first open slot (not null) or append to the list if it's dynamic. If
      * the list is dynamic it calls canConnectMyOutputTo(index, object) on an
      * index = to listSize.
      */
     virtual ossim_int32 getMyOutputIndexToConnectTo(
        ossimConnectableObject* object)const;
     
     /**
      * required to be overriden by derived classes
      */
     virtual bool canConnectMyInputTo(
        ossim_int32 myInputIndex, const ossimConnectableObject* object)const=0;
     
     /**
      * default implementation is to allow anyone to connect to us.
      */
     virtual bool canConnectMyOutputTo(ossim_int32 myOutputIndex,
                                       const ossimConnectableObject* object)const;
     
     /**
      * Will disconnect the object passed in.
      */
     virtual void disconnect(ossimConnectableObject* object=0);
  
     /**
      * Will disconnect the object passed in.
      */
     virtual void disconnect(const ossimId& id);
     
     /**
      * Will disconnect the object at the given input index and generate
      * a connection event.
      */
     virtual ossimRefPtr<ossimConnectableObject> disconnectMyInput(
        ossim_int32 inputIndex,
        bool disconnectOutputFlag=true,
        bool createEventFlag = true);
     
    /**
     * Finds the index of the passed in input and calls
     * disconnectMyInput(inputIndex, disconnectOutputFlag, createEventFlag);
     */
     virtual void disconnectMyInput(ossimConnectableObject* input,
                                    bool disconnectOutputFlag=true,
                                    bool createEventFlag = true);
     /**
      *
      */
     virtual void disconnectMyInputs(
        ConnectableObjectList& inputList,
        bool disconnectOutputFlag=true,
        bool createEventFlag=true);
     
     /**
      * Will disconnect the object at the given output index and generate
      * a connection event.  If there is no object at that index then no
      * event is generated and NULL is returned.  The disconnectOutputFlag
      * says do you want this method to disconnect the output pointer to
      * this object.
      */
     virtual ossimRefPtr<ossimConnectableObject> disconnectMyOutput(
        ossim_int32 outputIndex,
        bool disconnectInputFlag=true,
        bool createEventFlag = true);
     
     /**
      * Will disconnect the output object.  It will get the index of
      * the object and call disconnectMyOutput(index, disconnectOutputFlag).
      */
     virtual void disconnectMyOutput(ossimConnectableObject* output,
                                     bool disconnectInputFlag=true,
                                     bool createEventFlag=true);
  
     virtual void disconnectMyOutputs(
        ConnectableObjectList& outputList,
        bool disconnectOutputFlag=true,
        bool createEventFlag=true);
     
     /**
      * Will disconnect all of the input objects.
      */
     virtual void disconnectAllInputs();
  
     /**
      * Will disconnect all of the output objects.
      */
     virtual void disconnectAllOutputs();
  
     /**
      * Will try to connect this objects input to the passed in object.
      * It will return a valid index >= 0 if successful.  Will use the
      * getMyInputIndexToConnectTo method to implement the connection
      */
     virtual ossim_int32 connectMyInputTo(ossimConnectableObject* inputObject,
                                          bool makeOutputConnection=true,
                                          bool createEventFlag=true);
  
     /**
      * Will connect the specified input to the passed in object
      */
     virtual ossim_int32 connectMyInputTo(ossim_int32 inputIndex,
                                          ossimConnectableObject* inputObject,
                                          bool makeOutputConnection=true,
                                          bool createEventFlag=true);
     
     virtual bool connectMyInputTo(
        ConnectableObjectList& inputList,
        bool makeOutputConnection=true,
        bool createEventFlag = true);   
  
     /**
      * Will try to connect this objects output to the passed in object.
      * It will return a valid index >= 0 if successful.  It will in turn call
      * the passed in objects connect input command if makeInputConnection
      * is set to true.
      *
      * Will use the getMyOutputIndexToConnectTo to implement this method
      */
     virtual ossim_int32 connectMyOutputTo(ossimConnectableObject* outputObject,
                                           bool makeInputConnection=true,
                                           bool createEventFlag=true);
     
     virtual bool connectMyOutputTo(
        ConnectableObjectList& outputList,
        bool makeInputConnection=true,
        bool createEventFlag=true);
     
     /**
      * Will disconnect itself from all inputs and reset to the passed in
      * input list.  It will return true if all objects were successfully
      * added.
      */
     virtual bool connectInputList(
        ConnectableObjectList& inputList);
     
     /**
      * Will disconnect itself from all outputs and reset to the passed in
      * output list.  It will return true if all objects were successfully
      * added.
      */
     virtual bool connectOutputList(
        ConnectableObjectList& outputList);
     
     /**
      * Returns the number of input objects.
      */
     virtual ossim_uint32 getNumberOfInputs()const;
  
     /**
      * Return the number of output objects
      */
     virtual ossim_uint32 getNumberOfOutputs()const;
     
     /**
      * returns the object at the specified index.
      * if the index is not valid then NULL is
      * returned
      */
     ossimConnectableObject* getInput(ossim_uint32 index=0);   
  
     /**
      * returns the object at the specified index.
      * if the index is not valid then NULL is
      * returned
      */
     const ossimConnectableObject* getInput(ossim_uint32 index=0)const;
  
     /**
      * returns the object at the specified index.
      * if the index is not valid then NULL is
      * returned
      */
     ossimConnectableObject* getOutput(ossim_uint32 index=0);
  
     /**
      * returns the object at the specified index.
      * if the index is not valid then NULL is
      * returned
      */
     const ossimConnectableObject* getOutput(ossim_uint32 index=0)const;
     
     /**
      * Will set the number of inputs.  This will expand the list if the number
      * of inputs is larger than the current number of inputs.  Will shrink
      * the list if the current number of inputs is larger than the passed in
      * inputs.
      */
     virtual void setNumberOfInputs(ossim_int32 numberOfInputs);
  
     virtual bool getInputListIsFixedFlag()const;
     
     virtual bool getOutputListIsFixedFlag()const;
  
     /**
      * Will set the number of outputs.  This will expand the list if the
      * number of outputs is larger than the current number of outputs.
      * Will shrink the list if the current number of outputs is larger than
      * the passed in outputs.
      */
     virtual void setNumberOfOutputs(ossim_int32 numberOfInputs);
     
     const ConnectableObjectList& getInputList()const;
  
     const ConnectableObjectList& getOutputList()const;
  
     ConnectableObjectList& getInputList();
  
     ConnectableObjectList& getOutputList();
  
     /*!
      * These methods are now deprecated.  You can achieve the same thing by
      * using the new visitor design pattern.  If this does not achieve exactly
      * what you want then you can derive new rules by overriding the virtual
      * visit method in ossimVisitor
      *
      * <pre>
      *    ossimTypeNameVisitor visitor("<put type name here>",
      *    false, ossimVisitor::VISIT_CHILDREN);
      *    connectableObject->accept(visitor);
      *    ossimCollectionVisitor::List& collection = visitor.getObjects();
      * </pre>
      */
      OSSIM_DEPRECATE_METHOD(virtual void findAllObjectsOfType(
                                ConnectableObjectList& result,
                                const RTTItypeid& typeInfo, bool recurse=true) );
      
     /*!
      * These methods are now deprecated.  You can achieve the same thing by
      * using the new visitor design pattern.  If this does not achieve exactly
      * what you want then you can derive new rules by overriding the virtual
      * visit method in ossimVisitor
      *
      * <pre>
      *    ossimTypeNameVisitor visitor("<put type name here>", false,
      *    ossimVisitor::VISIT_CHILDREN);
      *    connectableObject->accept(visitor);
      *    ossimCollectionVisitor::List& collection = visitor.getObjects();
      * </pre>
      */
     OSSIM_DEPRECATE_METHOD(virtual void findAllObjectsOfType(
                               ConnectableObjectList& result,
                               const ossimString& className,
                               bool recurse=true));
  
  #if 0 /* Deprecated code. Left here until thoroughly debugged. (drb) */
     /*!
      * These methods are now deprecated.  You can achieve the same thing by
      * using the new visitor design pattern.  If this does not 
      * achieve exactly what you want then you can derive new rules by overriding
      * the virtual visit method in ossimVisitor
      *
      * <pre>
      *    ossimTypeIdVisitor visitor(<put type id here>, false,
      *    ossimVisitor::VISIT_CHILDREN | ossimVisitor::VISIT_INPUTS);
      *    connectableObject->accept(visitor);
      *    ossimCollectionVisitor::List& collection = visitor.getObjects();
      * </pre>
      */
     OSSIM_DEPRECATE_METHOD(virtual void findAllInputsOfType(
        ConnectableObjectList& result,
        const RTTItypeid& typeInfo,
        bool propagateToInputs=true,
        bool recurseChildren=false));
     
     /*!
      * These methods are now deprecated.  You can achieve the same thing by
      * using the new visitor design pattern.  If this does not 
      * achieve exactly what you want then you can derive new rules by overriding
      * the virtual visit method in ossimVisitor
      *
      * <pre>
      *    ossimTypeNameVisitor visitor("<put type name here>",
      *    false, ossimVisitor::VISIT_CHILDREN | ossimVisitor::VISIT_INPUTS);
      *    connectableObject->accept(visitor);
      *    ossimCollectionVisitor::List& collection = visitor.getObjects();
      * </pre>
      */
     
     OSSIM_DEPRECATE_METHOD(virtual void findAllInputsOfType(
                               ConnectableObjectList& result,
                               const ossimString& className,
                               bool propagateToInputs=true,
                               bool recurseChildren=false));
  #endif  /* deprecated code. (drb) */
  
     virtual void propagateEventToOutputs(ossimEvent& event);
     virtual void propagateEventToInputs(ossimEvent& event);
  
     /* ------------------- PROPERTY INTERFACE -------------------- */
     virtual void setProperty(ossimRefPtr<ossimProperty> property);
     virtual void setProperty(const ossimString& name, const ossimString& value);
     virtual ossimRefPtr<ossimProperty> getProperty(const ossimString& name)const;
     virtual void getPropertyNames(std::vector<ossimString>& propertyNames)const;
     /* ------------------ PROPERTY INTERFACE END ------------------- */
  
     
     virtual bool loadState(const ossimKeywordlist& kwl,
                            const char* prefix = 0);
     
     virtual bool saveState(ossimKeywordlist& kwl,
                            const char* prefix = 0)const;
  
     /**
      * Save the state of all inputs to a keyword list.  This will do a
      * recursive call through all inputs and save their state to a
      * keyword list.
      *
      * @param kwl Keyword list to save state to.
      *
      * @param saveThisStateFlag If the true the state of this object will be
      * saved as well as all inputs. Default = true.
      *
      * @param  objectIndex Index to be used for prefix.  So if
      * objectIndex = 1, the first object will have a prefix of: "object1."
      * Default = 1.
      *
      * @param prefix Prefix to tack onto keyword.  If prefix = "myChain." and
      * objectIndex = 1, then the first keyword would be
      * "myChain.object1.some_keyword".
      *
      * @return Returns the next object index.  This is the last index used
      * plus one.  Used internally to keep track of index to use for prefix.
      */
     virtual ossim_uint32 saveStateOfAllInputs(ossimKeywordlist& kwl,
                                               bool saveThisStateFlag=true,
                                               ossim_uint32 objectIndex=1,
                                               const char* prefix=0) const;
  
     /**
      * Inserts this object and all of its children and inputs into the container
      * provided.
      * @return Returns TRUE if successful.
      */
     virtual bool fillContainer(ossimConnectableContainer& container);
  
     /**
      * Moves the input connection matching id up one in the connection list.
      * @param id The id to move.
      * @return true if action was performed, false if not.
      */
     bool moveInputUp(const ossimId& id);
  
     /**
      * Moves the input connection matching id down one in the connection list.
      * @param id The id to move.
      * @return true if action was performed, false if not.
      */
     bool moveInputDown(const ossimId& id);
  
     /**
      * Moves the input connection matching id to the top of the connection list.
      * @param id The id to move.
      * @return true if action was performed, false if not.
      */   
     bool moveInputToTop(const ossimId& id);
  
     /**
      * Moves the input connection matching id to the bottom of the connection
      * list.
      * @param id The id to move.
      * @return true if action was performed, false if not.
      */     
     bool moveInputToBottom(const ossimId& id);
     
     /**
      * We will add a visitor interface for all connectable objects.
      */
     virtual void accept(ossimVisitor& visitor);
     
  protected:
  
     ossimConnectableObject* findObjectOfType(
        ConnectableObjectList* connectableList,
        ossimVisitor& visitor );
     
     ossimId      theId;
     ossimString  theDescription;
     ossimObject* theOwner;
  
     /**
      * Indicates whether the theInputObjectList is fixed
      */
     bool theInputListIsFixedFlag;
  
     /**
      * Indicates whether the theOutputObjectList is fixed
      */
     bool theOutputListIsFixedFlag;
     
     /**
      * Holds a list of input objects.
      */
     ConnectableObjectList theInputObjectList;
     
     /**
      * Holds a list of output objects.
      */
     ConnectableObjectList theOutputObjectList;
  
  private:
  TYPE_DATA
  };
  
  #endif /* #ifndef ossimConnectableObject_HEADER */
  