/*

ARIA header files for use with ARNL 1.7.1

Copyright(C) 2004, 2005 ActivMedia Robotics, LLC. 
Copyright(C) 2006, 2007, 2008, 2009 MobileRobots Inc.
All rights reserved.

This copy of Aria was relicensed for use with Arnl and the Arnl
license by MobileRobots Inc.  If you wish to download a seperate
distribution of Aria licensed under the GPL or a commercial license go to
http://www.mobilerobots.com/SOFTWARE/aria.html or contact MobileRobots
Inc, at robots@mobilerobots.com or MobileRobots Inc,
10 Columbia Drive, Amherst, NH 03031; 800-639-9481

MobileRobots Inc hereby grants to other individuals or
organizations permission to use this software with Arnl and in
compliance with the Arnl license.  This software may not be
distributed to others except by MobileRobots Inc.

MobileRobots Inc does not make any representations about the
suitability of this software for any purpose.  It is provided "as is"
without express or implied warranty.

*/
/*  \file ArMapObject.h
 *  \brief Contains the definition of the ArMapObject class.
 *  \date 06/27/08
 *  \author K. Cunningham
*/
#ifndef ARMAPOBJECT_H
#define ARMAPOBJECT_H
 
#include "ariaTypedefs.h"
#include "ariaUtil.h"

/// A point or region of interest in an Aria map.
/**
 * ArMapObject contains the data related to an Aria map object, i.e a point or
 * region of interest in an Aria map that is not part of the sensed obstacle 
 * data.  Examples of map objects include goals, docks, forbidden lines, and 
 * forbidden areas.  Applications may define their own custom ArMapObject types 
 * using the ArMap MapInfo mechanism.  See @ref ArMap for more information.
 * 
 * The basic attributes of an ArMapObject include the type of the map object,
 * an optional name of the object, and its position information.  As mentioned 
 * above, there are two basic categories of ArMapObjects:  
 *
 *  - Points:  A single ArPose in the map. By convention, if a map object
 *    can have an optional heading, then "WithHeading" appears at the end of 
 *    the object type when the heading is specified.  For example, "Goal" 
 *    designates an (x,y) location in the map (any heading or theta value should
 *    be ignored) and "GoalWithHeading" designates
 *    an (x,y,th) location.
 *
 *  - Regions: A set of two ArPoses ("from" and "to") which define a rectangle
 *    or a line.  Rectangles may have an associated rotation value. It is the
 *    rotation to be applied to the "from" and "to" poses <em> around
 *    the global origin </em>.  To retrieve the list of line segments that 
 *    comprise the rotated rectangle's perimeter, use the getFromToSegments()
 *    method.
 * 
 * Note that the ArMapObject is generally immutable.  If an object needs to be 
 * changed, then the original version should simply be replaced with a new one.  
 * See ArMap::getMapObjects(), ArMap::setMapObjects(), and ArMap::mapChanged().
 * 
**/
class ArMapObject
{
public: 

  /// Creates a new ArMapObject whose attributes are as specified in the given arguments
  /**
   * @param arg the ArArgumentBuilder * from which to create the ArMapObject; this
   * should correspond to a parsed line in the ArMap file
   * @return ArMapObject * the newly created map object, or NULL if an error 
   * occurred
  **/
  AREXPORT static ArMapObject *createMapObject(ArArgumentBuilder *arg);

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  // Instance Methods
  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  /// Constructor
  /**
   * @param type the char * type of the map object (e.g. "Goal", "ForbiddenLine");
   * must be non-empty
   * @param pose the primary ArPose of the map object; for points, this is its
   * location; for rectangles, this specifies the rotation of the rectangle (in
   * pose.getTh())
   * @param description an optional char * description of the object.
   * @param iconName char * currently unused
   * @param name the char * name of the map object; depending on the object type,
   * this may be optional or required
   * @param hasFromTo a bool set to true if the object is a region (i.e. line or
   * rectangle); false if the object is a point
   * @param fromPose the ArPose that defines the start point of the region object;
   * applicable only when hasFromTo is true
   * @param toPose the ArPose that defines the end point of the region object;
   * applicable only when hasFromTo is true
  **/
  AREXPORT ArMapObject(const char *type, 
                       ArPose pose, 
                       const char *description,
 		                   const char *iconName, 
                       const char *name,
 		                   bool hasFromTo, 
                       ArPose fromPose, 
                       ArPose toPose);

  /// Copy constructor
  AREXPORT ArMapObject(const ArMapObject &mapObject);

  /// Assignment operator
  AREXPORT ArMapObject &operator=(const ArMapObject &mapObject);

  /// Destructor
  AREXPORT virtual ~ArMapObject();

  // --------------------------------------------------------------------------
  // Text Attributes:
  // --------------------------------------------------------------------------

  /// Returns the type of the map object
  AREXPORT const char *getType(void) const;

  /// Returns the "base" (or root) type of the map object
  /**
   * If the map object type ends with "WithHeading", then the base is the
   * corresponding heading-less type.  For example, "GoalWithHeading" has a 
   * base type of "Goal".  
   * 
   * If the map object type does not end with "WithHeading", then the base 
   * is the same as the type.
  **/
  AREXPORT const char *getBaseType(void) const;

  /// Returns the name of the map object (if any)
  AREXPORT const char *getName(void) const;

  /// Returns the optional description of the map object
  AREXPORT const char *getDescription() const ;

  /// Returns the icon string of the object 
  /**
   * Reserved for future use
  **/
  AREXPORT const char *getIconName(void) const;

  /// Sets the description of the map object
  /**
   * This method really should only be called immediately after the object
   * is created, and before it is added to the map.  (Since the map object
   * isn't intended to be mutable.)  It exists for backwards compatibility.
  **/
  AREXPORT void setDescription(const char *description);


  // --------------------------------------------------------------------------
  // Position Attributes:
  // --------------------------------------------------------------------------

  /// Returns the primary pose of the object 
  /**
   * For points, this is the map object's location; for rectangles, this 
   * specifies the rotation of the rectangle (in getPose().getTh())
  **/
  AREXPORT ArPose getPose(void) const;

  /// Returns true if the map object has valid "from/to" poses (i.e. is a line or rectangle)
  AREXPORT bool hasFromTo(void) const;

  /// Returns the "from" pose for lines and rectangles; valid only if hasFromTo() 
  AREXPORT ArPose getFromPose(void) const;
  /// Returns the "to" pose for lines and rectangles; valid only if hasFromTo() 
  AREXPORT ArPose getToPose(void) const;

  /// Returns the optional rotation of a rectangle; or 0 if none
  /**
   * Note that this function doesn't know whether it actually makes sense 
   * for this map object to have the rotation.  (For example, it makes sense
   * on a ForbiddenArea but not a ForbiddenLine.)
   *
  **/
  AREXPORT double getFromToRotation(void) const;

  /// Gets a list of fromTo line segments that have been rotated
  /**
   * Note that this function doesn't know whether it actually makes sense 
   * for this map object to have the rotation.  (For example, it makes sense
   * on a ForbiddenArea but not a ForbiddenLine.)  This is just here so
   * that everyone doesn't have to do the same calculation.  Note that
   * this might be a little more CPU/Memory intensive transfering
   * these around, so you may want to keep a copy of them if you're
   * using them a lot (but make sure you clear the copy if the map
   * changes).  It may not make much difference on a modern processor
   * though (its set up this way for safety).
  **/
  AREXPORT std::list<ArLineSegment> getFromToSegments(void);

  /// Computes the center pose of the map object.
  /**
   * This method determines the center of map objects that have a "from" and a 
   * "to" pose (i.e. lines and rectangles).  For map objects that are poses, 
   * this method simply returns the pose.
  **/
  AREXPORT ArPose findCenter(void) const;

  // --------------------------------------------------------------------------
  // I/O Methods
  // --------------------------------------------------------------------------

  /// Returns the text representation of the map object
  /**
   * The returned string is suitable for writing to the ArMap file.  Note that
   * the string does NOT include the map object's optional parameters.
  **/
  AREXPORT const char *toString() const;

  /// Returns the text representation of the map object 
  /**
   * This method is equivalent to toString();
  **/
  const char *getStringRepresentation() const {
    return toString();
  }

  /// Writes the map object to the ArLog.
  /**
   * @param intro an optional string that should appear before the object
  **/
  AREXPORT void log(const char *intro = NULL);


  // --------------------------------------------------------------------------
  // Miscellaneous Methods
  // --------------------------------------------------------------------------

  /// Less than operator (for sets), orders by position
  AREXPORT bool operator<(const ArMapObject& other) const;


  /// Gets the fileName of the object (probably never used for maps)
  /**
  * This method is maintained solely for backwards compatibility.
  * It now returns the same value as getDescription (i.e. any file names
  * that may have been associated with an object can now be found in the
  * description attribute).
  * @deprecated 
  **/
  AREXPORT const char *getFileName(void) const;

private:

  /// Parses the given arguments and sets the description of the given ArMapObject
  static bool setObjectDescription(ArMapObject *object,
                                   ArArgumentBuilder *arg);

protected:

  /// The type of the map object
  std::string myType;
  /// If non-empty, then myType ends with "WithHeading" and this is the "root"
  std::string myBaseType;

  /// The name of the map object, if any
  std::string myName;
  /// The description of the map object
  std::string myDescription;

  /// For pose objects, THE pose; For rectangle objects, contains the optional rotation
  ArPose myPose;

  /// Reserved for future use
  std::string myIconName;

  /// Whether the map object is a region (line or rect) with "from/to" poses
  bool myHasFromTo;
  /// The "from" pose of a region map object; valid only if myHasFromTo is true
  ArPose myFromPose;
  /// The "to" pose of a region map object; valid only if myHasFromTo is true
  ArPose myToPose;

  /// For rectangle objects, the line segments that comprise the perimeter (even if rotated)
  std::list<ArLineSegment> myFromToSegments;
  
  /// Text representation written to the map file
  mutable std::string myStringRepresentation;

}; // end class ArMapObject


// =============================================================================

#ifndef SWIG
/// Comparator for two pointers to map objects
/** @swigomit */
struct ArMapObjectCompare : 
  public std::binary_function<const ArMapObject *,
                              const ArMapObject *,
                              bool> 
 {
   /// Returns true if obj1 is less than obj2; NULL pointers are greater than non-NULL
   bool operator()(const ArMapObject *obj1,
                   const ArMapObject *obj2)
   {
     if ((obj1 != NULL) && (obj2 != NULL)) {
       return *obj1 < *obj2;
     }
     else if ((obj1 == NULL) && (obj2 == NULL)) {
       return false;
     }
     else {
       return (obj1 == NULL);
     }
   } // end operator()

 }; // end struct ArMapObjectCompare

#endif //ifndef SWIG

#endif // ARMAPOBJECT_H

