#include "jaudio.h"
#include "jfile.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_mixer.h>
#include <stdio.h>

namespace audio
{
    // Açò son estructures de mentires, per a usar estructures de SDL_Mixer de forma opaca.
    // Al final es un punter, així que és irrelevant el tipus del punter,
    //  però si amague que son estructures de SDL_Mixer, no fa falta ficar el include a SDL_mixer fora de este arxiu
    struct sound
    {
    }; // Dummy structs

    static char *buffer = nullptr;
    static Mix_Music *music = nullptr;
    static std::string music_filename = "";

    // Inicialitza el sistema de só
    void init()
    {
        // Al final he ficat la configuració automàtica i au. Si en el futur necesitem canviar-ho pos se canvia
        if (Mix_Init(MIX_INIT_OGG)==0) {
           printf("Failed Mix_Init()\n");
        }
        if (Mix_OpenAudio(48000, AUDIO_S16, 2, 1024)!=0) {
            printf("Failed Mix_OpenAudio()\n");
        }
    }

    // Tanca el sistema de só (no shit, sherlock)
    void quit()
    {
        Mix_CloseAudio();
    }

    // Carrega un arxiu de música en format OGG
    const bool loadMusic(const std::string filename)
    {
        if (music != nullptr) {
            Mix_FreeMusic(music);
            free(buffer);
        }
        int filesize=0;
        buffer = file::getFileBuffer(filename, &filesize);
        music = Mix_LoadMUS_RW(SDL_RWFromMem(buffer, filesize), 1);
        
        if (music==nullptr) return false;

        music_filename = filename;
        return true;
    }

    // Comença a reproduïr la música en questió
    void playMusic(const int loop)
    {
        if (Mix_PlayMusic(music, loop) == -1) {
            printf("Failed Mix_PlayMusic()\n");
        }
    }

    // Pausa la música que està sonant ara
    void pauseMusic()
    {
        Mix_PauseMusic();
    }

    // Continua la música pausada
    void resumeMusic()
    {
        Mix_ResumeMusic();
    }

    // Para la música que estava sonant
    void stopMusic()
    {
        Mix_HaltMusic();
    }

    // Para la música que estava sonant fent un fade
    void fadeoutMusic()
    {
        Mix_FadeOutMusic(500);
    }

    // Obté el estat actual de la música
    const music_state getMusicState()
    {
        if (Mix_PausedMusic())
        {
            return MUSIC_PAUSED;
        }
        else if (Mix_PlayingMusic())
        {
            return MUSIC_PLAYING;
        }
        else
        {
            return MUSIC_STOPPED;
        }
    }

    // Obté el nom de l'arxiu de música actual
    std::string whichMusic()
    {
        return music_filename;
    }

    // Carrega un só des d'un arxiu WAV
    const sound *loadSound(const std::string filename)
    {
        return (sound *)Mix_LoadWAV(filename.c_str());
    }

    // Comença a reproduïr el só especificat
    const int playSound(sound *snd, const int loop)
    {
        return Mix_PlayChannel(-1, (Mix_Chunk *)snd, loop);
    }

    // Allibera un só
    void deleteSound(sound *snd)
    {
        Mix_FreeChunk((Mix_Chunk *)snd);
    }

    // Pausa un canal en el que s'estava reproduïnt un só
    void pauseChannel(const int channel)
    {
        Mix_Pause(channel);
    }

    // Continua un canal pausat
    void resumeChannel(const int channel)
    {
        Mix_Resume(channel);
    }

    // Para un canal que estava reproduïnt un só
    void stopChannel(const int channel)
    {
        Mix_HaltChannel(channel);
    }

    // Obté l'estat d'un canal
    const channel_state getChannelState(const int channel)
    {
        if (Mix_Paused(channel))
        {
            return CHANNEL_PAUSED;
        }
        else if (Mix_Playing(channel))
        {
            return CHANNEL_PLAYING;
        }
        else
        {
            return CHANNEL_FREE;
        }
    }

    // Estableix el volum general
    const int setVolume(int volume)
    {
        return Mix_Volume(-1, volume);
    }
}