//
// GLfloat rangeSensor(p)
// Last modified: 08Nov2009
//
// Returns with the distance from this robot
// to the position being auctioned.
//
// Returns:    the distance from this robot to the position being auctioned
// Parameters:
//      p      in/out   the packet (auction) to be processed
GLfloat Robot::rangeSensor(Packet &p)
{

    // unpack the auction from the packet
    Push_Auction_Announcement *aa = (Push_Auction_Announcement *)p.msg;

    // unpack the formation definition from the state within the auction
    Formation f = aa->s_i.formation;

    // get the range from the auctioneer to this robot
    GLfloat range = env->distanceToRobot(env->getCell(p.fromID), this);

    // if the auctioneer is beyond sensor range, do not bid
    if (range > SENSOR_RANGE) return -1.0f;

    // get the relative bearing from the auctioneer to this robot
    GLfloat bearing = bearingSensor(p.fromID);

    // get the angle between the auctioneer and the position being auctioned
    GLfloat ang = atan2(f.getFunction()(f.getRadius()), f.getRadius()) -
                  bearing;

    // get the vector between the auctioneer and this robot
    Vector d = (*(Vector *)this) - (*(Vector *)env->getCell(p.fromID));

    // get the vector between the auctioneer and the position being auctioned
    Vector e;
    e.y = f.getFunction()(f.getRadius());
    e.x = sqrt((f.getRadius() * f.getRadius()) - (e.y * e.y));

    // get the vector between the position being auctioned and this robot
    Vector a;
    if (aa->right)    // if the position is to the right of the auctioneer
        a = d - e;
    else
        a = d + e;

    // range is the magnitude of the vector between
    // the position being auctioned and this robot
    range = a.magnitude();

    //cout << "robot " << getID() << " bidding " << range << endl;

    return range;
}   // rangeSensor(Packet &)
//
// bool initCells(n, f)
// Last modified: 28Aug2006
//
// Initializes each cell to the parameterized values,
// returning true if successful, false otherwise.
//
// Returns:     true if successful, false otherwise
// Parameters:
//      n           in      the initial number of cells
//      f           in      the initial formation
//
bool Environment::initCells(const GLint n, const Formation f)
{
    srand(time(NULL));
    for (GLint i = 0; i < n; ++i) if (!addCell()) return false;

    // initialize each robot's neighborhood
    if (!initNbrs()) return false;

    // organizes the cells into an initial formation (default line)
    Cell *c  = NULL;
    for (GLint i = 0; i < getNCells(); ++i)
    {
        if (!cells.getHead(c)) return false;
        c->x = f.getRadius() *
               ((GLfloat)i - (GLfloat)(getNCells() - 1) / 2.0f);
        c->y = 0.0f;
        c->setColor(DEFAULT_ROBOT_COLOR);
        c->setHeading(f.getHeading());
        ++cells;
    }
    return (getNCells() == n) &&
           sendMsg(new Formation(f), f.getSeedID(),
                   ID_OPERATOR,      CHANGE_FORMATION);
}   // initCells(const GLint, const Formation f)
// simulation global constants
const GLfloat   SELECT_RADIUS     = 1.5f * DEFAULT_ROBOT_RADIUS;
const GLint     N_CELLS           = 0;
const GLint     MIDDLE_CELL       = 0;//(N_CELLS - 1) / 2;
const Formation DEFAULT_FORMATION = Formation(formations[0],
                                    DEFAULT_ROBOT_RADIUS *
                                    FACTOR_COLLISION_RADIUS,
                                    Vector(), MIDDLE_CELL, 0,
                                    90.0f);



// simulation global variables
Environment *g_env           = NULL;
GLint        g_nRobots       = 0;
GLfloat      g_fRadius       = DEFAULT_FORMATION.getRadius();
GLint        g_sID           = DEFAULT_FORMATION.getSeedID();
GLint        g_fID           = DEFAULT_FORMATION.getFormationID();
GLfloat      g_fHeading      = DEFAULT_FORMATION.getHeading();
GLint        g_fIndex        = 0;
GLint        g_selectedIndex = g_sID;
GLint        g_dt            = 50;    // time interval (in milliseconds)
bool         g_prop_toggle   = false;



//
// GLint main(argc, argv)
// Last modified:   04Sep2006
//
// Uses the OpenGL Utility Toolkit to set the