/*
 * Drive.c
 *
 * Copyright (c) 2007  Vreixo Formoso
 *
 * This library 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.
 * See COPYING file for details.
 */

#include "org_pykix_libburnia_libburn_Drive.h"
#include "BindingsUtil.h"

#include "libburn.h"


/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_drive_grab
 * Signature: (JI)Z
 */
JNIEXPORT jboolean JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1drive_1grab
(
	JNIEnv *env, jclass cls, jlong drive, jint load
)
{
	return burn_drive_grab( (struct burn_drive *) drive, load);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_drive_release
 * Signature: (JI)V
 */
JNIEXPORT void JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1drive_1release
(
	JNIEnv *env, jclass cls, jlong drive, jint eject
)
{
	burn_drive_release( (struct burn_drive *) drive, eject);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_get_status
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1get_1status
(
	JNIEnv *env, jclass cls, jlong drive
)
{
	return burn_disc_get_status( (struct burn_drive *) drive );
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_get_profile
 * Signature: (J)S
 */
JNIEXPORT jshort JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1get_1profile
(
	JNIEnv *env, jclass cls, jlong d
)
{
	int pno;
	char name[80];

	if ( burn_disc_get_profile( (struct burn_drive *) d, &pno, name) ) {
		return (jshort) pno;
	} else {
		return 0; //no profile
	}
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_erasable
 * Signature: (J)Z
 */
JNIEXPORT jboolean JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1erasable
(
	JNIEnv *env, jclass cls, jlong d
)
{
	return burn_disc_erasable( (struct burn_drive *) d);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_drive_get_status
 * Signature: (JJ)I
 */
JNIEXPORT jint JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1drive_1get_1status
(
	JNIEnv *env, jclass cls, jlong drive, jlong p
)
{
	return burn_drive_get_status( (struct burn_drive *)drive, (struct burn_progress *) p);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_erase
 * Signature: (JZ)V
 */
JNIEXPORT void JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1erase
(
	JNIEnv *env, jclass cls, jlong drive, jboolean fast
)
{
	burn_disc_erase( (struct burn_drive *) drive, fast);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_write_opts_new
 * Signature: (J)J
 */
JNIEXPORT jlong JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1write_1opts_1new
(
	JNIEnv *env, jclass cls, jlong drive
)
{
	return (jlong) burn_write_opts_new( (struct burn_drive *) drive);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_available_space
 * Signature: (JJ)J
 */
JNIEXPORT jlong JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1available_1space
(
	JNIEnv *env, jclass cls, jlong d, jlong o
)
{

	return burn_disc_available_space( (struct burn_drive *) d, 
					  (struct burn_write_opts *) o);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_write
 * Signature: (JJ)V
 */
JNIEXPORT void JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1write
(
	JNIEnv *env, jclass cls, jlong o, jlong disc
)
{
	burn_disc_write( (struct burn_write_opts *) o, (struct burn_disc *) disc);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_format
 * Signature: (JJI)V
 */
JNIEXPORT void JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1format
(
	JNIEnv *env, jclass cls, jlong drive, jlong size, jint flag
)
{
	burn_disc_format( (struct burn_drive *) drive, size, flag);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_drive_cancel
 * Signature: (J)V
 */
JNIEXPORT void JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1drive_1cancel
(
	JNIEnv *env, jclass cls, jlong d
)
{
	burn_drive_cancel( (struct burn_drive *) d );
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_drive_wrote_well
 * Signature: (J)Z
 */
JNIEXPORT jboolean JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1drive_1wrote_1well
(
	JNIEnv *env, jclass cls, jlong d
)
{
	return burn_drive_wrote_well( (struct burn_drive *) d );
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_drive_get_disc
 * Signature: (J)J
 */
JNIEXPORT jlong JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1drive_1get_1disc
(
	JNIEnv *env, jclass cls, jlong d
)
{
	return (jlong) burn_drive_get_disc( (struct burn_drive *) d );
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_drive_set_speed
 * Signature: (JII)V
 */
JNIEXPORT void JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1drive_1set_1speed
(
	JNIEnv *env, jclass cls, jlong d, jint r , jint w
)
{
	burn_drive_set_speed( (struct burn_drive *) d, r, w);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_drive_get_write_speed
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1drive_1get_1write_1speed
(
	JNIEnv *env, jclass cls, jlong drive
)
{
	return burn_drive_get_write_speed( (struct burn_drive *) drive);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_drive_get_min_write_speed
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1drive_1get_1min_1write_1speed
(
	JNIEnv *env, jclass cls, jlong drive
)
{
	return burn_drive_get_min_write_speed( (struct burn_drive *) drive);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_drive_get_read_speed
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1drive_1get_1read_1speed
(
	JNIEnv *env, jclass cls, jlong drive
)
{
	return burn_drive_get_read_speed( (struct burn_drive *) drive);
}


/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_read_opts_new
 * Signature: (J)J
 */
JNIEXPORT jlong JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1read_1opts_1new
(
	JNIEnv *env, jclass cls, jlong drive
)
{
	return (jlong) burn_read_opts_new( (struct burn_drive *) drive);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_drive_get_speedlist
 * Signature: (J)[Lorg/pykix/libburnia/libburn/SpeedDescriptor;
 */
JNIEXPORT jobjectArray JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1drive_1get_1speedlist
(
	JNIEnv *env, jclass cls, jlong d
)
{
	struct burn_speed_descriptor *list;
	int count = 0;
	static jclass speedDescCls = NULL;
	static jmethodID cid = NULL;
	jobjectArray result;

	if ( speedDescCls == NULL ) {
		speedDescCls = java_libburn_find_class(env, "org/pykix/libburnia/libburn/SpeedDescriptor");
		if ( speedDescCls == NULL ) {
			return NULL;
		}
	}

	if ( cid == NULL ) {
		cid = (*env)->GetMethodID(env, speedDescCls, "<init>", "(ISIIIIZZ)V");
		if (cid == NULL) {
		    return NULL; /* exception thrown */
		}
	}

	int res = burn_drive_get_speedlist((struct burn_drive *) d, &list);
	
	if ( res < 0 ) {
		return NULL; //error
	}
	
	/* count speed descs */
	if ( res != 0) {

		/* no empty list */
		count = 1;
		struct burn_speed_descriptor *sd = list;
		while ( (sd = sd->next) != NULL) {
			count++;
		}
	}

	result = (*env)->NewObjectArray(env, count, speedDescCls, NULL);

	int i;
	struct burn_speed_descriptor *csd = list;
	for ( i = 0; i < count; ++i ) {
		jobject sd = (*env)->NewObject(env, speedDescCls, cid, csd->source, 
			     (jshort) csd->profile_loaded, csd->end_lba, csd->write_speed, 
			     csd->read_speed, csd->wrc, csd->exact, csd->mrw);
		
		if (sd == NULL) {
		    return NULL; /* out of memory error thrown */
		}
		
		(*env)->SetObjectArrayElement(env, result, i, sd);
		csd = csd->next;
	}

	/* free speed list returned by libburn */
	burn_drive_free_speedlist( &list );

	return result;
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_pretend_blank
 * Signature: (J)Z
 */
JNIEXPORT jboolean JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1pretend_1blank
(
	JNIEnv *env, jclass cls, jlong d
)
{
	return burn_disc_pretend_blank( (struct burn_drive *) d);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_pretend_full
 * Signature: (J)Z
 */
JNIEXPORT jboolean JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1pretend_1full
(
	JNIEnv *env, jclass cls, jlong d
)
{
	return burn_disc_pretend_full( (struct burn_drive *) d);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_read_atip
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1read_1atip
(
	JNIEnv *env, jclass cls, jlong d
)
{
	return burn_disc_read_atip( (struct burn_drive *) d );
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_drive_get_start_lba
 * Signature: (JI)I
 */
JNIEXPORT jint JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1drive_1get_1start_1lba
(
	JNIEnv *env, jclass cls, jlong d, jint flag
)
{
	int start_lba, end_lba;

	if ( burn_drive_get_start_end_lba( (struct burn_drive *) d,
                                 &start_lba, &end_lba, flag) == 1 ) {
		
		/* valid values */
		return start_lba;
	} else {
		/* invalid, throw exception */
		java_libburn_throw_burn_exception(env, "Can't get valid LBA value");
	}
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_drive_get_end_lba
 * Signature: (JI)I
 */
JNIEXPORT jint JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1drive_1get_1end_1lba
(
	JNIEnv *env, jclass cls, jlong d, jint flag
)
{
	int start_lba, end_lba;

	if ( burn_drive_get_start_end_lba( (struct burn_drive *) d,
                                 &start_lba, &end_lba, flag) == 1 ) {
		
		/* valid values */
		return end_lba;
	} else {
		/* invalid, throw exception */
		java_libburn_throw_burn_exception(env, "Can't get valid LBA value");
		return -1;
	}
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_track_lba
 * Signature: (JJI)I
 */
JNIEXPORT jint JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1track_1lba
(
	JNIEnv *env, jclass cls, jlong d, jlong o, jint trackno
)
{
	int lba, nwa;

	int res = burn_disc_track_lba_nwa( (struct burn_drive *) d, (struct burn_write_opts *) o,
				trackno, &lba, &nwa);

	if ( res < 0 ) {
		java_libburn_throw_burn_exception(env, "Can't get Track LBA");
		return -1;
	} else {
		return lba;
	}
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_track_nwa
 * Signature: (JJI)I
 */
JNIEXPORT jint JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1track_1nwa
(
	JNIEnv *env, jclass cls, jlong d, jlong o, jint trackno
)
{
	int lba, nwa;

	int res = burn_disc_track_lba_nwa( (struct burn_drive *) d, (struct burn_write_opts *) o,
				trackno, &lba, &nwa);

	switch (res) {
	case 1:
		return nwa;
	case 0:
		java_libburn_throw_burn_exception(env, "Track nwa is not valid");
		return -1;
	default:
		java_libburn_throw_burn_exception(env, "Can't get Track nwa");
		return -1;
	}
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_get_msc1
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1get_1msc1
(
	JNIEnv *env, jclass cls, jlong d
)
{
	int start_lba;
	if ( burn_disc_get_msc1( (struct burn_drive *) d, &start_lba) == 1 ) {
		return start_lba;
	} else {
		java_libburn_throw_burn_exception(env, "Can't get msc1");
		return -1;
	}
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_get_multi_caps
 * Signature: (JII)Lorg/pykix/libburnia/libburn/MultiCaps;
 */
JNIEXPORT jobject JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1get_1multi_1caps
(
	JNIEnv *env, jclass cls, jlong d, jint wt, jint flag
)
{
	struct burn_multi_caps *caps;
	static jclass multiCapsCls = NULL;
	static jmethodID cid = NULL;
	
	int res = burn_disc_get_multi_caps( (struct burn_drive *) d, wt, &caps, flag);

	if ( res < 0 ) {
		java_libburn_throw_burn_exception(env, "Can't get multi caps");
		//TODO is needed the free of caps???
		return NULL;
	}

	if ( multiCapsCls == NULL ) {
		multiCapsCls = java_libburn_find_class(env, "org/pykix/libburnia/libburn/MultiCaps");
		if ( multiCapsCls == NULL ) {
			return NULL;
		}

	}

	if ( cid == NULL ) {
		cid = (*env)->GetMethodID(env, multiCapsCls, "<init>", "(ZZZJJJIIIIISZZ)V");
		if (cid == NULL) {
		    return NULL; /* exception thrown */
		}
	}

	jobject mc = (*env)->NewObject(env, multiCapsCls, cid, caps->multi_session, caps->multi_track,
		caps->start_adr, caps->start_alignment, caps->start_range_low, caps->start_range_high,
		caps->might_do_tao, caps->might_do_sao, caps->might_do_raw, caps->advised_write_mode,
		caps->selected_write_mode, caps->current_profile, caps->current_is_cd_profile, res);

	burn_disc_free_multi_caps(&caps);

	return mc;
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_read
 * Signature: (JJ)V
 */
JNIEXPORT void JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1read
(
	JNIEnv *env, jclass cls, jlong d, jlong o
)
{
	burn_disc_read( (struct burn_drive *) d, (const struct burn_read_opts *) o);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_get_formats
 * Signature: (J)Lorg/pykix/libburnia/libburn/Formats;
 */
JNIEXPORT jobject JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1get_1formats
(
	JNIEnv *env, jclass cls, jlong d
)
{
	int status;
	off_t size;
	unsigned bl_sas;
	int num_formats;
	static jclass formatsCls = NULL;
	static jmethodID cid = NULL;
	
	if ( burn_disc_get_formats( (struct burn_drive *) d, &status, &size,
				&bl_sas, &num_formats) != 1 ) {
		return NULL;
	}

	if ( formatsCls == NULL ) {
		formatsCls = java_libburn_find_class(env, "org/pykix/libburnia/libburn/Formats");
		if ( formatsCls == NULL ) {
			return NULL;
		}

	}

	if ( cid == NULL ) {
		cid = (*env)->GetMethodID(env, formatsCls, "<init>", "(IJII)V");
		if (cid == NULL) {
		    return NULL; /* exception thrown */
		}
	}

	return (*env)->NewObject(env, formatsCls, cid, status, size, bl_sas, num_formats);
}

/*
 * Class:     org_pykix_libburnia_libburn_Drive
 * Method:    burn_disc_get_format_descr
 * Signature: (JI)Lorg/pykix/libburnia/libburn/FormatDesc;
 */
JNIEXPORT jobject JNICALL 
Java_org_pykix_libburnia_libburn_Drive_burn_1disc_1get_1format_1descr
(
	JNIEnv *env, jclass cls, jlong d, jint index
)
{
	int type;
	off_t size;
	unsigned tdp;
	static jclass formatDescCls = NULL;
	static jmethodID cid = NULL;
	
	if ( burn_disc_get_format_descr( (struct burn_drive *) d, index,
				&type, &size, &tdp) != 1 ) {
		return NULL;
	}

	if ( formatDescCls == NULL ) {
		formatDescCls = java_libburn_find_class(env, "org/pykix/libburnia/libburn/FormatDesc");
		if ( formatDescCls == NULL ) {
			return NULL;
		}

	}

	if ( cid == NULL ) {
		cid = (*env)->GetMethodID(env, formatDescCls, "<init>", "(IJI)V");
		if (cid == NULL) {
		    return NULL; /* exception thrown */
		}
	}

	return (*env)->NewObject(env, formatDescCls, cid, type, size, tdp);
}


