# -*- coding: utf-8 -*-
r"""Quantos jogadores cabem, quantos estao dentro, e o estado que a tela mostra.

TRES PROCESSOS PRECISAM DISTO e nenhum ve a memoria do outro:

    world_server    sabe quem esta no mundo, e quem publica a contagem
    channel_server  desenha "Selecao de canal" com Baixo/Medio/Alto/Cheio
    login_server    recusa quem chega com o mundo cheio

Por isso a contagem viaja num ficheiro. E a coisa mais simples que funciona entre processos
na mesma maquina, e nao obriga a mexer no banco por causa de um numero.

O CARIMBO DE TEMPO NAO E ZELO A MAIS. Sem ele, um world_server que morresse deixava o
numero cravado: a tela mostrava lotacao de um mundo em baixo e o login recusava toda a
gente -- incluindo quem fosse la ver o que se passava. Passado um minuto sem novidade, a
contagem vale ZERO, que e o lado seguro para falhar.
"""
import os
import time

CAPACIDADE = 10
"""Quantos jogadores cabem no canal. Pedido do jogador em 30/08: comecar por 10."""

FICHEIRO = os.path.join(os.path.dirname(os.path.abspath(__file__)), "online.txt")

SEGUNDOS_VALIDA = 60
"""Acima disto o carimbo e considerado velho e a contagem passa a zero."""

BAIXO, MEDIO, ALTO, CHEIO = 0, 1, 2, 3
"""Os quatro patamares do client, com ids de string seguidos:

    20618 Baixo    20619 Medio    20620 Alto    20621 Cheio

Foi isso que confirmou que o campo e um indice de 0 a 3, e nao um numero solto.
"""
NOMES = ("Baixo", "Medio", "Alto", "Cheio")


def publicar(quantos: int) -> None:
    """Escreve 'quantos carimbo'. Chamado pelo mundo a cada entrada e saida.

    Falha em silencio de proposito: nao ha razao para derrubar uma entrada no mundo porque
    o disco recusou uma escrita de vinte bytes.
    """
    try:
        with open(FICHEIRO, "w", encoding="ascii") as f:
            f.write("%d %d" % (max(0, int(quantos)), int(time.time())))
    except OSError:
        pass


def quantos_online() -> int:
    """A contagem publicada, ou 0 se nao houver ou estiver velha."""
    try:
        with open(FICHEIRO, encoding="ascii") as f:
            partes = f.read().split()
        n, carimbo = int(partes[0]), int(partes[1])
    except (OSError, ValueError, IndexError):
        return 0
    if time.time() - carimbo > SEGUNDOS_VALIDA:
        return 0
    return max(0, n)


def estado(online: int | None = None) -> int:
    """0 Baixo, 1 Medio, 2 Alto, 3 Cheio -- o `status_flag` da lista de canais.

    O jogador viu o defeito: *"Status Medio ... nosso nao ta funcionando pq se nao tem
    ninguem jogando era pra esta baixo"*. Estava cravado em 1, que e justamente o Medio.

    Os cortes sao por fraccao da lotacao, para nao ser preciso mexer aqui quando a
    CAPACIDADE mudar.

    CHEIO SO QUANDO ESTA MESMO CHEIO. Uma primeira versao dava Cheio aos 80 por cento, e com
    lotacao 10 isso punha "Cheio" com oito dentro e dois lugares livres -- a tela mentia e
    afastava gente sem razao.
    """
    if online is None:
        online = quantos_online()
    if online >= CAPACIDADE:
        return CHEIO
    fraccao = online / float(CAPACIDADE or 1)
    if fraccao >= 0.5:
        return ALTO
    if fraccao >= 0.2:
        return MEDIO
    return BAIXO


def ha_lugar(online: int | None = None) -> bool:
    """Se cabe mais um. Com a contagem em falta ou velha devolve True -- ver o cabecalho."""
    if online is None:
        online = quantos_online()
    return online < CAPACIDADE
