/*  xio - I/O 
 *  Copyright (C) Joakim Kolsjö and Anders Asplund 2003
 *	This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.

 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.

 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
 */
  
#ifndef XIO_H
#define XIO_H

#include "xs.h"

// SDL and SDL_Mixer
#ifdef WIN32
	#include <SDL/SDL.h>
	#include <SDL/SDL_mixer.h>
#else
	#include <SDL.h>
	#include <SDL_mixer.h>
#endif

// PI
#ifdef M_PI
	#undef M_PI
#endif
#define M_PI 3.14159265358979323846
 
using namespace std;
 
namespace xio
{	 
	typedef Uint8 u8;
	typedef Uint16 u16;	
	typedef Uint32 u32;
	
	struct vector2d {
		float x, y;
	};
	
	struct vector3d {
		float x, y, z;
	};

	class Random {
	public:
		Random();
		float get();
	};
	
	struct rgb {
		u8 r, g, b;
	};

	typedef SDL_Surface surface;
		
	class Video {
	public:	
		Video(int w, int h, int bpp, bool fs, bool opengl, const char *window_title);
		void init();
		void lock() {  if(SDL_MUSTLOCK(sdl_screen)) SDL_LockSurface(sdl_screen); };
		void unlock() {  if(SDL_MUSTLOCK(sdl_screen)) SDL_UnlockSurface(sdl_screen); };

		// Update buffer to screen
		void update();
		
		// Getting screen width, height
		inline int getWidth() { return sdl_screen->w; };
		inline int getHeight() { return sdl_screen->h; };

		// Direct screen access
		surface *getScreen() { return (surface*)sdl_back; };
		
		// Pixel functions
		void setPixel(xio::surface *surface, int x, int y, u8 r, u8 g, u8 b);
		void getPixel(xio::surface *surface, rgb *pixel, int x, int y);

		// Create surface
		xio::surface *createSurface(int w, int h);
		
		// Free surface
		void freeSurface(xio::surface *surface);
		
		// Resizeing
		xio::surface *resizeSurface(surface *src, int width, int height);
		
		// Rotating
		//void rotateSurface(surface *src, surface *dst, float angle);
		
		// Warping
		void warpSurface(surface *src, surface *dst, int dx, int dy);
		
		// Bliting surfaces
		void blit(surface *src, surface *dst, int dx, int dy, int width, int height, float alpha, bool centralize);
		void blitToScreen(surface *src, int dx, int dy, int width, int height, float alpha, bool centralize);
		
		// Filling surfaces
		void fillSurface(xio::surface *s, u32 color, int sx, int sy, int dx, int dy);		
		void fillScreen(u32 color, int sx, int sy, int dx, int dy);
		void fillSurfaceAll(xio::surface *s, u32 color);
		void fillScreenAll(u32 color);
	
	private:
		int width, height, b;
		bool fullscreen, ogl;
		std::string wtitle;
		SDL_Rect updatedest, filldest;
		SDL_Surface *sdl_screen;
		SDL_Surface *sdl_back;
		SDL_Surface *temp;
	};


	class Sound
	{
	public:
		Sound(bool use, int samplerate);	
		void play(const char *name);
		void setVol(int vol);
		void restart();
		
	private:
		Mix_Music *snd;
		bool use_sound;
	};
	
	class Texture {
	public:
		Texture();
		void loadOne(const char *file);
		void loadAll(const char *dir);
		void add(xio::surface *src, const char *name);
		surface *Texture::get(const char *idstr);
#ifdef DEBUG	
		int kbytes;
#endif
	private:
#ifdef DEBUG
		bool using_loadall;
#endif
		std::map <std::string, surface *> list;
		surface *loadPNG(const char *file);
		xio::Video *video;
	};

	class Timer {
	public:
		Timer();
		long getTime();
		void delay(long time);
	private:
		double starttime;
#ifdef unix
		struct timeval tm;
#endif
	};
		
	class Event {
	public:
		Event() { keyboard_input = SDLK_UNKNOWN; };
		void update();
		SDLKey keyboard() { SDLKey t = keyboard_input; keyboard_input = SDLK_UNKNOWN; return t; };
	private:
		SDLKey keyboard_input;
	};
		
	class Manager {
	public:
		Manager(int width, int height, int bpp, bool fullscreen, bool opengl, 
				const char *window_title, // Video
				bool use_sound, int samplerate, int vol) // Sound
		{	
			static xio::Video v(width, height, bpp, fullscreen, opengl, window_title); video = &v;
			static xio::Sound s(use_sound, samplerate); sound = &s;
			static xio::Event e; event = &e;
			static xio::Timer t; timer = &t;
			static xio::Texture tx; texture = &tx;
		};
		xio::Video *video;
		xio::Sound *sound;
		xio::Event *event;
		xio::Timer *timer;
		xio::Texture *texture;
	};
 }
 
#endif
