/*

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.

*/
#ifndef ARSERVERMAP_H
#define ARSERVERMAP_H

#include "Aria.h"
#include "ArServerBase.h"
#include "ArConfig.h"


class ArServerClient;

class ArMapInterface;

/**  @brief Service providing the contents of a map file to the client.
 *
 * A map can be provided from an ArMap object, or else the 
 * filename can be given in the global ArConfig object (see Aria::getConfig())
 * as "Map" in the "Files" section.  This handler can also be configured to 
 * only send "point" data, "line" data, or both kinds of data from the map.
 *
 * This service accepts the following data requests:
 * <ul>
 *  <li><code>getMapId</code>
 *  <li><code>getMapName</code>
 *  <li><code>getMap</code>
 *  <li><code>getGoals</code>
 *  <li><code>getMapBinary</code>
 *  <li><code>getMapMultiScans</code>
 * </ul>
 *
 * The following data types will also be broadcast to all clients to indicate
 * certain events:
 * <ul>
 *  <li><code>mapUpdated</code>
 *  <li><code>goalsUpdated</code>
 * </ul>
 *
 * The <code>getMapId</code> request replies with... TODO 
 * 
 * The <code>getMapName</code> request replies with a packet containing a 
 * NULL-terminated string containing the filename of the map, or an empty string
 * ("") if there is no map.
 *
 * The <code>getMap</code> request replies with a packet containing the map as
 * it appears in the map file (see the documentation for ArMap for the file
 * format).
 *
 * The <code>getGoals</code> request replies with a series of NULL-terminated
 * strings containing the names of the Goal objects in the map.
 *
 * The <code>getMapBinary</code> request replies with the map headers and
 * objects list (see ArMap for map file format) as text, but supplies point
 * "DATA" and/or "LINES" as an undelimited sequence of 2-byte integers. (In
 * the case of point data, each pair of integers is a point; for lines, each
 * sequence of four integers defines a line).  This binary representation of data
 * is more compact than the ASCII text representation.
 *
 * The <code>getMapMultiScans</code> request is similar to getMapBinary,
 * but it includes a list of the scan sources, along with the point and lines 
 * for each scan source in binary format.
 *
 * The <code>mapUpdated</code> packet is sent to all connected clients whenever
 * a new map is loaded or the map is changed.  The packet contains no data; the 
 * new map can be downloaded using one of the above requests.
 *
 * The <code>goalsUpdated</code> packet is sent to all connected clients
 * whenever the list of Goal objects changes in the map or a new map is loaded.
 * The packet contains no data; the new list of goals can be downloaded using 
 * <code>getGoals</code>, or by downloading the entire map.
 *
 */
class ArServerHandlerMap
{
public:
  enum DataToSend { LINES = 1, POINTS = 2, BOTH = 3 };
  /// Constructor
  AREXPORT ArServerHandlerMap(ArServerBase *server, 
                              ArMapInterface *arMap = NULL, 
			                        DataToSend dataToSend = BOTH);
  /// Destructor
  AREXPORT virtual ~ArServerHandlerMap();
  /// Loads the map from a file
  AREXPORT bool loadMap(const char *mapFile);
  /// Uses a map already loaded
  AREXPORT void useMap(ArMapInterface *mapObj, 
                       bool takeOwnershipOfMap = false);
  /// Gets the map object this is using
  AREXPORT ArMapInterface *getMap(void);

  /// Handles the request for the map ID.
  AREXPORT void serverGetMapId(ArServerClient *client,
                               ArNetPacket *packet);
  /// The command that gets the map name
  AREXPORT void serverGetMapName(ArServerClient *client,
				                         ArNetPacket *packet);
  /// The command that'll get the map itself
  AREXPORT void serverGetMap(ArServerClient *client,
			     ArNetPacket *packet);
  /// The command that gets the map, with the data in binary format for improved performance
  AREXPORT void serverGetMapBinary(ArServerClient *client,
				                           ArNetPacket *packet);

  /// Requests that the server send the map, including scan data for multiple sources if available.
  AREXPORT void serverGetMapMultiScans(ArServerClient *client,
				                               ArNetPacket *packet);

  /// Requests that the server send the map with the specified maximum features.
  AREXPORT void serverGetMapWithMaxCategory(ArServerClient *client,
				                                    ArNetPacket *packet);

  /// The command that'll get the goals
  AREXPORT void serverGetGoals(ArServerClient *client,
			                         ArNetPacket *packet);

  /// Sets which kind of data we send 
  AREXPORT void setDataToSend(DataToSend dataToSend) 
    { myDataToSend = dataToSend; }
  /// Gets which kind of data we send
  DataToSend getDataToSend(void) { return myDataToSend; }

protected:
  AREXPORT void handleCheckMap(ArServerClient *client, 
                               ArNetPacket *packet);

  AREXPORT void sendMapWithMaxCategory(ArServerClient *client,
				                               const char *maxCategory);

  AREXPORT bool processFile(void);
  AREXPORT void mapChanged(void);
  // internal function that is used to toss the map to the client
  AREXPORT void writeMapToClient(const char *line, ArServerClient *client);
 

  AREXPORT void writePointsToClient(int pointCount,
				    std::vector<ArPose> *points,
				    ArServerClient *client);

  AREXPORT void writeLinesToClient(int lineCount,
				    std::vector<ArLineSegment> *points,
				    ArServerClient *client);

  ArServerBase *myServer;
  bool myOwnMap;
  DataToSend myDataToSend;
  ArMapInterface *myMap;
  std::string myMapName;
  ArServerHandlerMap *myServerHandlerMap;

  bool myAlreadyLoaded;
  char myMapFileName[512];
  char myLastMapFile[1024];
  struct stat myLastMapFileStat;

  ArFunctor2C<ArServerHandlerMap, 
      ArServerClient *, ArNetPacket *> myGetMapIdCB;
  ArFunctor2C<ArServerHandlerMap, 
      ArServerClient *, ArNetPacket *> myGetMapNameCB;
  ArFunctor2C<ArServerHandlerMap, 
      ArServerClient *, ArNetPacket *> myGetMapCB;
  ArFunctor2C<ArServerHandlerMap, 
      ArServerClient *, ArNetPacket *> myGetMapBinaryCB;
  ArFunctor2C<ArServerHandlerMap, 
      ArServerClient *, ArNetPacket *> myGetMapMultiScansCB;
  ArFunctor2C<ArServerHandlerMap, 
      ArServerClient *, ArNetPacket *> myGetMapMaxCategoryCB;
  ArFunctor2C<ArServerHandlerMap, 
      ArServerClient *, ArNetPacket *> myGetGoalsCB;
  ArFunctor2C<ArServerHandlerMap, 
      ArServerClient *, ArNetPacket *> myCheckMapCB;
  ArRetFunctorC<bool, ArServerHandlerMap> myProcessFileCB;
  ArFunctorC<ArServerHandlerMap> myMapChangedCB;
};

#endif

