#ifndef D_SND_BGM_HARP_DATA_H
#define D_SND_BGM_HARP_DATA_H

#include "common.h"
#include "d/snd/d_snd_rng_mgr.h"

/**
 * This file deals with the pitch of the Goddess' Harp when Link
 * is freely strumming. In this case the pitch of the strings
 * is adjusted to match the key of background music through sequence variables.
 * When Link strums the harp, 12 strings can be heard, but it's actually only four
 * notes of the same chord spanning three octaves.
 *
 * I haven't yet investigated all the data, but a typical chord Link might play
 * is Cmaj^7, consisting of C-E-G-B. Link actually plays:
 * G3-C4-E4-G4-B4-C5-E5-G5-B5-C6-E6-G6
 * B3 is missing, possibly to prevent dissonance at the ends of the scale.
 * (Sealed Grounds, before Demise fight, no actual BGM)
 *
 * TODO: This deals with slightly more than the harp. It additionally
 * also deals with the combat hit sounds that also seem to match up in
 * pitch with the BGM.
 */

/**
 * Contains a single Seq sound var controlling the pitch of a subset of harp strings
 * Size: 0x02
 */
struct dSndBgmDataHarpVar_c {
    dSndBgmDataHarpVar_c() : field_0x00(0), field_0x01(0) {}

    void reset() {
        field_0x00 = 0;
        field_0x01 = 0;
    }

    void onFlag() {
        field_0x00 |= 1;
    }

    bool checkFlag() const {
        return field_0x00 & 1;
    }

    /* 0x00 */ u8 field_0x00; // flags
    /* 0x01 */ s8 field_0x01; // var
};

/**
 * Contains Seq sound vars for all harp strings, represents a "key" in the bgm music
 * Size: 0x0C
 */
class dSndBgmDataHarpVarSetBase_c {
public:
    dSndBgmDataHarpVarSetBase_c(s32 count);
    ~dSndBgmDataHarpVarSetBase_c();

    void resetVars();
    void addVar(u8 value);

    s32 getPosition() const {
        return mPosition;
    }

    void setPosition(s32 position) {
        mPosition = position;
    }

    s32 getCount() {
        return mCount;
    }

    s32 getMax() const {
        return mMax;
    }

    s32 getNumBitsSet() {
        s32 numBits = 0;
        for (int i = 0; i < getCount(); i++) {
            if (mpVars[i].checkFlag()) {
                numBits++;
            }
        }
        return numBits;
    }

    dSndBgmDataHarpVar_c *getVar(s32 idx) {
        if (idx >= getCount()) {
            return nullptr;
        }
        return &mpVars[idx];
    }

    s32 getRandomIdx() {
        return dSndRngMgr_c::GetInstance()->rndIntRange(0, getCount());
    }

    s32 getRandomIdxWithBitSet() {
        s32 numBitsSet = getNumBitsSet();
        s32 idx;
        if (numBitsSet <= 0) {
            return 0;
        } else {
            idx = dSndRngMgr_c::GetInstance()->rndIntRange(0, getCount());
            while (true) {
                if (mpVars[idx].checkFlag()) {
                    return idx;
                }
                idx = dSndRngMgr_c::GetInstance()->rndIntRange(0, getCount());
            }
        }
    }

    s32 getVal(s32 idx) {
        if (idx >= getCount()) {
            return 0;
        }
        return mpVars[idx].field_0x01;
    }

    dSndBgmDataHarpVar_c *getUnusedVar() {
        if (mCount >= mMax) {
            return nullptr;
        }
        return &mpVars[mCount];
    }

private:
    /* 0x00 */ dSndBgmDataHarpVar_c *mpVars;
    /* 0x04 */ s32 mPosition;
    /* 0x08 */ s16 mMax;
    /* 0x0A */ s16 mCount;
};

class dSndBgmDataHarpVarSet_c : public dSndBgmDataHarpVarSetBase_c {
public:
    dSndBgmDataHarpVarSet_c() : dSndBgmDataHarpVarSetBase_c(4) {}

private:
};

/**
 * Contains parsed seq data for harp strings for a single bgm sound
 */
class dSndBgmHarpDataBase_c {
public:
    dSndBgmHarpDataBase_c();
    void resetVars();
    s32 getIdxForPosition(s32 position);

    dSndBgmDataHarpVarSetBase_c *getUsableVarSet(s32 idx);
    void addVar(s32 position, s32 value, s32 unk);
    void setField_0x08(s32 value);

protected:
    dSndBgmDataHarpVarSetBase_c *getVarSet(s32 idx);
    /* 0x00 */ dSndBgmDataHarpVarSetBase_c *mpVarSets;
    /* 0x04 */ s16 mMax;
    /* 0x06 */ s16 mCount;
    /* 0x08 */ s32 field_0x08;
};

class dSndBgmHarpData_c : public dSndBgmHarpDataBase_c {
public:
    dSndBgmHarpData_c();
    ~dSndBgmHarpData_c();

    /**
     * Writes the Seq sound variables that control the pitch
     * of the individual harp strings.
     */
    void writeSeqVars(s32 idx);

private:
    static const u32 NUM_SETS = 300;
};

#endif
