/*
 * Copyright (c) 1997 University of Southern California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by the Information Sciences
 *      Institute of the University of Southern California.
 * 4. Neither the name of the University nor of the Institute may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * @(#) $Header: /usr/src/mash/repository/vint/nam-1/agent.cc,v 1.14 1998/07/24 17:41:11 haoboy Exp $ (LBL)
 */

#include <stdlib.h>
#ifdef WIN32
#include <windows.h>
#endif
#include "netview.h"
#include "psview.h"
#include "node.h"
#include "feature.h"
#include "agent.h"
#include "edge.h"
#include "paint.h"
#include "monitor.h"
#include "sincos.h"

Agent::Agent(const char* name, double size) :
	Animation(0, 0),
	next_(0),
	size_(size),
	x_(0.),
	y_(0.),
	node_(0),
	features_(NULL),
	edge_(NULL),
	angle_(NO_ANGLE),
	anchor_(0),
	mark_(0)  
{
	label_ = new char[strlen(name) + 1];
	strcpy(label_, name);
	nn_ = atoi(name); /*XXX*/
	paint_ = Paint::instance()->thin();
}

float Agent::distance(float x, float y) const 
{
	return ((x_-x)*(x_-x) + (y_-y)*(y_-y));
}

void Agent::size(double s)
{
	size_ = s;
	update_bb();
}

void Agent::update_bb()
{
	double off = 0.5 * size_;
	/*XXX*/
	bb_.xmin = x_ - off;
	bb_.ymin = y_ - off;
	bb_.xmax = x_ + off;
	bb_.ymax = y_ + off;
}

void Agent::add_feature(Feature* f)
{
  f->next_ = features_;
  features_ = f;
}

Feature *Agent::find_feature(char *name) const
{
  /*given a feature, remove it from an agent's feature list*/
  Feature *ft;
  ft=features_;
  while (ft!=NULL)
    {
      if (strcmp(ft->name(), name)==0)
	return ft;
      ft=ft->next();
    }
  return NULL;
}
 

 
void Agent::delete_feature(Feature* r)
{
  /*given a feature, remove it from an agent's feature list*/
  Feature *f1, *f2;
  f1=features_;
  f2=features_;
  while ((f1!=r)&&(f1!=NULL))
    {
      f2=f1;
      f1=f1->next();
    }
  if (f1==r)
    {
      f2->next(f1->next());
      if (f1==features_)
	features_=f1->next();
    }
}
 

 
void Agent::label(const char* name, int anchor)
{
	delete label_;
	label_ = new char[strlen(name) + 1];
	strcpy(label_, name);
	anchor_ = anchor;
}

void Agent::drawlabel(View* nv) const
{
	/*XXX node number */
	if (label_ != 0)
		nv->string(x_, y_, size_, label_, anchor_);
}

void Agent::drawlabel(PSView* nv) const
{
	/*XXX node number */
	if (label_ != 0)
		nv->string(x_, y_, size_, label_, anchor_);
}

void Agent::reset(double)
{
	paint_ = Paint::instance()->thick();
}

void Agent::place(double x, double y)
{ 
	x_ = x;
	y_ = y;
	mark_ = 1;
	update_bb();
}

const char* Agent::info() const
{
	static char text[128];
	sprintf(text, "Agent: %s", label_);
	return (text);
}

const char* Agent::getname() const
{
	static char text[128];
	sprintf(text, "a %s", label_);
	return (text);
}

void Agent::monitor(Monitor *m, double now, char *result, int len)
{
  char buf[256];
  Feature *f;
  monitor_=m;
  sprintf(result, "Agent: %s", label_);
  for(f=features_;f!=NULL;f=f->next()) {
    strcat(result, "\n");
    f->monitor(now, buf, 255);
    if (strlen(result)+strlen(buf)<(unsigned int)len)
      strcat(result, buf);
    else {
      fprintf(stderr, "not enough space for monitor return string\n");
      return;
    }
  }
}

BoxAgent::BoxAgent(const char* name, double size) : Agent(name, size)
{
	BoxAgent::size(size);
}

void BoxAgent::size(double s)
{
	Agent::size(s);
	double delta = 0.5 * s;
	x0_ = x_ - delta;
	y0_ = y_ - delta;
	x1_ = x_ + delta;
	y1_ = y_ + delta;
	update_bb();
}

void BoxAgent::update_bb()
{
	bb_.xmin = x0_;
	bb_.ymin = y0_;
	bb_.xmax = x1_;
	bb_.ymax = y1_;
}

int BoxAgent::inside(double, float px, float py) const
{
	return (px >= x0_ && px <= x1_ &&
		py >= y0_ && py <= y1_);
}

void BoxAgent::draw(View* nv, double ) const
{
  nv->rect(x0_, y1_, x1_, y0_, paint_);
  if (label_ != 0)
    {
      nv->string((x0_+x1_)/2, y1_, size_*0.75, label_, ANCHOR_NORTH);
    }
  if (monitor_!=NULL)
    monitor_->draw(nv, (x0_+x1_)/2, y0_);
}

void BoxAgent::draw(PSView* nv, double ) const
{
  nv->rect(x0_, y1_, x1_, y0_, paint_);
  if (label_ != 0)
    {
      nv->string((x0_+x1_)/2, (y0_+y1_)/2, size_*0.75, label_, ANCHOR_CENTER);
    }
}

void BoxAgent::place(double x, double y)
{
  Agent::place(x, y);
  double nsin, ncos;
  SINCOSPI(angle_, &nsin, &ncos);
  height_=0.75;
  /*XXX should really use the X-display width*/
  width_=strlen(label_)/2;
  /* on solaris, sin(M_PI)!=0 !!!*/
  if ((nsin<1.0e-8)&&(nsin>-1.0e-9)) {
    y0_ = y_ - size_*0.5*height_;
    y1_ = y_ + size_*0.5*height_;
  } else if (nsin > 0) {
    y0_ = y_;
    y1_ = y_ + size_*height_;
  } else {
    y0_ = y_ - size_*height_;
    y1_ = y_;
  }
  if ((ncos<1.0e-8)&&(ncos>-1.0e-9)) {
    x0_ = x_ - size_*width_*0.5;
    x1_ = x_ + size_*width_*0.5;
  } else if (ncos > 0) {
    x0_ = x_;
    x1_ = x_ + size_*width_;
  } else {
    x0_ = x_ - size_*width_;
    x1_ = x_;
  }
  update_bb();
}
