/*
 * MIT License
 * Author: Mark Allyn
 *
 * scope_ppi.h — abstract base for all PPI (Plan Position Indicator) scopes.
 *
 * Handles everything common to every PPI scope:
 *   - Phosphor FBO (P7 decay, ping-pong rendering)
 *   - Incandescent bearing graticule
 *   - Left description panel
 *   - Cursor (arc + bearing line, yellow)
 *   - Cursor bearing / range controls  (r/l/t/y)
 *   - Display bearing-offset controls  (k/j)
 *   - Gain and clutter controls        (1/2/3/4/5/6)
 *   - Sweep-angle integration from elapsed time
 *   - Held-key acceleration model
 *
 * Derived classes supply:
 *   - Max range and range-ring geometry (pure virtual)
 *   - u/d key handling for their range steps
 *   - Left-panel description lines
 *   - Target data (polled from TargetBuffer each sweep)
 */

#pragma once
#include <unordered_map>
#include <string>
#include <vector>
#include "scope.h"
#include "phosphor.h"
#include "graticule.h"
#include "left_panel.h"

class PPIScope : public Scope {
public:
    PPIScope(SharedRenderState& srs, TargetBuffer& tb, TextRenderer& tr,
             float sweepPeriodSec)
        : Scope(srs, tb, tr), panel_(tr), sweepPeriod_(sweepPeriodSec) {}

    bool        init(const std::string& shaderDir) override;
    void        render(float dt, float viewportW, float viewportH) override;
    void        handleKey(int key, int scancode, int action, int mods) override;

protected:
    // ---- Derived class overrides ----

    // Current full-scale range in metres.
    virtual float maxRangeM() const = 0;

    // Normalised ring radii for current range setting (values 0-1).
    virtual const float* ringRadii()  const = 0;
    virtual int          ringCount()  const = 0;

    // Range-specific keys (u/d); called from handleKey().
    virtual void handleKeyRange(int key, int action) = 0;

    // Text lines for the left panel.
    virtual std::vector<std::string> panelLines() const = 0;

    // ---- State visible to derived classes ----
    float cursorBrgDeg_  = MARINE_PPI_DEFAULT_CURSOR_BRG;
    float cursorRngMi_   = MARINE_PPI_DEFAULT_CURSOR_RNG;
    float brgOffsetDeg_  = 0.0f;

    float sweepAngle_     = 0.0f;   // current beam angle (degrees CW from north)
    float sweepAnglePrev_ = 0.0f;

    PhosphorRenderer phosphor_;
    Graticule        graticule_;
    LeftPanel        panel_;

private:
    // ---- Held-key acceleration ----
    struct HeldKey {
        float holdTime  = 0.f;
        float stepAccum = 0.f;
    };
    std::unordered_map<int, HeldKey> heldKeys_;

    void updateHeldKeys(float dt);
    void applyKeyStep(int key, float stepSize);

    float sweepPeriod_  = MARINE_PPI_SWEEP_PERIOD;

    void renderReadout(float viewportW, float viewportH) const;
};
