/**************************************************************
 * FFTacticsMUD : group.cpp                                   *
 **************************************************************
 * (c) 2002 Damien Dailidenas (Trenton). All rights reserved. *
 **************************************************************/

#include "main.h"
#include <strstream>
#include <iomanip>

GROUP::~GROUP() {
  for(CH *m = people; m; m = m->next_in_group)
    m->group = NULL;

  return;
}

void do_join(CH *ch, string argument = "") {
  CH *pers;

  if(ch->group) {
    ch->printf("join: ERROR: You are already in a group.\n\r");
    return;
  }

  if(argument.empty() || !(pers = ch->get_ch_room(argument))) {
    ch->printf("Usage: join [player]\n\r");
    return;
  }

  if(!ch->can_group(pers)) {
    ch->printf("ERROR: Can't join " + pers->name + ".\n\r");
    return;
  }

  ch->following = pers;
  ch->room->echo(ch->name + " wants to join " + pers->name + "'s group.\n\r", ch, pers);
  pers->printf(ch->name + " wants to join your group.\n\r");
  ch->printf("You ask " + pers->name + " if you can join them.\n\r");
  return;
}

void do_group(CH *ch, string argument = "") {
  CH *pers;

  if(argument.empty() || !(pers = ch->get_ch_room(argument))) {
    ch->printf("Usage: group [player]\n\r");
    ostrstream ost, ost_CT;

    if(ch->group) {
      for(pers = ch->group->people; pers; pers = pers->next_in_group) {
	ost_CT.freeze(false);
	ost_CT.seekp(0, ios::beg);
	ost_CT << MAX(pers->CT, 100) << ends;
        ost << setw(12) << pers->name << "  Lv." << setw(2) << setfill('0') << pers->lvl << ENDL;
        ost << "Hp " << str_bar(pers->HP[0], pers->HP[1], C_B_CYAN) << setw(3) << setfill('0') << pers->HP[0] << '/' << setw(3) << setfill('0') << pers->HP[1] << "  ";
	ost << "Mp " << str_bar(pers->MP[0], pers->MP[1], C_B_YELLOW) << setw(3) << setfill('0') << pers->MP[0] << '/' << setw(3) << setfill('0') << pers->MP[1] << "  ";
	ost << "CT " << str_bar(pers->CT, 100, C_B_GREEN) << setw(3) << setfill('0') << (pers->battle ? ost_CT.str() : "---") << '/' << (pers->battle ? "100" : "---") << ENDL;
      }
    }

    ost << ends;
    ch->printf(ost.str());
    return;
  }

  if(!pers->following || pers->following != ch) {
    ch->printf("group: ERROR: " + pers->name + " hasn't asked to join your group.\n\r");
    return;
  }

  if(!pers->can_group(ch)) {
    ch->printf("ERROR: Can't group " + pers->name + ".\n\r");
    pers->following = NULL;
    return;
  }

  pers->join_group(ch);
  return;
}

void do_leave(CH *ch, string argument = "") {
  if(!ch->group) {
    ch->printf("leave: ERROR: You aren't in a group.\n\r");
    return;
  }

  ch->leave_group();
  return;
}

CH *GROUP::get_member(const string name) {
  for(CH *ch = people; ch; ch = ch->next_in_group)
    if(find(name, ch->name))
      return ch;

  return NULL;
}

void do_kick(CH *ch, string argument = "") {
  CH *pers;

  if(!ch->group) {
    ch->printf("kick: ERROR: You aren't in a group.\n\r");
    return;
  }

  if(ch->group->leader != ch) {
    ch->printf("kick: ERROR: You aren't the group leader.\n\r");
    return;
  }

  if(argument.empty() || !(pers = ch->group->get_member(argument))) {
    ch->printf("Usage: kick [group member]\n\r");
    return;
  }

  ch->printf("You kick " + pers->name + " out of your group.\n\r");
  pers->printf(ch->name + " kicks you out of " + ch->his_her() + " group!\n\r");
  ch->room->echo(ch->name + " kicks " + pers->name + " out of " + ch->his_her() + " group.\n\r", ch, pers);
  pers->leave_group();
  return;
}

void CH::join_group(CH *leader) {
  following = NULL;

  if(!leader->group) {
    GROUP *group = new GROUP;
    leader->group = group;
    group->leader = leader;
    leader->next_in_group = group->people;
    group->people = leader;
    leader->room->echo(leader->name + " forms a new group.\n\r");
  }
  
  room->echo(name + " joins " + leader->name + "'s group.\n\r");
  this->group = leader->group;
  this->next_in_group = this->group->people;
  this->group->people = this;
  return;
}

void CH::leave_group() {
  if(!group)
    return;

  if(this != group->leader)
    group->leader->printf(this->name + " leaves your group.\n\r");
  else
    group->leader->printf("You leave your group.\n\r");

  room->echo(name + " leaves " + group->leader->name + "'s group.\n\r", group->leader);

  if(group->members() > 2) {  
    if(group->leader == this && this != group->people) {
      printf("You take command!\n\r");
      room->echo(group->people->name + " takes command.\n\r", this);
      group->leader = group->people;
    }
  }
  else {
    group->leader->printf("Your group has been disbanded!\n\r");
    group->leader->room->echo(group->leader->name + "'s group has been disbanded!\n\r", group->leader);
  }

  if(this == group->people)
    group->people = next_in_group;
  else {
    for(CH *ch = group->people; ch; ch = ch->next_in_group) {
      if(ch->next_in_group == this) {
        ch->next_in_group = next_in_group;
        break;
      }
    }
  }
  
  if(group->members() < 2)
    zap(group);

  group = NULL;
  return;
}

short GROUP::members() {
  short x = 0;

  for(CH *m = people; m; m = m->next_in_group)
    ++x;

  return MIN(x, 1);
}

bool CH::can_group(const CH *ch) {
  return true;
}

short CH::get_group_cnt() {
  short x = 0;
  
  if(!group)
    return (status(status_dead) || status(status_bloodsuck) || status(status_petrify) ? 0 : 1);
      
  for(CH *ch = group->people; ch; ch = ch->next_in_group)
    if(!ch->status(status_dead) && !ch->status(status_bloodsuck) && !ch->status(status_petrify))
      ++x;
  
  return x;
}