/*
 * IsoTreeNode.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.libisofs;

import java.io.File;
import java.io.FileNotFoundException;

import org.pykix.libburnia.bindings.Proxy;

/**
 * A node in the filesystem tree.
 * 
 * @author Vreixo Formoso
 * @since 0.1
 */
public class IsoTreeNode extends Proxy {

	/*
	 * Package protected
	 */
	IsoTreeNode(long ptr) {
		super(ptr);
	}
	
	/**
	 * Add a file to this node (have to be a directory).
	 * 
	 * @param path
	 * 		The path, on the local filesystem, of the file. Have to be not a
	 * 		directory, but a file.
	 * @return
	 * 		An IsoTreeNode whose path is <code>path</code> and whose parent
	 * 		is this node.
	 * @throws FileNotFoundException
	 * 		If path not exists or is not a file.
	 */
	public IsoTreeNode addNode(String path) throws FileNotFoundException {
		return addNode(this, new File(path));
	}

	/**
	 * Add a file to this node (have to be a directory).
	 * 
	 * @param path
	 * 		The path, on the local filesystem, of the file. Have to be not a
	 * 		directory, but a file.
	 * @return
	 * 		An IsoTreeNode whose path is <code>path</code> and whose parent
	 * 		is this node.
	 * @throws FileNotFoundException
	 * 		If path not exists or is not a file.
	 */
	public IsoTreeNode addNode(File path) throws FileNotFoundException {
		return addNode(this, path);
	}
	
	/**
	 * Recursively add an existing directory as a child of this node, that have
	 * to be a directory.
	 * Warning: when using this, you'll lose files or subdirectories objects.
	 * If you want to have all files and directories objects,
	 * use {@link #addNode(File)} and {@link #addNewDir(String)}
	 * 
	 * @param path
	 * 		The path, on the local filesystem, of the directory to add.
	 * @return
	 * 		The new created node or <code>null</code>.
	 * @throws FileNotFoundException
	 * 		If path not exists or is not a directory
	 */
	public IsoTreeNode raddDir(String path) throws FileNotFoundException {
		return raddDir(this, new File(path));
	}

	/**
	 * Recursively add an existing directory as a child of this node, that have
	 * to be a directory.
	 * Warning: when using this, you'll lose files or subdirectories objects.
	 * If you want to have all files and directories objects,
	 * use {@link #addNode(File)} and {@link #addNewDir(String)}
	 * 
	 * @param path
	 * 		The path, on the local filesystem, of the directory to add.
	 * @return
	 * 		The new created node or <code>null</code>.
	 * @throws FileNotFoundException
	 * 		If path not exists or is not a directory
	 */
	public IsoTreeNode raddDir(File path) throws FileNotFoundException {
		return raddDir(this, path);
	}
	
	/* this function is for testing purposes mainly */
	void print(int spaces) {
		iso_tree_print( pointerOf(this), spaces);
	}
	
	/**
	 * Set the name of the node (using the current locale).
	 * 
	 * @param name
	 * 		Name to set
	 */
	public void setName(String name) {
		iso_tree_node_set_name( pointerOf(this), name);
	}

	/**
	 * Creates a new directory as a child of this node (have to be a
	 * directory).
	 * 
	 * @param name
	 * 		Name of the directory to create. Must be a unique name among 
	 * 		all node children, and mustn't contain '/' characters.
	 * @return
	 * 		The newly created directory.
	 */
	public IsoTreeNode addNewDir(String name) {
		return addNewDir(this, name);
	}
	
	/**
	 * Add a file to a directory.
	 * 
	 * @param parent
	 * 		Node to which add file. Can be <code>null</code>, but if
	 * 		not it must be a directory.
	 * @param path
	 * 		The path, on the local filesystem, of the file. Have to be non-dir
	 * @return
	 * 		An IsoTreeNode whose path is <code>path</code> and whose parent 
	 * 		is <code>parent</code>.
	 * @throws FileNotFoundException 
	 * 		If path not exists or is not a file
	 */
	public static IsoTreeNode addNode(IsoTreeNode parent, File path) 
	throws FileNotFoundException {
		
		long pptr = (parent == null) ? 0 : pointerOf(parent);
		
		/* extra check */
		if ( !path.exists() ) {
			throw new FileNotFoundException(path.getPath());
		}
		if ( !path.isFile() ) {
			throw new FileNotFoundException(path + " is not a file");
		}
		
		long ptr = iso_tree_add_node(pptr, path.getPath());
		
		return (ptr == 0) ? null : new IsoTreeNode(ptr);
	}
	
	/**
	 * Recursively add an existing directory to the tree.
	 * Warning: when using this, you'll lose files or subdirectories objects.
	 * If you want to have all files and directories objects,
	 * use {@link #addNode(File)} and {@link #addNewDir(String)}.
	 * 
	 * @param parent
	 * 		Node to which add file. Can be <code>null</code>, but if
	 * 		not it must be a directory.
	 * @param path
	 * 		The path, on the local filesystem, of the directory to add.
	 * @return
	 * 		The new created node or <code>null</code>.
	 * @throws FileNotFoundException
	 * 		If path not exists or is not a directory
	 */
	public static IsoTreeNode raddDir(IsoTreeNode parent, File path) 
	throws FileNotFoundException {
		
		long pptr = (parent == null) ? 0 : pointerOf(parent);
		
		/* extra check */
		if ( !path.exists() ) {
			throw new FileNotFoundException(path.getPath());
		}
		if ( !path.isDirectory() ) {
			throw new FileNotFoundException(path + " is not a directory");
		}
		
		long ptr = iso_tree_radd_dir(pptr, path.getPath());
		
		return (ptr == 0) ? null : new IsoTreeNode(ptr);
	}
	
	/**
	 * Creates a new, empty directory on the volume.
	 * 
	 * @param parent
	 * 		Directory in which add the new dir, or <code>null</code>
	 * @param name
	 * 		Name of the directory to create. Must be a unique name among 
	 * 		the children and files belonging to parent, and mustn't 
	 * 		contain '/' characters.
	 * @return
	 * 		The newly created directory.
	 */
	public static IsoTreeNode addNewDir(IsoTreeNode parent, String name) {
		
		long pptr = (parent == null) ? 0 : pointerOf(parent);
		
		long ptr = iso_tree_add_new_dir(pptr, name);
		
		return (ptr == 0) ? null : new IsoTreeNode(ptr);
	}
	
	private static native long iso_tree_add_node(long parent, String path);
	
	private static native long iso_tree_radd_dir(long parent, String path);

	private static native void iso_tree_print(long root, int spaces);

	private static native void iso_tree_node_set_name(long file, String name);
	
	private static native long iso_tree_add_new_dir(long parent, String name);
	
	static {
		System.loadLibrary("java-libburn-0.1");
	}
}
