// em-dirs.hh  stuff for picking directions

class Directions {
public:
  Directions(){};
  ~Directions(){};

  // class
  static int choice() {return(picked);}
  inline static void pick_safe();
  inline static void pick_sheltered();
  inline static void pick_new_sheltered();
  inline static void pick_forage();
  inline static int go_home();
  inline static void pick_mate();
  inline static void pick();
  inline static int go_fast();
  inline static int go();
  inline static int observe_predator();

private:
  static int picked;     // the next direction

  static int opposite[9];
  static int opleft[9], opright[9];
  static int left[9], right[9];
  inline static double dangerof(int direction);
}; // class Directions


// go the safest aprox. of opposite the most scary predator
// (we assume this was called to flee)  sets the variable "picked"
inline void Directions::pick_safe() {
  static int bad;
  static double op, or, ol;

  // small chance but...
  if (den_dir == SAME_SQUARE && max_den_perc_stimulus > CERTAIN) {
    picked = SAME_SQUARE; return;}
      
  if (max_p2_perc_stimulus > max_p1_perc_stimulus)
    bad = p2_dir;
  else
    bad = p1_dir;
  op = dangerof(opposite[bad]);
  or = dangerof(opright[bad]);
  ol = dangerof(opleft[bad]);
  if (op > or) {
    if (or > ol)
      picked = opleft[bad];
    else
      picked = opright[bad];
  } else {
    if (op > ol)
      picked = opleft[bad];
    else
      picked = opposite[bad];
  }
} // Directions::pick_safe


// go the safest aprox. of home -- assume nothing to run away
// from (we assume then we'd be fleeing)  sets the variable "picked"
inline int Directions::go_home() {
  static double dval, lval, rval;
  int den;

  if (max_den_perc_stimulus > TRIVIAL || 
      (max_den_perc_stimulus > max_den_memory_stimulus))
    den = den_dir;
  else
    den = remembered_den_dir;

  dval = dangerof(den) - shelter_perc_stim[den];
  rval = dangerof(right[den]) - shelter_perc_stim[den];
  lval = dangerof(left[den]) - shelter_perc_stim[den];
  if (dval > rval) {
    if (rval > lval)
      picked = left[den];
    else
      picked = right[den];
  } else {
    if (dval > lval)
      picked = left[den];
    else
      picked = den;
  }

  // we wouldn't have called this if we were home, so if we aren't
  // moving our perception is off.
  if (picked == SAME_SQUARE)
    return (LOOKING_AROUND);
  else
    return (go());

} // Directions::go_home

// go the safest aprox. of nearest mate -- assume nothing to run away
// from (we assume then we'd be fleeing)  sets the variable "picked"
// don't take a "big" risk here -- TWEAK
inline void Directions::pick_mate() {
  static double mval, lval, rval;

  mval = dangerof(mate_dir);
  if (mval < TRIVIAL) 
    picked = mate_dir;
  else {
    rval = dangerof(right[mate_dir]);
    lval = dangerof(left[mate_dir]);
    if (lval > rval && rval < TRIVIAL)
      picked = right[mate_dir];
    else if (lval < TRIVIAL)
      picked = left[mate_dir];
    else
      pick(); // try to stay out of the way of moving animals...
  }
} // Directions::pick_mate


// just combine stuff -- world doesn't look that hard that we have
// to be very clever, so take tyrrell's word for the combined solution stuff
// (sort of!)  note no mate -- we handle them seperately
inline void Directions::pick() {
  static int iii, max_dir;
  static double food_need, max, res;
  food_need = carbo_minus + protein_minus + fat_minus / 3;

  max = 0; max_dir = 0;
  // start from current square to avoid oscillating
  for (iii = 0; iii < 9; iii++)
    if (dangerof(iii) < TRIVIAL * AVOID) { // TWEAK 
      res =  food_perc_stim[iii] * food_need * 1.1
	+ water_perc_stim[iii] * water_minus 
	+ mate_perc_stim[iii]
	- an_temp_minus * shade_perc_stim[iii]
	+ an_temp_plus  * shade_perc_stim[iii]
	+shelter_perc_stim[iii] * shelter_perc_stim[iii] * SHELTER // TWEAK
	// can't do anything interesting at home!
	- den_perc_stim[iii] * den_perc_stim[iii]; 
      if (res > max) {
	max = res;
	max_dir = iii;
      }
    } // if danger (for iii)
  picked = max_dir; // will rest if surrounded by danger
} // Directions::pick()


// like pick but bias towards shelter and mate
inline void Directions::pick_sheltered() {
  static int iii, max_dir;
  static double food_need, max, res;
  food_need = carbo_minus + protein_minus + fat_minus / 3;

  max = 0; max_dir = 0;
  // start from current square to avoid oscillating
  for (iii = 0; iii < 9; iii++)
    if (dangerof(iii) < TRIVIAL * AVOID) { // TWEAK 
      res = mate_perc_stim[iii] +
	+shelter_perc_stim[iii] 
	- den_perc_stim[iii];
      if (res > max) {
	max = res;
	max_dir = iii;
      }
    } // if danger (for iii)
  picked = max_dir; // will rest if surrounded by danger
} // Directions::pick_sheltered()

// like pick-sheltered, but ignore present square (want to move)
inline void Directions::pick_new_sheltered() {
  static int iii, max_dir;
  static double food_need, max, res;
  food_need = carbo_minus + protein_minus + fat_minus / 3;

  max = 0; max_dir = 0;
  // start from current square to avoid oscillating
  for (iii = 1; iii < 9; iii++)
    if (dangerof(iii) < TRIVIAL * AVOID) { // TWEAK 
      res = mate_perc_stim[iii] +
	+shelter_perc_stim[iii] 
	- den_perc_stim[iii];
      if (res > max) {
	max = res;
	max_dir = iii;
      }
    } // if danger (for iii)
  picked = max_dir; // will rest if surrounded by danger
} // Directions::pick_new_sheltered()


// like pick but food or water sought
inline void Directions::pick_forage() {
  static int iii, max_dir;
  static double food_need, max, res;
  food_need = carbo_minus + protein_minus + fat_minus / 3;

  max = 0; max_dir = 0;
  // start from current square to avoid oscillating
  for (iii = 0; iii < 9; iii++)
    if (dangerof(iii) < TRIVIAL * AVOID) { // TWEAK 
      res =  food_perc_stim[iii] * food_need * 1.1
	+ water_perc_stim[iii] * water_minus
	+shelter_perc_stim[iii] * shelter_perc_stim[iii] * SHELTER // TWEAK
	// can't do anything interesting at home!
	- den_perc_stim[iii] * den_perc_stim[iii]; 
      if (res > max) {
	max = res;
	max_dir = iii;
      }
    } // if danger (for iii)
  picked = max_dir; // will rest if surrounded by danger
} // Directions::pick_forage()


// sum all the scary things (maybe scale these things later as TWEAK)
inline double Directions::dangerof(int dir) { 
  return (p2_perc_stim[dir] + p1_perc_stim[dir] + 
	  irr_perc_stim[dir] + edge_perc_stim[dir] +
	  dp_perc_stim[dir] - den_perc_stim[dir]);
} // Directions::dangerof

inline int Directions::go_fast() {
  switch(picked) {
  case (N): return(MOVE2_N);
  case (NE): return(MOVE2_NE);
  case (E): return(MOVE2_E);
  case (SE): return(MOVE2_SE);
  case (S): return(MOVE2_S);
  case (SW): return(MOVE2_SW);
  case (W): return(MOVE2_W);
  case (NW): return(MOVE2_NW);
  default:
    return (FREEZING);  // could throw error...
  } // switch
} // Directions::go_fast()

inline int Directions::go() {
  switch(picked) {
  case (N): return(MOVE_N);
  case (NE): return(MOVE_NE);
  case (E): return(MOVE_E);
  case (SE): return(MOVE_SE);
  case (S): return(MOVE_S);
  case (SW): return(MOVE_SW);
  case (W): return(MOVE_W);
  case (NW): return(MOVE_NW);
  default:
    return (RESTING);  // could throw error...
  } // switch
} // Directions::go()

inline int Directions::observe_predator() {
  static int dir;

  dir = (max_p2_perc_stimulus < max_p1_perc_stimulus) ? p1_dir : p2_dir;
  switch(dir) {
  case (N): return(LOOKING_N);
  case (NE): return(LOOKING_NE);
  case (E): return(LOOKING_E);
  case (SE): return(LOOKING_SE);
  case (S): return(LOOKING_S);
  case (SW): return(LOOKING_SW);
  case (W): return(LOOKING_W);
  case (NW): return(LOOKING_NW);
  default:
    return (LOOKING_AROUND);  // if there's a predator here we'd know it!
  } // switch
} // Directions::go()


