#include "dvd_video.h"

uint8_t dvd_video_angles(ifo_handle_t *vmg_ifo, uint16_t track_number) {

	if(vmg_ifo->tt_srpt == NULL)
		return 0;

	uint8_t angles = vmg_ifo->tt_srpt->title[track_number - 1].nr_of_angles;

	return angles;

}

/**
 * MPEG version
 *
 * 0 = MPEG1
 * 1 = MPEG2
 * 2 = Reserved, do not use
 * 3 = Reserved, do not use
 *
 */
uint8_t dvd_track_mpeg_version(ifo_handle_t *vts_ifo) {

	if(vts_ifo->vtsi_mat == NULL)
		return 0;
	else if(vts_ifo->vtsi_mat->vts_video_attr.mpeg_version == 0)
		return 1;
	else if(vts_ifo->vtsi_mat->vts_video_attr.mpeg_version == 1)
		return 2;
	else
		return 0;

}

/**
 * Helper function to check if video codec is MPEG-1
 */
bool dvd_track_mpeg1(ifo_handle_t *vts_ifo) {

	if(dvd_track_mpeg_version(vts_ifo) == 1)
		return true;
	else
		return false;

}

/**
 * Helper function to check if video codec is MPEG-2
 */
bool dvd_track_mpeg2(ifo_handle_t *vts_ifo) {

	if(dvd_track_mpeg_version(vts_ifo) == 2)
		return true;
	else
		return false;

}

/**
 * Check if a video format is NTSC
 *
 * 0 = NTSC
 * 1 = PAL
 * 2 = Reserved, do not use
 * 3 = Reserved, do not use
 */
bool dvd_track_ntsc_video(ifo_handle_t *vts_ifo) {

	if(vts_ifo->vtsi_mat == NULL)
		return false;
	else if(vts_ifo->vtsi_mat->vts_video_attr.video_format == 0)
		return true;
	else
		return false;

}

/**
 * Check if a video format is PAL
 */
bool dvd_track_pal_video(ifo_handle_t *vts_ifo) {

	if(vts_ifo->vtsi_mat == NULL)
		return false;
	else if(vts_ifo->vtsi_mat->vts_video_attr.video_format == 1)
		return true;
	else
		return false;

}

/**
 * Get the video height
 */
uint16_t dvd_video_height(ifo_handle_t *vts_ifo) {

	if(vts_ifo->vtsi_mat == NULL)
		return 0;

	uint16_t video_height = 0;
	uint8_t picture_size = vts_ifo->vtsi_mat->vts_video_attr.picture_size;

	if(dvd_track_ntsc_video(vts_ifo))
		video_height = 480;
	else if(dvd_track_pal_video(vts_ifo))
		video_height = 576;

	if(picture_size == 3 && video_height > 0) {
		video_height = video_height / 2;
	}

	return video_height;

}

/**
 * Get the video width
 *
 */
uint16_t dvd_video_width(ifo_handle_t *vts_ifo) {

	if(vts_ifo->vtsi_mat == NULL)
		return 0;

	uint16_t video_width = 0;
	uint16_t video_height = dvd_video_height(vts_ifo);
	uint8_t picture_size = vts_ifo->vtsi_mat->vts_video_attr.picture_size;

	if(video_height == 0)
		return 0;

	if(picture_size == 0) {
		video_width = 720;
	} else if(picture_size == 1) {
		video_width = 704;
	} else if(picture_size == 2) {
		video_width = 352;
	} else if(picture_size == 3) {
		video_width = 352;
	} else {
		// Catch wrong integer values burned in DVD, and guess at the width
		video_width = 720;
	}

	return video_width;

}

/**
 * Check for a valid aspect ratio (4:3, 16:9)
 */
bool dvd_track_valid_aspect_ratio(ifo_handle_t *vts_ifo) {

	if(vts_ifo->vtsi_mat == NULL)
		return false;
	else if(vts_ifo->vtsi_mat->vts_video_attr.display_aspect_ratio == 0 || vts_ifo->vtsi_mat->vts_video_attr.display_aspect_ratio == 3)
		return true;
	else
		return false;

}

/**
 * Check for 4:3 aspect ratio
 */
bool dvd_track_aspect_ratio_4x3(ifo_handle_t *vts_ifo) {

	if(vts_ifo->vtsi_mat == NULL)
		return false;
	else if(vts_ifo->vtsi_mat->vts_video_attr.display_aspect_ratio == 0)
		return true;
	else
		return false;

}

/**
 * Check for 16:9 aspect ratio
 */
bool dvd_track_aspect_ratio_16x9(ifo_handle_t *vts_ifo) {

	if(vts_ifo->vtsi_mat == NULL)
		return false;
	else if(vts_ifo->vtsi_mat->vts_video_attr.display_aspect_ratio == 3)
		return true;
	else
		return false;

}

/**
 * Get the permitted_df field for a track.  Returns the uint8_t
 * directly, error checking should be done to see if it's valid or not.
 *
 * 0 = Pan and Scan or Letterbox
 * 1 = Pan and Scan
 * 2 = Letterbox
 * 3 = Unset
 */
uint8_t dvd_video_df(ifo_handle_t *vts_ifo) {

	if(vts_ifo->vtsi_mat == NULL)
		return 3;

	uint8_t permitted_df = vts_ifo->vtsi_mat->vts_video_attr.permitted_df;

	return permitted_df;

}

/** FIXME
 *
 * All of these functions need to be correctly fixed:
 * - is letterbox (anamorphic widescreen or not)
 * - is widescreen (anamorphic widescreen or not)
 * - is pan & scan
 *
 * The problem is that permitted display format has *part* of the answer, while
 * the VTS itself can also have it's own "letterbox" tag.
 *
 * FIXME is that I need to clarify / document / code all the possible options
 * when it comes to widescreen (16x9), letterbox, pan & scan.
 *
 * See also http://stnsoft.com/DVD/ifo.html
 */

/**
 * Check for letterbox video
 *
 * This function looks at the permitted display format of the DVD.  Possible
 * values for this variable are:
 *
 * 0: Pan and Scan plus Letterbox
 * 1: Pan and Scan
 * 2: Letterbox
 * 3: Unset (most likely non-anormphic widescreen?)
 */
bool dvd_video_letterbox(ifo_handle_t *vts_ifo) {

	if(vts_ifo->vtsi_mat == NULL)
		return false;

	uint8_t permitted_df = vts_ifo->vtsi_mat->vts_video_attr.permitted_df;

	if(permitted_df == 0 || permitted_df == 2)
		return true;
	else
		return false;

}

/**
 * Check for pan & scan video
 *
 * This function looks at the permitted display format of the DVD.  Possible
 * values for this variable are:
 *
 * 0: Pan & Scan plus Letterbox
 * 1: Pan & Scan
 * 2: Letterbox
 * 3: ???
 *
 * This function returns true if either the first condition or the second one
 * is true.  This means that a video may be pan & scan, or it may be non-
 * anomorphic widescreen.
 */
bool dvd_video_pan_scan(ifo_handle_t *vts_ifo) {

	if(vts_ifo->vtsi_mat == NULL)
		return false;

	uint8_t permitted_df = vts_ifo->vtsi_mat->vts_video_attr.permitted_df;

	if(permitted_df == 0 || permitted_df == 1)
		return true;
	else
		return false;

}

/*
 * Get the video codec for a track
 */
bool dvd_video_codec(char *dest_str, ifo_handle_t *vts_ifo) {

	if(vts_ifo->vtsi_mat == NULL)
		return false;
	else if(vts_ifo->vtsi_mat->vts_video_attr.mpeg_version == 0) {
		strncpy(dest_str, "MPEG1", DVD_VIDEO_CODEC + 1);
		return true;
	} else if(vts_ifo->vtsi_mat->vts_video_attr.mpeg_version == 1) {
		strncpy(dest_str, "MPEG2", DVD_VIDEO_CODEC + 1);
		return true;
	}

	return false;

}

/*
 * Get the video format for a track
 */
bool dvd_track_video_format(char *dest_str, ifo_handle_t *vts_ifo) {

	if(vts_ifo->vtsi_mat == NULL)
		return false;
	else if(vts_ifo->vtsi_mat->vts_video_attr.video_format == 0)
		strncpy(dest_str, "NTSC", DVD_VIDEO_FORMAT + 1);
	else if(vts_ifo->vtsi_mat->vts_video_attr.mpeg_version == 1)
		strncpy(dest_str, "PAL", DVD_VIDEO_FORMAT + 1);

	return true;

}

/*
 * Get the video aspect ratio for a track
 */
bool dvd_video_aspect_ratio(char *dest_str, ifo_handle_t *vts_ifo) {

	if(vts_ifo->vtsi_mat == NULL)
		return false;
	else if(vts_ifo->vtsi_mat->vts_video_attr.display_aspect_ratio == 0)
		strncpy(dest_str, "4:3", DVD_VIDEO_ASPECT_RATIO + 1);
	else if(vts_ifo->vtsi_mat->vts_video_attr.display_aspect_ratio == 3)
		strncpy(dest_str, "16:9", DVD_VIDEO_ASPECT_RATIO + 1);

	return true;

}

// FIXME needs documentation
double dvd_track_fps(dvd_time_t *dvd_time) {

	double frames_per_s[4] = {-1.0, 25.00, -1.0, 29.97};
	double fps = frames_per_s[(dvd_time->frame_u & 0xc0) >> 6];

	return fps;

}

bool dvd_track_str_fps(char *dest_str, ifo_handle_t *vmg_ifo, ifo_handle_t *vts_ifo, uint16_t track_number) {

	if(vts_ifo->vts_pgcit == NULL || vts_ifo->vts_ptt_srpt == NULL || vts_ifo->vts_ptt_srpt->title == NULL)
		return false;

	uint8_t ttn = dvd_track_ttn(vmg_ifo, track_number);
	pgcit_t *vts_pgcit = vts_ifo->vts_pgcit;
	pgc_t *pgc = vts_pgcit->pgci_srp[vts_ifo->vts_ptt_srpt->title[ttn - 1].ptt[0].pgcn - 1].pgc;

	if(!pgc)
		return false;

	double fps = dvd_track_fps(&pgc->playback_time);

	if(fps > 0) {
		snprintf(dest_str, DVD_VIDEO_FPS + 1, "%02.02f", fps);
		return true;
	}

	return false;

}
