/*
 * Source.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 java.util.EnumSet;

import org.pykix.libburnia.bindings.Proxy;
import org.pykix.libburnia.libisofs.Ecma119ExtensionFlag;
import org.pykix.libburnia.libisofs.IsoVolSet;

/**
 * 
 * FIXME move here the newECma119 source
 * FIXME create java.io.File versions.
 * 
 * @author Vreixo Formoso
 * @since 0.1
 */
public final class Source extends Proxy implements BurnSource  {
	
	/**
	 * Creates a data source for an image file (and maybe subcode file).
	 * 
	 * @param path
	 * 		Path for the image file.
	 * @param subpath
	 * 		Path for the subcode file, or <code>null</code>.
	 */
	public Source(String path, String subpath) {
		super( burn_file_source_new(path, subpath) );
	}
	
	/**
	 * Creates a data source for an image file (a track) from an open
	 * readable file descriptor, an eventually open readable subcodes file
	 * descriptor and eventually a fixed size in bytes.
	 * 
	 * <p>
	 * You must take care that Unix file descriptor used by this constructor
	 * are not used by Java standard classes, so you must use your own
	 * functions/libraries to get these fds.
	 * 
	 * @param datafd
	 * 		The source of data.
	 * @param subfd
	 * 		The eventual source for subcodes. Not used if -1.
	 * @param size
	 * 		The eventual fixed size of eventually both fds. 
	 * 		If this value is 0, the size will be determined from datafd.
	 */
	public Source(int datafd, int subfd, long size) {
		super( burn_fd_source_new(datafd, subfd, size) );
	}

	/**
	 * Creates a data source from a ISO Volume Set.
	 * 
	 * TODO. The volume set used to create the libburn_source can _not_ be 
	 * modified until the libburn_source is freed. This is difficul to implement
	 * in Java, because user can't know when a object is actually freed, so
	 * for now IsoVolSet should not be modified anyway after call this.
	 * 
	 * @param volset
	 * 		The volume set to use as source.
	 * @param volnum
	 * 		The volume in the set which you want to write (usually 0)
	 * @param level
	 * 		ISO level to write at.
	 * @param flags
	 * 		Which extensions to support.
	 */
	public Source(IsoVolSet volset, int volnum, int level, 
			EnumSet<Ecma119ExtensionFlag> flags) {
		
		super( newEcma119Source(volset, volnum, level, flags) );
	}
	
	/**
	 * {@inheritDoc}
	 */
	public int read(byte[] buffer, int size) {
		
		if ( buffer.length < size ) {
			throw new IndexOutOfBoundsException("size bigger than buffer length");
		}
		
		return read( pointerOf(this), buffer, size);
	}

	/**
	 * {@inheritDoc}
	 */
	public int readSub(byte[] buffer, int size) {
		
		if ( buffer.length < size ) {
			throw new IndexOutOfBoundsException("size bigger than buffer length");
		}
		
		return read_sub( pointerOf(this), buffer, size);
	}
	
	/**
	 * {@inheritDoc}
	 */
	public long getSize() {
		return get_size(pointerOf(this));
	}

	/**
	 * {@inheritDoc}
	 */
	public int setSize(long bytes) {
		return set_size(pointerOf(this), bytes);
	}
	
	@Override
	protected void finalize() throws Throwable {
		super.finalize();
		burn_source_free(pointerOf(this));
	}

	private static long newEcma119Source(IsoVolSet volset, int volnum, int level, 
			EnumSet<Ecma119ExtensionFlag> flags) {
		
		int f = 0;
		
		if ( flags.contains(Ecma119ExtensionFlag.ROCKRIDGE) ) {
			f |= (1 << 0);
		}
		
		if ( flags.contains(Ecma119ExtensionFlag.JOLIET) ) {
			f |= (1 << 1);
		}
		
		return iso_source_new_ecma119(pointerOf(volset), volnum, level, f);
		
	}
	
	private static native long burn_file_source_new(String path, String subpath);

	private static native long burn_fd_source_new(int datafd, int subfd, 
			long size);
	
	private static native long iso_source_new_ecma119(long volumeset,
		    int volnum, int level, int flags);
	
	private static native int read(long ptr, byte [] buffer, int size);

	private static native int read_sub(long ptr, byte [] buffer, int size);

	private static native long get_size(long ptr);
	
	private static native int set_size(long ptr, long bytes);

	private static native void burn_source_free(long s);
}
