package unit.tree;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

import org.neo4j.api.core.EmbeddedNeo;
import org.neo4j.api.core.Transaction;
import org.neo4j.tutor.tree.File;
import org.neo4j.tutor.tree.FileFactory;
import org.neo4j.tutor.tree.MyRelationshipTypes;

public class TestFile extends TestCase
{
	public TestFile( String testName )
	{
		super( testName );
	}
	
	public static Test suite()
	{
		TestSuite suite = new TestSuite( TestFile.class );
		return suite;
	}
	
	private EmbeddedNeo neo;
	private Transaction tx;
	
	
	public void setUp()
	{
		neo = new EmbeddedNeo( MyRelationshipTypes.class, "var/file-test", 
			true );
		FileFactory.getFactory().injectNeo( neo );
		tx = Transaction.begin();
	}
	
	public void tearDown()
	{
		tx.finish();
		neo.shutdown();
	}
	
	public void testSimpleCreate()
	{
		FileFactory factory = FileFactory.getFactory();
		assertTrue( factory.createNewFile( "test" ) != null );
	}
	
	public void testChangeFileName()
	{
		FileFactory factory = FileFactory.getFactory();
		File file = factory.createNewFile( "test" );
		if ( file != null )
		{
			file.changeFileName( "new_name" );
			assertEquals( "Unable to change file name", "new_name", 
				file.getFileName() );
		}
		else
		{
			fail( "FileFactory create new file returned null" );
		}
		try
		{
			file.changeFileName( null );
			fail( "null name should throw IllegalArgumentException" );
		}
		catch ( IllegalArgumentException e )
		{ // good
		}
	}
	
	public void testSimpleChildParent()
	{
		FileFactory factory = FileFactory.getFactory();
		File parent = factory.createNewFile( "parent" );
		File child = factory.createNewFile( "child" );
		if ( parent != null && child != null )
		{
			parent.addChild( child );
			assertEquals( "Child file didn't return correct parent", parent, 
				child.getParent() );
		}
		else
		{
			fail( "FileFactory create new file returned null" );
		}
	}
	
	public void testDisconnectFromParent()
	{
		FileFactory factory = FileFactory.getFactory();
		File parent = factory.createNewFile( "parent" );
		File child = factory.createNewFile( "child" );
		if ( parent != null && child != null )
		{
			parent.addChild( child );
			child.disconnectFromParent();
			assertEquals( "Child file didn't return null parent", null, 
				child.getParent() );
			child.disconnectFromParent();
			assertEquals( "Child file didn't return null parent", null, 
				child.getParent() );
		}
		else
		{
			fail( "FileFactory create new file returned null" );
		}
	}
	
	public void testCreateChangeDelete()
	{
		FileFactory factory = FileFactory.getFactory();
		try
		{
			factory.createNewFile( null );
		}
		catch ( IllegalArgumentException e )
		{ // good
		}
		File file1 = factory.createNewFile( "root1" );
		File file2 = factory.createNewFile( "root2" );
		// just commit stuff we created so far
		tx.success();
		tx.finish();
		tx = Transaction.begin();
		assertEquals( "root1", file1.getFileName() );
		assertEquals( "root2", file2.getFileName() );
		file1.changeFileName( "root3" );
		assertEquals( "root3", file1.getFileName() );
		file1.delete();
		file2.delete();
		tx.success();
		// commit in tearDown
	}
	
	public void testParentChild()
	{
		FileFactory factory = FileFactory.getFactory();
		File root = factory.createNewFile( "root" );
		assertTrue( root.getParent() == null );
		File child1 = factory.createNewFile( "child1" );
		root.addChild( child1 );
		assertTrue( root.getParent() == null );
		assertEquals( root, child1.getParent() );
		int count = 0;
		for ( File child : root.getChildren() )
		{
			assertEquals( child, child1 );
			count++;
		}
		assertEquals( 1, count );
		// just commit stuff we created so far
		tx.success();
		tx.finish();
		tx = Transaction.begin();
		File child2 = factory.createNewFile( "child2" );
		root.addChild( child2 );
		count = 0;
		for ( File child : root.getChildren() )
		{
			assertTrue( child.equals( child1 ) || child.equals( child2 ) );
			count++;
		}
		assertEquals( 2, count );
		child1.disconnectFromParent();
		assertTrue( child1.getParent() == null );
		// verify we can do disconnect many times
		child1.disconnectFromParent();
		// add one more depth
		File child21 = factory.createNewFile( "child21" );
		File child22 = factory.createNewFile( "child22" );
		child2.addChild( child21 );
		child2.addChild( child22 );
		tx.success();
		tx.finish();
		tx = Transaction.begin();
		count = 0;
		for ( File child : child2.getChildren() )
		{
			assertTrue( child.equals( child21 ) || child.equals( child22 ) );
			count++;
		}
		assertEquals( 2, count );
		count = 0;
		for ( File child : root.getChildren() )
		{
			assertEquals( child, child2 );
			count++;
		}
		assertEquals( 1, count );
		// cleanup
		root.delete(); // root,child2,child21,child22
		child1.delete();
		tx.success();
		// commit in tearDown
	}
	
	public void testWrongAddChild()
	{
		FileFactory factory = FileFactory.getFactory();
		File root = factory.createNewFile( "root" );
		File child1 = factory.createNewFile( "child1" );
		File child2 = factory.createNewFile( "child2" );
		root.addChild( child1 );
		root.addChild( child2 );
		try
		{
			child1.addChild( child2 );
		}
		catch ( IllegalArgumentException e )
		{ // good
		}
		tx.success();
	}
}
