/*
 *  playlist-ogg.c
 *  mod_musicindex
 *
 *  $Id: playlist-vorbis.c 1010 2012-08-07 13:38:34Z varenet $
 *
 *  Created by Regis BOUDIN on Thu Jan 22 2004.
 *  Copyright (c) 2003-2004 Regis BOUDIN
 *  Copyright (c) 2003-2005,2007 Thibaut VARENE
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License version 2.1,
 *  as published by the Free Software Foundation.
 *
 */

/**
 * @file
 * Ogg files management system.
 *
 * @author Regis Boudin
 * @author Thibaut Varene
 * @version $Revision: 1010 $
 * @date 2003-2005
 * @date 2007
 *
 * This file contains everything needed to produce music entries from
 * Ogg Vorbis files.
 */

#include "playlist.h"
#include "playlist-vorbis.h"

#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>

#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif

/**
 * Checks for valid OGG filename extension.
 *
 * @param filename The filename to check.
 *
 * @return FALSE when the extension is correct, TRUE otherwise.
 */
static inline short ogg_ext_check(const char *const filename)
{
	const char *const ext = strrchr(filename, '.');
	if (ext	&& (!strncasecmp(ext, ".ogg", 4)	|| /* official extention */
		!strncasecmp(ext, ".oga", 4))	)	/* audio in ogg */
		return TRUE;
	return FALSE;
}

/**
 * Fills in the information fields about OGG data.
 *
 * This function reads the ogg tags (using libvorbisfile) from the ogg file @a in
 * and fills in the struct mu_ent fields accordingly.
 *
 * @param pool Pool
 * @param in ogg file to parse (closed on normal exit)
 * @param filename current filename
 * @param r Apache request_rec struct to handle log writings (debugging)
 *
 * @return When possible, struct mu_ent correctly set up, file stream closed.
 */
mu_ent *make_ogg_entry(request_rec *r, apr_pool_t *pool, FILE *const in,
	const char *const filename)
{
	const mu_config *const conf = (mu_config *)ap_get_module_config(r->per_dir_config, &musicindex_module);
	mu_ent			*p = NULL;
	OggVorbis_File		vf;
	const char 		*t;
	struct stat		filestat;

	if (!ogg_ext_check(filename) || (ov_test(in, &vf, NULL, 0) != 0))
		return NULL;
	
	p = NEW_ENT(pool);
	if (p == NULL) {
		ov_clear(&vf);
		return NULL;
	}
	
	p->filetype = FT_OGG;
	p->flags &= ~EF_VBR;

	fstat(fileno(in), &filestat);
	p->size = filestat.st_size;
	p->mtime = filestat.st_mtime;

	if (ov_test_open(&vf) == 0) {

		vorbis_comment *comment = ov_comment(&vf, -1);
		if (comment != NULL) {
			if ((t = vorbis_comment_query(comment, "ALBUM", 0)))
				p->album = apr_pstrdup(pool, t);
			if ((t = vorbis_comment_query(comment, "ARTIST", 0)))
				p->artist = apr_pstrdup(pool, t);
			if ((t = vorbis_comment_query(comment, "TITLE", 0)))
				p->title = apr_pstrdup(pool, t);
			if ((t = vorbis_comment_query(comment, "TRACKNUMBER", 0)))
				p->track = atoi(t);
			if ((t = vorbis_comment_query(comment, "DATE", 0)))
				p->date = atoi(t);
			if ((t = vorbis_comment_query(comment, "DISCNUMBER", 0)))	/* http://reactor-core.org/ogg-tagging.html */
				p->posn = atoi(t);
			if ((t = vorbis_comment_query(comment, "GENRE", 0)))
				p->genre = apr_pstrdup(pool, t);
		}

		if (conf->options & MI_QUICKPL) {
			p->bitrate = p->length = p->freq = 0;
		}
		else {
			vorbis_info *info = ov_info(&vf, -1);
			p->freq = info->rate;

#ifndef NO_BR_NOMINAL
			if (info->bitrate_nominal)
				p->bitrate = info->bitrate_nominal;	/* when available this is what players show */
			else
#endif
				p->bitrate = (long)ov_bitrate(&vf, -1);
			if ((info->bitrate_upper > 0) && (info->bitrate_upper == info->bitrate_lower));
			else	/* we have a VBR file */
				p->flags |= EF_VBR;
			p->length = (long)ov_time_total(&vf, -1);
		}

	}
	ov_clear(&vf);
	return p;
}
