#include "main.h"
#include "bsprender2.h"
#include "avikit.h"

#define MAX_MAP_VIDS 16

#define NUM_AUDIO_BUFFS 4

typedef struct 
{
	bool used;
	bool usable;
	AVIKit*Avi;
	texture_t*tex;
	int xsize,ysize;
	char*frame_buffer;
	
	float frame;
	int last_uploaded_frame;
	
	int sample_rate;
	int num_channels;
	bool is16bit;

	byte*audio_buff[NUM_AUDIO_BUFFS];
	long timeoffsets[NUM_AUDIO_BUFFS];
	int current_audio_buffer;

}avi_texture_t;

avi_texture_t Avis[MAX_MAP_VIDS];

avi_texture_t*AllocAviTexture()
{
	for(int i=0;i<MAX_MAP_VIDS;i++)
	{
		if (!Avis[i].used)
		{
			Avis[i].used=true;
			return &Avis[i];
		}
	}
	FAIL("AllocAviTexture(): no free slots!");
}

bool CheckAviError(AVIKit*avi)
{
	int err;
	char *emsg;
	
	bool ret=false;

	while ((err = avi->getError(&emsg)) != AVIKIT_NOERROR)
	{
		ret=true;
		switch (err)
		{
		case AVIKIT_ERROR_BADFILE: // "No handler found, or file does not exist."
		case AVIKIT_ERROR_BADFORMAT: // "Corrupt AVI or unknown format."
		case AVIKIT_ERROR_MEMERROR: // "Not enough memory to open AVI."
		case AVIKIT_ERROR_DISKERROR: // "Disk error attempting to read AVI."
			
			// errors opening video
		case AVIKIT_ERROR_NOVIDEO: // "No video stream found in specified file."
		case AVIKIT_ERROR_VIDEOERROR: // "VFW failed to read video stream."
			RPRINTF("LoadAviForTexture() error:%s",emsg);
			break;
			
			// errors opening audio
		case AVIKIT_ERROR_ACM: // "ACM failed to open conversion stream."
			RPRINTF("LoadAviForTexture(): ACM failed to open conversion stream (is the codec installed?)");
			break;
			
		case AVIKIT_ERROR_ACMCODEC: // "ACM does not support this audio codec." (WMA).
		default:
			RPRINTF("LoadAviForTexture() error:%s",emsg);
			break;
		}
	}
	return ret;
}

void LoadAviForTexture(texture_t*tex)
{
	avi_texture_t*avi_tex=AllocAviTexture();
	avi_tex->tex=tex;

	char vidname[8];
	sscanf(tex->name,"avi@%s",vidname);



	//glGenTextures(1,(GLuint*)&tex->gl_texturenum);
	tex->gl_texturenum=1;
	
	avi_tex->Avi=new AVIKit(VA("data/textures/video/%s.avi",vidname));

	if (CheckAviError(avi_tex->Avi)) 
	{
		delete avi_tex->Avi;
		avi_tex->used=false;
		return;
	}

	long xsize,ysize;
	float len;
	
	avi_tex->Avi->getVideoInfo(&xsize,&ysize,&len);
	avi_tex->frame_buffer=(char*)Z_Malloc(xsize*ysize*3);
	avi_tex->xsize=xsize;
	avi_tex->ysize=ysize;

	glBindTexture(GL_TEXTURE_2D,tex->gl_texturenum);
	
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, xsize,ysize, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);

	long sample_rate,bps,channels;
	bool is16bit;

	avi_tex->Avi->getAudioInfo(&sample_rate,&bps,&channels,&is16bit);
	avi_tex->sample_rate=sample_rate;

	avi_tex->is16bit=is16bit;
	avi_tex->num_channels=channels;

	for(int i=0;i<NUM_AUDIO_BUFFS;i++)
	{
		avi_tex->audio_buff[i]=(byte*)Z_Malloc(sample_rate*channels* bps*is16bit ? 2:1);
		avi_tex->timeoffsets[i]=0;
	}
	avi_tex->current_audio_buffer=0;
	

	RPRINTF("Loading avi %s - %d frames,",VA("textures/video/%s.avi",vidname),avi_tex->Avi->NumVideoFrames());
	RPRINTF("Audio: %d Hz %d bps  %d channels %s",sample_rate,bps,channels,is16bit ? "16bit" : "8bit");
	

}

void DBG_DumpFrame(avi_texture_t*tex)
{
	FILE*fp=fopen(VA("%s.raw",tex->tex->name),"wb");
	fwrite(tex->frame_buffer,tex->xsize*tex->ysize*3,1,fp);
	fclose(fp);
}

void RefreshBspAvis()
{
//	return;
	for(int i=0;i<MAX_MAP_VIDS;i++)
	{
		avi_texture_t*tex=&Avis[i];

		if (!tex->used) continue;

		tex->frame+=R_FrameTime()*25;



	if (tex->frame>tex->Avi->NumVideoFrames())
		tex->frame=0;

	int f=tex->Avi->getVideoFrameNumber(tex->frame/25);
		tex->Avi->getVideoFrame(tex->frame_buffer, tex->frame);

	//RefreshAviAudio(tex);

	if (f!=tex->last_uploaded_frame)
	{
		glBindTexture(GL_TEXTURE_2D,tex->tex->gl_texturenum);
		glTexSubImage2D(GL_TEXTURE_2D, 0,0, 0, tex->xsize,tex->ysize,GL_RGB, GL_UNSIGNED_BYTE, tex->frame_buffer);
		//glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,tex->xsize,tex->ysize,0,GL_RGB,GL_UNSIGNED_BYTE,tex->frame_buffer);

		tex->last_uploaded_frame=f;
	}	
	
	}
}