/* bzflag
 * Copyright (c) 1993-2025 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

// Interface header
#include "ShotStatistics.h"

// Common headers
#include "TimeKeeper.h"
#include "playing.h"
#include "mathRoutine.h"

ShotStatistics::ShotStatistics() :
    totalFired(0), totalHit(0)
{
    lastShotTimeDelta = 0;
    lastShotTime = 0;
    lastShotDeviation = 0;
}

ShotStatistics::~ShotStatistics()
{
}

int ShotStatistics::getTotalPerc() const
{
    if (getTotalFired() == 0)
        return 0;
    return (int)(100 * ((float)getTotalHit() / (float)getTotalFired()));
}

void ShotStatistics::recordFire(FlagType* flag, const float *pVec, const float *shotVec )
{
    fired[flag]++;
    totalFired++;

    double currentTime = TimeKeeper::getCurrent().getSeconds();
    if (lastShotTime > 0)
        lastShotTimeDelta = currentTime-lastShotTime;
    lastShotTime = currentTime;

    float playerNorm[3];
    float shotNorm[3];
    float playerMag,shotMag;

    playerMag = sqrt((pVec[0]*pVec[0])+(pVec[1]*pVec[1])+pVec[2]*pVec[2]);
    shotMag = bzInverseSqrt(shotVec[0] * shotVec[0] +
                            shotVec[1] * shotVec[1] +
                            shotVec[2] * shotVec[2]);

    playerNorm[0] = pVec[0]/playerMag;
    playerNorm[1] = pVec[1]/playerMag;
    playerNorm[2] = pVec[2]/playerMag;
    shotNorm[0]   = shotVec[0] * shotMag;
    shotNorm[1]   = shotVec[1] * shotMag;
    shotNorm[2]   = shotVec[2] * shotMag;

    float dot = (shotNorm[0] * playerNorm[0]) + (shotNorm[1] * playerNorm[1]) + shotNorm[2] * playerNorm[2];

    lastShotDeviation = acosf(dot) * RAD2DEGf;

    if (getShotStats())
        getShotStats()->refresh();
}

void ShotStatistics::recordHit(FlagType* flag)
{
    hit[flag]++;
    totalHit++;

    if (getShotStats())
        getShotStats()->refresh();
}

typedef std::pair<FlagType*, float> FlagStat;

FlagType* ShotStatistics::getFavoriteFlag() const
{
    /* return the flag the player fired most */
    FlagType* greatest = Flags::Null;

    // we don't deal with the case where there are two "equally favorite"
    // flags; doesn't really matter
    for (auto it = fired.begin(); it != fired.end(); it++)
    {
        // ignore none/null - looking for favorite *flags*
        if (it->second > getFired(greatest) && it->first != Flags::Null)
            greatest = it->first;
    }

    return greatest;
}

FlagType* ShotStatistics::getBestFlag() const
{
    /* return the flag with the best hits/fired ratio */
    FlagType* greatest = Flags::Null;
    float greatestRatio = getHit(greatest)/float(getFired(greatest));

    // we don't deal with the case where there are two "equally best"
    // flags; doesn't really matter
    for (auto it = fired.begin(); it != fired.end(); it++)
    {
        float ratio = getHit(it->first)/float(it->second);

        // normal shots have the opportunity to be best
        if (ratio > greatestRatio)
        {
            greatest = it->first;
            greatestRatio = getHit(greatest)/float(getFired(greatest));
        }
    }

    return greatest;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 4 ***
// c-basic-offset: 4 ***
// indent-tabs-mode: nil ***
// End: ***
// ex: shiftwidth=4 tabstop=4
