
#ifndef VIDEO_H
#define VIDEO_H

#include <SDL.h>
#include <SDL_sound.h>
#include <stdint.h>

#include <set>

#include "refptr/refptr.h"

#define AV_SOUND_FORMAT AUDIO_S16SYS

class AV
{
    public:
#if AV_SOUND_FORMAT == AUDIO_S16SYS
        typedef int16_t sample_t;
#elif AV_SOUND_FORMAT == AUDIO_U16SYS
        typedef uint16_t sample_t;
#else
# error Unknown AV_SOUND_FORMAT
#endif
        class Sound
        {
            public:
                Sound(AV & av);
                ~Sound();
                bool load(const unsigned char *data, unsigned int size);
                void play();
                void resume();
                void stop();
                void loop(int times);
                void rewind();
                int decode(Uint8 * stream, int len);
                float getVolume() { return m_volume; }
                void setVolume(float v);
            protected:
                AV & m_av;
                unsigned char *m_data;
                SDL_RWops * m_rwops;
                Sound_Sample * m_ss;
                int m_loop_count;
                int m_buff_bytes_left;
                float m_volume;
        };

        AV();
        ~AV();
        bool start(int width = 0, int height = 0,
                   bool fullscreen = true, bool grab_input = true,
                   int samples = 4);
        void stop();
        int getDefaultWidth() { return m_defaultWidth; }
        int getDefaultHeight() { return m_defaultHeight; }
        void toggleFullScreen() { SDL_WM_ToggleFullScreen(m_surface); }
        int getWidth() { return m_width; }
        int getHeight() { return m_height; }
        SDL_Surface * getSurface() { return m_surface; }
        void setCursorVisible(bool visible)
        {
            SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE);
        }
        bool getCursorVisible()
        {
            return SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE;
        }
        void setInputGrabbed(bool grabbed)
        {
            SDL_WM_GrabInput(grabbed ? SDL_GRAB_ON : SDL_GRAB_OFF);
        }
        bool getInputGrabbed()
        {
            return SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON;
        }
        refptr<Sound> createSound();
        void playSound(Sound * s);
        void stopSound(Sound * s);

        friend void AV_sound_callback(void * userdata, Uint8 * stream, int len);

    protected:
        void playCallback(Uint8 * stream, int len);

        int m_defaultWidth;
        int m_defaultHeight;
        int m_width;
        int m_height;
        SDL_Surface * m_surface;
        bool m_fullscreen;
#if 0
        std::set< refptr<Sound> > m_sounds;
#endif
        std::set< Sound * > m_active_sounds;
        SDL_mutex * m_active_sounds_mutex;
        sample_t * m_sound_buffer;
};

#endif
