/*
 * WriteOpts.java
 *
 * 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.
 */

package org.pykix.libburnia.libburn;

import org.pykix.libburnia.bindings.Proxy;

/**
 * References a set of write parameters.
 * 
 * <p>
 * To get a new <code>WriteOpts</code> object, you have to call
 * {@link Drive#newWriteOpts()} method.
 * 
 * @author Vreixo Formoso
 * @since 0.1
 */
public class WriteOpts extends Proxy {

	/* package protected */
	WriteOpts(long ptr) {
		super(ptr);
	}
	
	/**
	 * Sets the write type for the WriteOpts.
	 * 
	 * <p>
	 * Note: write type {@link WriteType#SAO} is currently not capable of 
	 * writing a mix of data and audio tracks. You must use 
	 * {@link WriteType#TAO} for such sessions.
	 * 
	 * @param writeType
	 * 		The write type to use.
	 * @param blockType
	 * 		The block type to use.
	 * @return
	 * 		<code>true</code> on success, <code>false</code> on failure.
	 */
	public boolean setWriteType( WriteType writeType, BlockType blockType ) {
		
		int bt = blockType.code;
		int wt = writeType.ordinal();
		
		return burn_write_opts_set_write_type( pointerOf(this), wt, bt);
	}
	
	/**
	 * As an alternative to {@link #setWriteType(WriteType, BlockType)} 
	 * this function tries to find a suitable write type and block type for a 
	 * given write job described by this opts and disc. To be used after all 
	 * other setups have been made, i.e. immediately before 
	 * {@link Drive#write(WriteOpts, Disc)}.
	 * 
	 * @param disc
	 * 		The already composed session and track model.
	 * @param flag
	 * 		Bitfield for control purposes:
	 * 		    bit0= do not choose type but check the one that is already set
	 * 		    bit1= do not issue error messages via burn_msgs queue
	 * 		          (is automatically set with bit0)
	 * @return
	 * 		Chosen write type or {@link WriteType#NONE} on failure.
	 */
	/*
	 * TODO a C returning field, reasons, is forgeting by this implementation
	 */
	public WriteType setAutoWriteType(Disc disc, int flag) {
		
		int wt = burn_write_opts_auto_write_type( pointerOf(this),
				pointerOf(disc), flag);
		
		return WriteType.values()[wt];
	}
	
	/**
	 * Sets the simulate value for the WriteOpts object.
	 * 
	 * @param sim
	 * 		If <code>true</code>, the drive will perform a simulation 
	 * 		instead of a burn
	 * @return
	 * 		<code>true</code> on success, <code>false</code> on failure.
	 */
	public boolean setSimulate(boolean sim) {
		return burn_write_opts_set_simulate( pointerOf(this), sim );
	}
	
	/**
	 * Controls buffer underrun prevention.
	 * 
	 * @param underrunProof
	 * 		if <code>true</code>, buffer underrun protection is enabled
	 * @return
	 * 		<code>true</code> on success, <code>false</code> on failure.
	 */
	public boolean setUnderrunProof(boolean underrunProof) {
		return burn_write_opts_set_underrun_proof( pointerOf(this), 
				underrunProof);
	}
	
	/**
	 * Sets whether to use OPC (Optical Power Calibration) 
	 * or not with this WriteOpts object.
	 * 
	 * @param opc
	 * 		if <code>true </code>, OPC will be performed at
	 * 		start of burn.
	 */
	public void setPerformOpc(boolean opc) {
		burn_write_opts_set_perform_opc( pointerOf(this), opc );
	}
	
	/**
	 * Sets the multi flag which eventually marks the emerging session as not
	 * being the last one and thus creating a {@link DiscStatus#APPENDABLE} 
	 * media.
	 * 
	 * @param multi
	 * 		If <code>true</code> media will be appendable, if 
	 * 		<code>false</code> media will be closed (default) 
	 */
	public void setMulti(boolean multi) {
		burn_write_opts_set_multi( pointerOf(this), multi );
	}
	
	/**
	 * Eventually makes libburn ignore the failure of some conformance checks:
	 * 
	 * <ul>
	 *   <li>the check wether CD write+block type is supported by the drive.
	 * </ul>  
	 * 
	 * @param force
	 * 		if <code>true</code> ignore above checks, otherwise refuse work on
	 * 		failed check.
	 */
	public void setForce(boolean force) {
		burn_write_opts_set_force( pointerOf(this), force ? 1 : 0 );
	}
	
	/**
	 * Sets a start address for writing to media and write modes which allow to
	 * choose this address at all (DVD+RW, DVD-RAM, formatted DVD-RW only for
	 * now). The address is given in bytes. If it is not -1 then a write run
	 * will fail if choice of start address is not supported or if the block
	 * alignment of the address is not suitable for media and write mode.
	 * (Alignment to 32 kB blocks is advised with DVD media.)
	 * 
	 * @param value
	 * 		The address in bytes (-1 = start at default address).
	 */
	public void setStartByte(long value) {
		burn_write_opts_set_start_byte( pointerOf(this), value );
	}
	
	/**
	 * Sets the session format for a disc.
	 * 
	 * @param format
	 * 		The session format to set.
	 */
	public void setFormat(SessionFormat format) {
		burn_write_opts_set_format( pointerOf(this), format.code );
	}
	
	public void setHasMediaCatalog(boolean hasMediaCatalog) {
		burn_write_opts_set_has_mediacatalog( pointerOf(this), hasMediaCatalog );
	}
	
	public void setMediaCatalog(String mediaCatalog) {
		burn_write_opts_set_mediacatalog( pointerOf(this), mediaCatalog );
	}
	
	/**
	 * Examines a completed setup for {@link Drive#write(WriteOpts, Disc)} 
	 * wether it is permissible  with drive and media. 
	 * 
	 * <p>
	 * This function is called by {@link Drive#write(WriteOpts, Disc)} but
	 * an application might be interested in this check in advance.
	 * 
	 * @param disc
	 * 		The descrition of the disc to be created
	 * @param silent
	 * 		<code>true</code> to not issue error messages , <code>false</code> 
	 * 		to report problems
	 * @throws BurnException
	 * 		on failure, a list of rejection reason statements can be getted
	 * 		as exception msg.
	 */
	public void precheckWrite(Disc disc, boolean silent) throws BurnException {
		burn_precheck_write(pointerOf(this), pointerOf(disc), silent ? 1 : 0);
	}
	
	/**
	 * Caution: still immature and likely to change. Problems arose with
	 * sequential DVD-RW on one drive.
	 * 
	 * Controls wether the whole available space of the media shall be filled 
	 * up by the last track of the last session.
	 * 
	 * @param fillUpMedia
	 *		<code>true</code> to fill up by last track, <code>false</code> to
	 *		not fill up
	 */
	public void setFillUp(boolean fillUpMedia) {
		burn_write_opts_set_fillup( pointerOf(this), fillUpMedia);
	}
	
	/**
	 * Supplies toc entries for writing - not normally required for CD 
	 * mastering.
	 * 
	 * @param entries
	 * 		Toc entries.
	 */
	public void setTocEntries(TocEntry[] entries) {
		burn_write_opts_set_toc_entries( pointerOf(this), entries.length, 
				entries);
	}
	
	@Override
	protected void finalize() throws Throwable {
		super.finalize();
		burn_write_opts_free( pointerOf(this) );
	}

	private static native void burn_write_opts_free(long opts);
	
	private static native boolean burn_write_opts_set_write_type(long opts,
			   int writeType, int blockType);
	
	private static native int burn_write_opts_auto_write_type(long opts,
			long disc, int flag);

	private static native boolean burn_write_opts_set_simulate(long opts, 
			boolean sim);

	private static native boolean burn_write_opts_set_underrun_proof(long opts,
			boolean underrun_proof);

	private static native void burn_write_opts_set_perform_opc(long opts, 
			boolean opc);
	
	private static native void burn_write_opts_set_multi(long opts, 
			boolean multi);

	private static native void burn_write_opts_set_force(long opts, int useForce);

	private static native void burn_write_opts_set_start_byte(long opts, 
			long value);

	private static native void burn_write_opts_set_format(long opts, int format);

	private static native void burn_write_opts_set_has_mediacatalog(
			long opts, boolean has_mediacatalog);

	private static native void burn_write_opts_set_mediacatalog(
			long opts, String mediacatalog);
	
	private static native void burn_precheck_write(long o, long disc,
            int silent) throws BurnException;
	
	private static native void burn_write_opts_set_fillup(long opts,
			boolean fill_up_media);
	
	//TODO untested and enought complex to have some bugs!!
	private static native void burn_write_opts_set_toc_entries(long opts,
		     int count, TocEntry[] entries);
	
}
