/*
PMP Mod
Copyright (C) 2006 Raphael

E-mail:   raphael@fx-world.org

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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
subtitle parsing layer
*/


#include <stdio.h>
#include "pmp_parse.h"
#include "pmp_microdvd.h"
#include "mem64.h"


struct pmp_sub_frame_struct* (*pmp_sub_parse_line)( FILE *f ) = 0;	// function pointer to line parsing


int strconv( char* s, const char a, const char b )
	{
	int i = 1;
	char* t = s;
	while (*t)
		{
		if (*t==a)
			{
			*t = b;
			i++;
			}
		t++;
		}

	return(i);
	}


void pmp_sub_frame_safe_constructor(struct pmp_sub_frame_struct *p)
	{
		p->p_start_frame = 0;
		p->p_end_frame = 0;
		p->p_num_lines = 0;
		p->p_string[0] = '\0';
		p->next = 0;
		p->prev = 0;
	}
	

void pmp_sub_frame_safe_destructor(struct pmp_sub_frame_struct *p)
	{
		if (p->next != 0) pmp_sub_frame_safe_destructor(p->next);
		p->next = 0;
		p->prev = 0;
		free_64( p );
		p = 0;
	}


void pmp_sub_parse_safe_constructor(struct pmp_sub_parse_struct *p)
	{
		p->p_sub_frame = 0;
		p->p_num_sub_frames = 0;
		p->p_cur_sub_frame = 0;
		p->p_in = 0;
	}
	

void pmp_sub_parse_close(struct pmp_sub_parse_struct *p)
	{
	    if (p->p_in != 0)        fclose(p->p_in);
		if (p->p_sub_frame != 0) pmp_sub_frame_safe_destructor(p->p_sub_frame);
	}


char *pmp_sub_parse_open(struct pmp_sub_parse_struct *p, char *s)
	{
		if (p==0) return("pmp_sub_parse_open: p not initialized");
		pmp_sub_parse_safe_constructor(p);
		
		p->p_in = fopen(s, "rb");
		if (p->p_in == 0)
			{
			pmp_sub_parse_close(p);
			return("pmp_sub_parse_open: can't open file");
			}
	
		
		struct pmp_sub_frame_struct *new_frame = 0;
		p->p_sub_frame = (struct pmp_sub_frame_struct*)malloc_64( sizeof(struct pmp_sub_frame_struct) );
		if (p->p_sub_frame==0)
			{
			pmp_sub_parse_close(p);
			return("pmp_sub_parse_open: malloc_64 failed on p_sub_frame");
			}
		pmp_sub_frame_safe_constructor(p->p_sub_frame);
		p->p_cur_sub_frame = p->p_sub_frame;
		
		struct pmp_sub_frame_struct *cur_frame = p->p_sub_frame;
		
		/* subtitle format selection here */
		pmp_sub_parse_line = &pmp_sub_parse_microdvd;
		
		while ((new_frame=pmp_sub_parse_microdvd( p->p_in ))!=0)
			{
			cur_frame->next = new_frame;
			new_frame->prev = cur_frame;
			cur_frame = new_frame;
			p->p_num_sub_frames++;
			}

		cur_frame->next = 0;
		
		fclose(p->p_in);
		p->p_in = 0;
		
		
		return(0);
	}


char* pmp_sub_parse_get_frame(struct pmp_sub_parse_struct *p, struct pmp_sub_frame_struct **f, unsigned int frame )
	{
		*f = 0;
		if (p==0) return("pmp_sub_parse_get_frame: p not initialized");
		if (p->p_sub_frame==0) return("pmp_sub_parse_get_frame: p_sub_frame not initialized");
	
		if (p->p_cur_sub_frame==0) p->p_cur_sub_frame = p->p_sub_frame;
		
		*f = p->p_cur_sub_frame;
		if (p->p_cur_sub_frame->p_start_frame<=frame && p->p_cur_sub_frame->p_end_frame>=frame) return(0);
		
		if (p->p_cur_sub_frame->p_end_frame<=frame)
			{
			// Forward search
			while (p->p_cur_sub_frame->next!=0 && p->p_cur_sub_frame->p_end_frame<=frame)
				{
				p->p_cur_sub_frame = p->p_cur_sub_frame->next;
				*f = p->p_cur_sub_frame;
				if (p->p_cur_sub_frame->p_start_frame<=frame && p->p_cur_sub_frame->p_end_frame>=frame) return(0);
				if (p->p_cur_sub_frame->p_start_frame>=frame) break;
				}
			}
		else if (p->p_cur_sub_frame->p_start_frame>=frame)
			{
			// Backward search
			while (p->p_cur_sub_frame->prev!=0)
				{
				if (p->p_cur_sub_frame->prev->p_end_frame<=frame) break;
				p->p_cur_sub_frame = p->p_cur_sub_frame->prev;
				*f = p->p_cur_sub_frame;
				if (p->p_cur_sub_frame->p_start_frame<=frame && p->p_cur_sub_frame->p_end_frame>=frame) return(0);
				}
			}
		
		*f = 0;
		return(0);
	}
	
