/* player-stats.m,
 *
 * This handles player's stats.  Status don't go into player class
 * because they get freed and will lose it.  Also stats need to be
 * carried over to the next level for campaigns.
 */

#include <allegro.h>
#include <assert.h>
#include "common.h"
#include "player-stats.h"
#include "seborrhea/seborrhea-font.h"


stats_t player_stats[MAX_PLAYERS];


void clear_stats_for_player(unsigned int pid)
{
    stats_t *s;
    int i;
    assert(pid < MAX_PLAYERS);
    s = &player_stats[pid];

    s->score = 0;
    s->cheated_death_count = 0;

    s->kills = 0;
    for (i = 0; i < NUM_KILL_RANGES_BUCKETS; i++)
	s->kill_bucket[i] = 0;

    s->crashes = 0;
    s->hits = 0;
    s->is_powerup_hog = TRIT_UNDETERMINED;
    s->powerups_gained = 0;
}

/*------------------------------------------------------------*/

enum KILL_BUCKET_STYLE {
    KILL_BUCKET_STYLE_EVEN = 0,
    KILL_BUCKET_STYLE_SHORT,
    KILL_BUCKET_STYLE_MEDIUM,
    KILL_BUCKET_STYLE_LONG,
    NUM_KILL_BUCKET_STYLES
};

static const char *kill_bucket_style_names[NUM_KILL_BUCKET_STYLES] = {
    "Even", "Short", "Medium", "Long"
};


const char *determine_favourite_killing_range(stats_t *s)
{
    int x, best_fitted_style;
    double normalized_buckets[NUM_KILL_RANGES_BUCKETS];
    double score, Delta, best_score;

    if (s->kills == 0)
	return "N/A";

    for (x = 0; x < NUM_KILL_RANGES_BUCKETS; x++)
	normalized_buckets[x] = (double)s->kill_bucket[x] / s->kills;

#if 0
    /* Even:
       y
       ^
       |___________	y = 1.0/NUM_KILL_RANGES_BUCKETS.
       |
       +---------->x */
    for (x = 0, score = 0.0; x < NUM_KILL_RANGES_BUCKETS; x++) {
	Delta = 1.0/NUM_KILL_RANGES_BUCKETS - normalized_buckets[x];
	score += SQ(Delta);
    }
    best_score = score;
    best_fitted_style = KILL_BUCKET_STYLE_EVEN;
#endif


    /* Short:
       y_
       | `\-._		y = -2.0/(NUM_KILL_RANGES_BUCKETS^2) * x + 2.0/NUM_KILL_RANGES_BUCKETS
       |      `-._
       +---------->x */
    for (x = 0, score = 0.0; x < NUM_KILL_RANGES_BUCKETS; x++) {
	Delta = -x * 2.0/SQ(NUM_KILL_RANGES_BUCKETS) + 2.0/NUM_KILL_RANGES_BUCKETS - normalized_buckets[x];
	score += SQ(Delta);
    }
    //if (score < best_score) {
    {
	best_score = score;
	best_fitted_style = KILL_BUCKET_STYLE_SHORT;
    }


    /* Medium:
       y   _^_		y =  4.0/(NUM_KILL_RANGES_BUCKETS^2) * x
       | _/   \_	y = -4.0/(NUM_KILL_RANGES_BUCKETS^2) * x + 4.0/NUM_KILL_RANGES_BUCKETS
       |/       \_
       +---------->x */
    for (x = 0, score = 0.0; x < NUM_KILL_RANGES_BUCKETS/2; x++) {
	Delta = x * 4.0/SQ(NUM_KILL_RANGES_BUCKETS) - normalized_buckets[x];
	score += SQ(Delta);
    }
    for (; x < NUM_KILL_RANGES_BUCKETS; x++) {
	Delta = -x * 4.0/SQ(NUM_KILL_RANGES_BUCKETS) + 4.0/NUM_KILL_RANGES_BUCKETS - normalized_buckets[x];
	score += SQ(Delta);
    }
    if (score < best_score) {
	best_score = score;
	best_fitted_style = KILL_BUCKET_STYLE_MEDIUM;
    }


    /* Long:
       y        _,
       |    _,-'	y =  2.0/(NUM_KILL_RANGES_BUCKETS^2) * x
       |_,-'
       +---------->x */
    for (x = 0, score = 0.0; x < NUM_KILL_RANGES_BUCKETS; x++) {
	Delta = x * 2.0/SQ(NUM_KILL_RANGES_BUCKETS) - normalized_buckets[x];
	score += SQ(Delta);
    }
    if (score < best_score) {
	best_score = score;
	best_fitted_style = KILL_BUCKET_STYLE_LONG;
    }

    return kill_bucket_style_names[best_fitted_style];
}

void draw_death_statusbar(BITMAP *dest, unsigned int pid)
{
#define TEXTOUT_R(dest,font,str,y,c)		[font putString:str To:dest X:dest->w-15 Y:y Colour:c Alignment:ALIGN_RIGHT]
#define DIGI_COL				0x40:0x80:0x20
#define TEXT_COL				0x40:0x40:0x40

    SebFont *status_font  = [base_sebum getSebumByName:"fonts/nano10"];
    SebFont *digital_font = [base_sebum getSebumByName:"fonts/digital2"];
    Sebum<SebImage> *status_bg;
    stats_t *s;
    int y;
    assert(dest && pid <= MAX_PLAYERS);

    status_bg = [base_sebum getSebumByName:"glue/statusbar-bg"];
    [status_bg drawTo:dest X:0 Y:0 W:dest->w H:dest->h];

    s = &player_stats[pid];

    /* Score */
    [status_font putString:"SCORE" To:dest X:5 Y:10 Colour:TEXT_COL];
    [digital_font putStringTo:dest X:dest->w-15 Y:22 Colour:DIGI_COL Alignment:ALIGN_RIGHT :"%d", s->score];

    /* Kills */
    [status_font putString:"KILLS" To:dest X:5 Y:40 Colour:TEXT_COL];
    [digital_font putStringTo:dest X:dest->w-15 Y:52 Colour:DIGI_COL Alignment:ALIGN_RIGHT :"%d", s->kills];

    /* Preferred Killing range.  */
    [status_font putString:"KILL RANGE" To:dest X:5 Y:70 Colour:TEXT_COL];
    TEXTOUT_R(dest, status_font, determine_favourite_killing_range(s), 82, TEXT_COL);

    y = 112;
    /* Miscellanious attributes. */
    [status_font putString:"ATTRIBUTES" To:dest X:5 Y:100 Colour:TEXT_COL];
    if (s->hits > 0 && 100 * s->crashes/s->hits > 50) {
	[status_font putString:"Suicidal" To:dest X:12 Y:y Colour:TEXT_COL];
	y += 12;
    }

    if (s->cheated_death_count > 0) {
	[status_font putString:"Cheated" To:dest X:12 Y:y   Colour:TEXT_COL];
	[status_font putString:"death"   To:dest X:26 Y:y+8 Colour:TEXT_COL];

	if (s->cheated_death_count == 1)
	    y -= 12;
	elif (s->cheated_death_count == 2)
	    TEXTOUT_R(dest, status_font, "twice", y+16, TEXT_COL);
	elif (s->cheated_death_count == 3)
	    TEXTOUT_R(dest, status_font, "thrice", y+16, TEXT_COL);
	else
	    [status_font putStringTo:dest X:dest->w-15 Y:y+16 Colour:TEXT_COL Alignment:ALIGN_RIGHT :"%d times", s->cheated_death_count];
	y += 28;
    }

    if ((num_players == 2) && (not player[0] || not player[1])) {
	if (s->is_powerup_hog == TRIT_UNDETERMINED) {
	    unsigned int total_powerups_collected = s->powerups_gained + player_stats[!pid].powerups_gained;

	    if (s->powerups_gained >= 3 &&
		s->powerups_gained >= 0.7 * total_powerups_collected)
		s->is_powerup_hog = TRIT_YES;
	    else
		s->is_powerup_hog = TRIT_NO;
	}

	if (s->is_powerup_hog) {
	    [status_font putString:"Powerup hog" To:dest X:12 Y:y Colour:TEXT_COL];
	    y += 12;
	}
    }

#undef TEXT_COL
#undef DIGI_COL
#undef TEXTOUT_R
}
