/**********************************************************************
 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
***********************************************************************/
#include <stdio.h>
#include <stdlib.h>

#include <player.h>
#include <unithand.h>
#include <civserver.h>
#include <map.h>
#include <maphand.h>
#include <mapgen.h>
#include <cityhand.h>
#include <cityturn.h>
#include <citytools.h>
#include <unit.h>
#include <city.h>
#include <player.h>
#include <tech.h>
#include <shared.h>
#include <plrhand.h>
#include <events.h>
#include <unitfunc.h>
#include <settlers.h>

/****************************************************************
...
*****************************************************************/

int city_got_barracks(struct city *pcity)
{
  return (city_affected_by_wonder(pcity, B_SUNTZU) ||
	  city_got_building(pcity, B_BARRACKS) || 
	  city_got_building(pcity, B_BARRACKS2) ||
	  city_got_building(pcity, B_BARRACKS3));
}

/**************************************************************************
...
**************************************************************************/

int can_sell_building(struct city *pcity, int id)
{

  return (city_got_building(pcity, id) ? (!is_wonder(id)) : 0);
}

/**************************************************************************
...
**************************************************************************/

enum city_tile_type get_worker_city(struct city *pcity, int x, int y)
{
  if ((x==0 || x==4) && (y == 0 || y == 4)) 
    return C_TILE_UNAVAILABLE;
  return(pcity->city_map[x][y]);
}

/**************************************************************************
...
**************************************************************************/
int is_worker_here(struct city *pcity, int x, int y) 
{
  if (x < 0 || x > 4 || y < 0 || y > 4 || ((x == 0 || x == 4) && (y == 0|| y==4))) {
    return 0;
  }
  return (get_worker_city(pcity,x,y)==C_TILE_WORKER); 
}

/**************************************************************************
...
**************************************************************************/

struct city *find_city_wonder(enum improvement_type_id id)
{
  return (find_city_by_id(game.global_wonders[id]));
}

/**************************************************************************
Locate the city where the players palace is located, (NULL Otherwise) 
**************************************************************************/

struct city *find_palace(struct player *pplayer)
{
  city_list_iterate(pplayer->cities, pcity) 
    if (city_got_building(pcity, B_PALACE)) 
      return pcity;
  city_list_iterate_end;
  return NULL;
}


/**************************************************************************
...
**************************************************************************/

int city_specialists(struct city *pcity)
{
  return (pcity->ppl_elvis+pcity->ppl_scientist+pcity->ppl_taxman);
}

/**************************************************************************
... v 1.0j code was too rash, only first penalty now!
**************************************************************************/
int content_citizens(struct player *pplayer) 
{
  int cities =  city_list_size(&pplayer->cities);
  int content = game.unhappysize;
  int basis   = game.cityfactor - (G_DEMOCRACY - pplayer->government);

  if (cities > basis) 
    content--;
  return content;
}

/**************************************************************************
...
**************************************************************************/

int get_temple_power(struct city *pcity)
{
  struct player *p=&game.players[pcity->owner];
  int power=1;
  if (get_invention(p, A_MYSTICISM)==TECH_KNOWN)
    power=2;
  if (city_affected_by_wonder(pcity, B_ORACLE)) 
    power*=2;
  return power;
}

/**************************************************************************
...
**************************************************************************/

int get_cathedral_power(struct city *pcity)
{
  struct player *p=&game.players[pcity->owner];
  int power = 3;
  if (get_invention(p, A_COMMUNISM) == TECH_KNOWN)
   power--;
  if (get_invention(p, A_THEOLOGY) == TECH_KNOWN)
   power++;
  return power;
}

/**************************************************************************
...
**************************************************************************/
int get_colosseum_power(struct city *pcity)
{
  int power = 3;
  struct player *p=&game.players[pcity->owner];
  if (get_invention(p, A_ELECTRICITY) == TECH_KNOWN)
   power++;
  return power;
}

/**************************************************************************
...
**************************************************************************/
int is_worked_here(int x, int y)
{
  return (map_get_tile(x, y)->worked >= 0); /* saves at least 10% of runtime CPU usage! */
}

int old_is_worked_here(int x, int y)
{
  struct player *pplayer;
  int my, i;
  int xx;

  x = map_adjust_x(x);
  for(i=0; i<game.nplayers; i++) {
    pplayer=&game.players[i];
    city_list_iterate(pplayer->cities, pcity) {

      my=y+2-pcity->y;
      if (0 <= my && my <5)
	for ( xx = 0; xx<5; xx++) 
	  if (map_adjust_x(pcity->x+xx-2) == x) 
	    if(get_worker_city(pcity, xx, my)==C_TILE_WORKER) return 1;
    }
    city_list_iterate_end;
  }
  return 0;
}

/**************************************************************************
x and y are city cords in the range [0;4]
**************************************************************************/
int can_place_worker_here(struct city *pcity, int x, int y)
{
  if ((x == 0 || x == 4) && (y == 0 || y == 4))
    return 0;
  if (x < 0  || x > 4 || y < 0 || y > 4)
    return 0;
  if (get_worker_city(pcity, x, y) != C_TILE_EMPTY)
    return 0;
  return  (map_get_known(pcity->x+x-2, pcity->y+y-2, city_owner(pcity))
    && !is_worked_here(map_adjust_x(pcity->x+x-2), pcity->y+y-2));
}

int food_weighting(int n)
{
  static int value[56] = { -1, 57, 38, 25, 19, 15, 12, 10, 9, 8, 7,
                         6, 6, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3,
                         2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
                         2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
  return(value[n]);
}

int city_tile_value(struct city *pcity, int x, int y, int foodneed, int prodneed)
{ /* by Syela, unifies best_tile, best_food_tile, worst_elvis_tile */
  int i, j, k;
  struct player *plr;

  plr = city_owner(pcity);

  i = get_food_tile(x, y, pcity);
  if (foodneed > 0) i += 9 * (MIN(i, foodneed));
/* *= 10 led to stupidity with foodneed = 1, mine, and farmland -- Syela */
  i *= food_weighting(MAX(2,pcity->size));
  
  j = get_shields_tile(x, y, pcity);
  if (prodneed > 0) j += 9 * (MIN(j, prodneed));
  j *= SHIELD_WEIGHTING * city_shield_bonus(pcity);
  j /= 100;
  k = get_trade_tile(x, y, pcity) * pcity->ai.trade_want *
      (city_tax_bonus(pcity) * (plr->economic.tax + plr->economic.luxury) +
       city_science_bonus(pcity) * plr->economic.science) / 10000;
  return(i + j + k);
}  

int worst_worker_tile_value(struct city *pcity)
{
  int x, y;
  int worst = 0, tmp;
  city_map_iterate(x, y) {
    if ((x !=2 || y != 2) && get_worker_city(pcity, x, y) == C_TILE_WORKER) {
      tmp = city_tile_value(pcity, x, y, 0, 0);
      if (tmp < worst || !worst) worst = tmp;
    }
  }
  return(worst);
}

int better_tile(struct city *pcity, int x, int y, int bx, int by, int foodneed, int prodneed)
{
  return (city_tile_value(pcity, x, y, foodneed, prodneed) >
          city_tile_value(pcity, bx, by, foodneed, prodneed));
}
/**************************************************************************
...
**************************************************************************/
int best_tile(struct city *pcity, int x, int y, int bx, int by)
{ /* obsoleted but not deleted by Syela */
  return (4*get_food_tile(x, y, pcity) +
          12*get_shields_tile(x, y, pcity) +
          8*get_trade_tile(x, y, pcity) >
          4*get_food_tile(bx, by, pcity) +
          12*get_shields_tile(bx, by, pcity) +
          8*get_trade_tile(bx, by, pcity) 
          );
}

/**************************************************************************
...
**************************************************************************/
int best_food_tile(struct city *pcity, int x, int y, int bx, int by)
{ /* obsoleted but not deleted by Syela */
  return (100*get_food_tile(x, y, pcity) +
          12*get_shields_tile(x, y, pcity) +
          8*get_trade_tile(x, y, pcity) >
          100*get_food_tile(bx, by, pcity) +
          12*get_shields_tile(bx, by, pcity) +
          8*get_trade_tile(bx, by, pcity) 
          );
}

/**************************************************************************
...
**************************************************************************/
int settler_eats(struct city *pcity)
{
  int eat=0;
  unit_list_iterate(pcity->units_supported, this_unit) {
    if (unit_flag(this_unit->type, F_SETTLERS)) {
      eat++;
      if (get_government(pcity->owner)>=G_COMMUNISM) {
        eat++;
      }
    }
  }
  unit_list_iterate_end;
  return eat;
}

/**************************************************************************
...
**************************************************************************/
int is_building_other_wonder(struct city *pc)
{
  struct player *pplayer = city_owner(pc);
  city_list_iterate(pplayer->cities, pcity) 
    if ((pc != pcity) && !(pcity->is_building_unit) && is_wonder(pcity->currently_building) && map_get_continent(pcity->x, pcity->y) == map_get_continent(pc->x, pc->y))
      return pcity->currently_building; /* why return 1? -- Syela */
  city_list_iterate_end;
  return 0;
}

/**************************************************************************
...
**************************************************************************/
int built_elsewhere(struct city *pc, int wonder)
{
  struct player *pplayer = city_owner(pc);
  city_list_iterate(pplayer->cities, pcity) 
    if ((pc != pcity) && !(pcity->is_building_unit) && pcity->currently_building == wonder)
      return 1;
  city_list_iterate_end;
  return 0;
}


/**************************************************************************
...
**************************************************************************/
void eval_buildings(struct city *pcity,int *values)
{
  int i, gov, tech;
  struct player *plr = city_owner(pcity);
  gov = get_government(pcity->owner);
  tech = (plr->research.researching != A_NONE);
    
  for (i=0;i<B_LAST;i++) {
    if (is_wonder(i) && can_build_improvement(pcity, i) && !built_elsewhere(pcity, i)) {
      if (wonder_obsolete(i))
	values[i]=1;
      else
	values[i]=99;
    } else
    values[i]=0;
  }
  
  if (gov <= G_COMMUNISM || pcity->size < 5) {
    if (can_build_improvement(pcity, B_GRANARY)) 
      values[B_GRANARY]=pcity->food_surplus*50;
  }
  if (can_build_improvement(pcity, B_SUPERMARKET))
    values[B_SUPERMARKET]=pcity->size*55;

  if (can_build_improvement(pcity, B_AQUEDUCT) && pcity->size > 6)
    values[B_AQUEDUCT]=pcity->size*125+pcity->food_surplus*50;
  if (can_build_improvement(pcity, B_SEWER) && pcity->size > 11)
    values[B_SEWER]=pcity->size*100+pcity->food_surplus*50;
  
  if (can_build_improvement(pcity, B_HARBOUR) && (pcity->size > 5)) 
    values[B_HARBOUR]=pcity->size*60;
  if (can_build_improvement(pcity, B_OFFSHORE) && 
      !can_build_improvement(pcity, B_HARBOUR))
    values[B_OFFSHORE]=pcity->size*60;
  
  if (can_build_improvement(pcity, B_MARKETPLACE)) 
    values[B_MARKETPLACE]=pcity->trade_prod*200;
  
  if (pcity->trade_prod > 15) 
    if (can_build_improvement(pcity, B_BANK)) 
      values[B_BANK]=pcity->tax_total*100;

    if (can_build_improvement(pcity, B_STOCK)) 
      values[B_STOCK]=pcity->tax_total*100;
  
  if (gov > G_COMMUNISM)
    if (can_build_improvement(pcity, B_SUPERHIGHWAYS)) 
      values[B_SUPERHIGHWAYS]=pcity->trade_prod*60;
  if (can_build_improvement(pcity, B_COURTHOUSE)) {
    if (gov != G_DEMOCRACY) 
      values[B_COURTHOUSE]=pcity->corruption*100;
    else 
      values[B_COURTHOUSE]=pcity->ppl_unhappy[4]*200+pcity->ppl_elvis*400;
  }
  if (tech) {
    if (can_build_improvement(pcity, B_LIBRARY)) 
      values[B_LIBRARY]=pcity->science_total*200;
    
    if (can_build_improvement(pcity, B_UNIVERSITY)) 
      values[B_UNIVERSITY]=pcity->science_total*101;
    
    if (can_build_improvement(pcity, B_RESEARCH)) 
      values[B_RESEARCH]=pcity->science_total*100;
  }
  if (can_build_improvement(pcity, B_AIRPORT))
    values[B_AIRPORT]=pcity->shield_prod*49;

  if (pcity->shield_prod >= 15)
    if (can_build_improvement(pcity, B_PORT))
      values[B_PORT]=pcity->shield_prod*48;

  if (pcity->shield_prod >= 5) {
    if (can_build_improvement(pcity, B_BARRACKS))
      values[B_BARRACKS]=pcity->shield_prod*50;

    if (can_build_improvement(pcity, B_BARRACKS2))
      values[B_BARRACKS2]=pcity->shield_prod*50;

    if (can_build_improvement(pcity, B_BARRACKS3))
      values[B_BARRACKS3]=pcity->shield_prod*50;
  }
  if (can_build_improvement(pcity, B_TEMPLE))
     values[B_TEMPLE]=pcity->ppl_unhappy[4]*200+pcity->ppl_elvis*600;

  if (can_build_improvement(pcity, B_COLOSSEUM))
    values[B_COLOSSEUM]=pcity->ppl_unhappy[4]*200+pcity->ppl_elvis*300;

  if (can_build_improvement(pcity, B_CATHEDRAL))
    values[B_CATHEDRAL]=pcity->ppl_unhappy[4]*201+pcity->ppl_elvis*300;

  if (!(tech && plr->economic.tax > 50)) {
    if (can_build_improvement(pcity, B_COASTAL))
      values[B_COASTAL]=pcity->size*36;
    if (can_build_improvement(pcity, B_CITY))
      values[B_CITY]=pcity->size*35;
  } 
  if (!(tech && plr->economic.tax > 40)) {
    if (can_build_improvement(pcity, B_SAM))
      values[B_SAM]=pcity->size*24;
    if (can_build_improvement(pcity, B_SDI))
      values[B_SDI]=pcity->size*25;
  }
  if (pcity->shield_prod >= 10)
    if (can_build_improvement(pcity, B_FACTORY)) 
      values[B_FACTORY]=pcity->shield_prod*125;

  if (city_got_building(pcity, B_FACTORY)) {
    
    if (can_build_improvement(pcity, B_HYDRO))
      values[B_HYDRO]=pcity->shield_prod*100+pcity->pollution*100;
    
    if (can_build_improvement(pcity, B_NUCLEAR))
      values[B_NUCLEAR]=pcity->shield_prod*101+pcity->pollution*100;
    
    if (can_build_improvement(pcity, B_POWER))
      values[B_POWER]=pcity->shield_prod*100;
  }

  if (can_build_improvement(pcity, B_MFG)) 
    values[B_MFG]=pcity->shield_prod*125;

  if (can_build_improvement(pcity, B_MASS)) 
    values[B_MASS]=pcity->pollution*(100+pcity->size);

  if (can_build_improvement(pcity, B_RECYCLING)) 
    values[B_RECYCLING]=pcity->pollution*(100+pcity->shield_prod);
    
  if (can_build_improvement(pcity, B_CAPITAL))
    values[B_CAPITAL]=pcity->shield_prod;
}

/**************************************************************************
...
**************************************************************************/
int do_make_unit_veteran(struct city *pcity, enum unit_type_id id)
{
  if (unit_flag(id,F_DIPLOMAT) && get_government(pcity->owner)==G_COMMUNISM)
    return 1;
  if (is_ground_unittype(id))
    return city_got_barracks(pcity);
  else if (is_water_unit(id))
    return (city_affected_by_wonder(pcity, B_LIGHTHOUSE) || city_got_building(pcity, B_PORT));
  else
    return city_got_building(pcity, B_AIRPORT);
  return 0;
}

/**************************************************************************
corruption, corruption is halfed during love the XXX days.
**************************************************************************/
int city_corruption(struct city *pcity, int trade)
{
  struct city *capital;
  int dist;
  int val;
  int corruption[]= { 12,8,20,24,20,0}; /* original {12,8,16,20,24,0} */
  if (get_government(pcity->owner)==G_DEMOCRACY) {
    return(0);
  }
  if (get_government(pcity->owner)==G_COMMUNISM) {
    dist=10;
  } else {
    capital=find_palace(city_owner(pcity));
    if (!capital)
      dist=36;
    else
      dist=min(36,map_distance(capital->x, capital->y, pcity->x, pcity->y));
  }
  if (get_government(pcity->owner) == G_DESPOTISM)
    dist = dist*2 + 3; /* yes, DESPOTISM is even worse than ANARCHY */
  
  val=(trade*dist*3)/(corruption[get_government(pcity->owner)]*10);

  if (city_got_building(pcity, B_COURTHOUSE) ||   
      city_got_building(pcity, B_PALACE))
    val /= 2;
  if (val >= trade && val)
    val = trade - 1;
  return(val); /* how did y'all let me forget this one? -- Syela */
}
  

int set_city_shield_bonus(struct city *pcity)
{
  int tmp = 0;
  if (city_got_building(pcity, B_FACTORY)) {
    if (city_got_building(pcity, B_MFG))
      tmp = 100;
    else
      tmp = 50;
  }

  if (city_affected_by_wonder(pcity, B_HOOVER) ||
      city_got_building(pcity, B_POWER) ||
      city_got_building(pcity, B_HYDRO) ||
      city_got_building(pcity,B_NUCLEAR))
    tmp *= 1.5;

  pcity->shield_bonus = tmp + 100;
  return (tmp + 100);
}

int city_shield_bonus(struct city *pcity)
{
  return pcity->shield_bonus;
}

/**************************************************************************
...
**************************************************************************/
int set_city_tax_bonus(struct city *pcity)
{
  int tax_bonus = 100;
  if (city_got_building(pcity, B_MARKETPLACE)) {
    tax_bonus+=50;
    if (city_got_building(pcity, B_BANK)) {
      tax_bonus+=50;
      if (city_got_building(pcity, B_STOCK)) 
	tax_bonus+=50;
    }
  }
  pcity->tax_bonus = tax_bonus;
  return tax_bonus;
}

int city_tax_bonus(struct city *pcity)
{
  return pcity->tax_bonus;
}

/**************************************************************************
...
**************************************************************************/
int set_city_science_bonus(struct city *pcity)
{
  int science_bonus = 100;
  if (city_got_building(pcity, B_LIBRARY)) {
    science_bonus+=50;
    if (city_got_building(pcity, B_UNIVERSITY)) {
      science_bonus+=50;
    }
    if ((city_affected_by_wonder(pcity, B_SETI) || city_got_building(pcity, B_RESEARCH)))
      science_bonus+=50;
  }
  if (city_affected_by_wonder(pcity, B_COPERNICUS)) 
    science_bonus+=50;
  if (city_affected_by_wonder(pcity, B_ISAAC))
    science_bonus+=100;
  pcity->science_bonus = science_bonus;
  return science_bonus;
}

int city_science_bonus(struct city *pcity)
{
  return pcity->science_bonus;
}

int wants_to_be_bigger(struct city *pcity)
{
  if (pcity->size < 8) return 1;
  if (city_got_building(pcity, B_SEWER)) return 1;
  if (city_got_building(pcity, B_AQUEDUCT) && pcity->size < 12) return 1;
  if (!pcity->is_building_unit) {
    if (pcity->currently_building == B_SEWER && pcity->did_buy == 1) return 1;
    if (pcity->currently_building == B_AQUEDUCT && pcity->did_buy == 1) return 1;
  } /* saves a lot of stupid flipflops -- Syela */
  return 0;
}

/*
 *  Units in a bought city are transferred to the new owner, units 
 * supported by the city, but held in other cities are updated to
 * reflect those cities as their new homecity.  Units supported 
 * by the bought city, that are not in a city square are deleted.
 * This is consistent with Civ2, but units just outside the bought
 * city are deleted rather than transferred as in Civ2.
 *
 * - Kris Bubendorfer <Kris.Bubendorfer@MCS.VUW.AC.NZ>
 */

void transfer_city_units(struct player *pplayer, struct player *pvictim, 
			 struct city *pcity, struct city *vcity){

  int x = vcity->x;
  int y = vcity->y;

  struct genlist_iterator myiter;

  printf("Transferring City Units to new owner");

  genlist_iterator_init(&myiter, &pvictim->units.list, 0);

  for(; ITERATOR_PTR(myiter); ITERATOR_NEXT(myiter)) {
    struct unit *vunit=(struct unit *)ITERATOR_PTR(myiter);

    /* Is unit in the city? */
    
    if(same_pos(vunit->x, vunit->y, x, y)){
      create_unit(pplayer, x, y, vunit->type, vunit->veteran,
		  pcity->id, vunit->moves_left);
      wipe_unit(0, vunit);
    }else{
      if(vunit->homecity == vcity->id){
	/* look up victim's cities and see if this unit is
	   in one of them */
	
	struct city* new_home_city = 
	  city_list_find_coor(&pvictim->cities, vunit->x, vunit->y);
	
	if(new_home_city){
	  /* unit is in another city: make that the new homecity */
	  
	  create_unit(pvictim, vunit->x, vunit->y, vunit->type, 
		      vunit->veteran, new_home_city->id, vunit->moves_left);

	}else{

	  /* 
	   * unit isn't in a city - Civ2 deletes it - seems like
	   * a good idea to prevent the city being immediately
	   * retaken.  We don't actually have to do anything here 
	   * as remove_city deletes all supported units.
	   */
	 
	  wipe_unit(0, vunit);
	  
	}
      }
    }
  }
}
