# -*- coding: utf-8 -*-
"""Compara o comportamento dos monstros entre o servidor OFICIAL e o NOSSO.

    python tools/comparar_mob.py
    python tools/comparar_mob.py <log_oficial> <log_nosso>

Sem argumentos usa as capturas correntes dos dois gravadores:

    C:\\RoshHook\\traffic.log    <- oficial  (AMo.exe, pasta C:\\Games\\Karos)
    C:\\RoshHook2\\traffic.log   <- nosso    (Axn.exe, pasta C:\\Games\\Axion)

As duas capturas passam pelo MESMO extrator, portanto a diferenca que aparecer e diferenca
de comportamento e nao de metodo de medida. Cada linha traz o valor dos dois lados e o erro
relativo; o que passar de DESVIO_GRITANTE leva marca.

Ler o resultado: uma linha com poucas amostras num dos lados nao quer dizer nada -- a coluna
`n` esta la para isso. Fase que o jogador nao provocou durante a gravacao sai vazia dos dois
lados, e isso e falta de dados, nao acordo.
"""
import os
import sys

sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "analise"))
import metricas as M                                                # noqa: E402

OFICIAL = "C:" + os.sep + "RoshHook" + os.sep + "traffic.log"
NOSSO = "C:" + os.sep + "RoshHook2" + os.sep + "traffic.log"
DESVIO_GRITANTE = 0.20      # 20 por cento

# (secao, chave, rotulo, unidade, casas)
LINHAS = [
    ("passeio", "corridas",     "trechos andados",        "",     0),
    ("passeio", "dt",           "intervalo entre passos", "s",    3),
    ("passeio", "passo",        "avanco por passo",       "u",    2),
    ("passeio", "velocidade",   "VELOCIDADE",             "u/s",  1),
    ("passeio", "dist_decl",    "distancia declarada",    "u",    2),
    ("passeio", "vel_decl",     "velocidade declarada",   "",     2),
    ("passeio", "giro",           "quanto VIRA entre passos",  "gr", 1),
    ("passeio", "giro_p90",       "virada dos 10% piores",     "gr", 1),
    ("passeio", "giro_recto_pc",  "passos em linha recta",      "%",  0),
    ("passeio", "solavanco",      "salto de velocidade",       "",   2),
    ("passeio", "arranque",       "arranque (1 = sem)",        "",   2),
    ("passeio", "duracao",      "duracao de um trecho",   "s",    1),

    ("perseguicao", "a_perseguir",         "cacadas",              "",    0),
    ("perseguicao", "dt",                  "intervalo entre passos", "s", 3),
    ("perseguicao", "passo",               "avanco por passo",     "u",   2),
    ("perseguicao", "velocidade",          "VELOCIDADE",           "u/s", 1),
    ("perseguicao", "dist_decl",           "distancia declarada",  "u",   2),
    ("perseguicao", "vel_decl",            "velocidade declarada", "",    2),
    ("perseguicao", "dur_perseguindo",     "duracao da cacada",    "s",   2),
    ("perseguicao", "dur_perseguindo_max", "cacada mais longa",    "s",   2),
    ("perseguicao", "distancia_percorrida", "quanto persegue",     "u",   1),
    ("perseguicao", "giro",           "quanto VIRA entre passos",  "gr", 1),
    ("perseguicao", "giro_p90",       "virada dos 10% piores",     "gr", 1),
    ("perseguicao", "giro_recto_pc",  "passos em linha recta",      "%",  0),
    ("perseguicao", "solavanco",      "salto de velocidade",       "",   2),
    ("perseguicao", "arranque",       "arranque (1 = sem)",        "",   2),
    ("perseguicao", "a_voltar",            "regressos ao poste",   "",    0),

    ("parado", "corridas",  "paragens",            "",  0),
    ("parado", "duracao",   "duracao de cada uma", "s", 2),

    ("combate", "golpes",      "golpes de mob",          "",  0),
    ("combate", "cadencia",    "intervalo entre golpes",  "s", 2),
    ("combate", "sessao",      "duracao de uma luta",     "s", 1),
    ("combate", "sessao_max",  "luta mais longa",         "s", 1),
    ("combate", "erro_rumo",   "erro do rumo do golpe",   "gr", 1),

    ("dano", "pacotes",         "pacotes de dano",           "", 0),
    ("dano", "rot_distintos",   "rotacoes distintas",        "", 0),
    ("dano", "rot_zeros_pc",    "rotacoes a zero",           "%", 0),
    ("dano", "rot_na_faixa_pc", "rotacoes dentro de 0..2pi", "%", 0),
]

TITULOS = {
    "passeio": "PASSEIO  (estado 0 -- o monstro a vaguear)",
    "perseguicao": "PERSEGUICAO  (estado 1 -- a correr atras do jogador)",
    "parado": "PARADO  (estado 2)",
    "combate": "COMBATE  (o 05 00 que o monstro manda)",
    "dano": "DANO AO MONSTRO  (o 05 02 que sai quando o jogador acerta)",
}


def fmt(v, casas):
    return ("%%.%df" % casas) % v


def main() -> int:
    of_cam = sys.argv[1] if len(sys.argv) > 2 else OFICIAL
    no_cam = sys.argv[2] if len(sys.argv) > 2 else NOSSO
    for cam, quem in ((of_cam, "oficial"), (no_cam, "nosso")):
        if not os.path.exists(cam):
            print("captura do %s nao existe: %s" % (quem, cam))
            return 1
        if os.path.getsize(cam) < 5000:
            print("captura do %s tem so %d bytes -- gravou alguma coisa?"
                  % (quem, os.path.getsize(cam)))

    print("oficial: %s  (%.1f MB)" % (of_cam, os.path.getsize(of_cam) / 1e6))
    print("nosso  : %s  (%.1f MB)" % (no_cam, os.path.getsize(no_cam) / 1e6))
    print()
    of = M.medir(M.carregar(of_cam))
    no = M.medir(M.carregar(no_cam))

    secao_atual = None
    gritantes = []
    for secao, chave, rotulo, unidade, casas in LINHAS:
        if secao != secao_atual:
            secao_atual = secao
            print()
            print(TITULOS[secao])
            print("  %-26s %12s %12s %10s" % ("", "OFICIAL", "NOSSO", "erro"))
            print("  " + "-" * 62)
        a = of.get(secao, {}).get(chave, 0.0)
        b = no.get(secao, {}).get(chave, 0.0)
        if a == 0 and b == 0:
            erro = "-"
        elif a == 0:
            erro = "so nosso"
        elif b == 0:
            erro = "so oficial"
        else:
            r = abs(b - a) / abs(a)
            erro = "%.0f%%" % (100 * r)
            if r > DESVIO_GRITANTE:
                erro += "  <<"
                gritantes.append((secao, rotulo, a, b, casas, unidade))
        rot = rotulo + (" (%s)" % unidade if unidade else "")
        print("  %-26s %12s %12s %10s" % (rot, fmt(a, casas), fmt(b, casas), erro))

    print()
    print("=" * 66)
    if not gritantes:
        print("Nada acima de %.0f%% de desvio." % (100 * DESVIO_GRITANTE))
    else:
        print("O QUE ESTA LONGE (mais de %.0f%%):" % (100 * DESVIO_GRITANTE))
        for secao, rotulo, a, b, casas, unidade in gritantes:
            print("   %-14s %-26s oficial %s   nosso %s %s"
                  % (secao, rotulo, fmt(a, casas), fmt(b, casas), unidade))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
