/*******************************************************************************
 * Copyright (c) 2004 Actuate Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *  Actuate Corporation  - initial API and implementation
 *******************************************************************************/

package org.eclipse.birt.core.archive;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

import junit.framework.TestCase;

public class FileArchiveTest extends TestCase
{

	static final String ARCHIVE_NAME = "./utest/test.archive";
	static final String TEMP_FOLDER_NAME = "./utest/test.archive.tmpfolder";
	static final String STREAM_NAME = "/teststream";

	public void setUp( )
	{
		ArchiveUtil.DeleteAllFiles( new File( ARCHIVE_NAME ) );
		ArchiveUtil.DeleteAllFiles( new File( TEMP_FOLDER_NAME ) );
	}

	public void tearDown( )
	{
		ArchiveUtil.DeleteAllFiles( new File( TEMP_FOLDER_NAME ) );
		ArchiveUtil.DeleteAllFiles( new File( ARCHIVE_NAME ) );
	}

	public void testReaderAfterWriter( ) throws Exception
	{
		FileArchiveWriter writer = new FileArchiveWriter( ARCHIVE_NAME );
		writer.initialize( );
		RAOutputStream ws = writer.createRandomAccessStream( STREAM_NAME );
		ws.writeInt( 1 );
		ws.flush( );
		ws.writeLong( -1L );
		ws.flush( );
		ws.close( );
		writer.finish( );

		FileArchiveReader reader = new FileArchiveReader( ARCHIVE_NAME );
		reader.open( );
		RAInputStream rs = reader.getStream( STREAM_NAME );
		assertEquals( 1, rs.readInt( ) );
		assertEquals( -1L, rs.readLong( ) );
		rs.close( );
		reader.close( );
	}

	public void testOpenEmptyFile( ) throws IOException
	{
		new RandomAccessFile( ARCHIVE_NAME, "rw" ).close( );
		try
		{
			FileArchiveReader reader = new FileArchiveReader( ARCHIVE_NAME );
			try
			{
				reader.open( );
			}
			finally
			{
				reader.close( );
			}
		}
		catch ( IOException ex )
		{
			assertTrue( true );
			return;
		}
		assertTrue( false );
	}

	public void testOpenNoneExistFile( )
	{
		new File( ARCHIVE_NAME ).delete( );
		try
		{
			FileArchiveReader reader = new FileArchiveReader( ARCHIVE_NAME );
			try
			{
				reader.open( );
			}
			finally
			{
				reader.close( );
			}
		}
		catch ( IOException ex )
		{
			assertTrue( !new File( ARCHIVE_NAME ).exists( ) );
			assertTrue( true );
			return;
		}
		assertTrue( false );
	}

	public void testMutipleThreadReadWrite( )
	{
		Command wrtCmd = new Command( );
		Command readCmd = new Command( );

		new Thread( new WriterRunnable( wrtCmd ) ).start( );
		new Thread( new ReaderRunnable( readCmd ) ).start( );
		new Thread( new ReaderRunnable( readCmd ) ).start( );
		new Thread( new ReaderRunnable( readCmd ) ).start( );
		new Thread( new ReaderRunnable( readCmd ) ).start( );
		new Thread( new ReaderRunnable( readCmd ) ).start( );
		new Thread( new ReaderRunnable( readCmd ) ).start( );
		sendCommand( wrtCmd, Command.OPEN );
		sendCommand( wrtCmd, Command.WRITING );
		sendCommand( wrtCmd, Command.CLOSE );
		sendCommand( wrtCmd, Command.EXIT );
		sendCommand( readCmd, Command.OPEN );
		sendCommand( readCmd, Command.READING );
		sendCommand( readCmd, Command.CLOSE );
		sendCommand( readCmd, Command.OPEN );
		sendCommand( readCmd, Command.READING );
		sendCommand( readCmd, Command.CLOSE );
		sendCommand( readCmd, Command.EXIT );
	}

	protected void sendCommand( Command command, int code )
	{
		synchronized ( command )
		{
			command.command = code;
			command.ex = null;
			command.status = Command.STATUS_START;
			command.notifyAll( );
		}
		while ( command.status != Command.STATUS_FINISH )
		{
			try
			{
				Thread.sleep( 1000 );
			}
			catch ( Exception ex )
			{

			}
		}
		if ( command.ex != null )
		{
			fail( "Exception occurs" );
		}
	}

	static class Command
	{

		static final int STATUS_START = 1;
		static final int STATUS_FINISH = 0;

		static final int OPEN = 1;
		static final int CLOSE = 2;
		static final int WRITING = 3;
		static final int READING = 4;
		static final int EXIT = 6;
		int command;
		int status;
		int threads;
		Exception ex;
	}

	class WriterRunnable implements Runnable
	{

		Command command;
		FileArchiveWriter writer;

		WriterRunnable( Command command )
		{
			this.command = command;
			this.command.threads++;
		}

		protected void doOpen( ) throws Exception
		{
			if ( writer == null )
			{
				writer = new FileArchiveWriter( ARCHIVE_NAME );
				writer.initialize( );
			}
		}

		protected void doWrite( ) throws Exception
		{
			if ( writer != null )
			{
				RAOutputStream os = writer
						.createRandomAccessStream( "/test.txt" );
				os.writeInt( -1 );
				os.writeInt( -1 );
				os.close( );
			}
		}

		protected void doClose( ) throws Exception
		{
			if ( writer != null )
			{
				writer.finish( );
				writer = null;
			}
		}

		public void run( )
		{
			while ( true )
			{
				synchronized ( command )
				{
					try
					{
						command.wait( );
					}
					catch ( InterruptedException e )
					{

					}
				}
				System.out.println( command.command );
				try
				{
					switch ( command.command )
					{
						case Command.OPEN :
							doOpen( );
							break;
						case Command.WRITING :
							doWrite( );
							break;
						case Command.CLOSE :
							doClose( );
							break;
						case Command.EXIT :
							command.status = Command.STATUS_FINISH;
							return;
					}
				}
				catch ( Exception ex )
				{
					ex.printStackTrace( );
					command.ex = ex;
				}
				command.status = Command.STATUS_FINISH;
			}
		}
	}

	class ReaderRunnable implements Runnable
	{

		Command command;
		FileArchiveReader reader;

		ReaderRunnable( Command command )
		{
			this.command = command;
			this.command.threads++;
		}

		protected void doOpen( ) throws Exception
		{
			if ( reader == null )
			{
				reader = new FileArchiveReader( ARCHIVE_NAME );
				reader.open( );
			}

		}

		protected void doRead( ) throws Exception
		{
			if ( reader != null )
			{
				RAInputStream is = reader.getStream( "/test.txt" );
				is.readInt( );
				is.readInt( );
				is.close( );
			}

		}

		protected void doClose( ) throws Exception
		{
			if ( reader != null )
			{
				reader.close( );
				reader = null;
			}
		};

		public void run( )
		{
			while ( true )
			{
				synchronized ( command )
				{
					try
					{
						command.wait( );
					}
					catch ( InterruptedException e )
					{

					}
				}

				System.out.println( command.command );
				try
				{
					switch ( command.command )
					{
						case Command.OPEN :
							doOpen( );
							break;
						case Command.READING :
							doRead( );
							break;
						case Command.CLOSE :
							doClose( );
							break;
						case Command.EXIT :
							command.status = Command.STATUS_FINISH;
							return;
					}
				}
				catch ( Exception ex )
				{
					ex.printStackTrace( );
					command.ex = ex;
				}
				command.status = Command.STATUS_FINISH;
			}

		}
	}

	/**
	 * test the open stream, get length etc.
	 */
	public void testOpenStream( ) throws Exception
	{
		FileArchiveWriter writer = new FileArchiveWriter( ARCHIVE_NAME );
		writer.initialize( );
		RAOutputStream ws = writer.createRandomAccessStream( STREAM_NAME );
		ws.writeInt( 1 );
		assertEquals( 4, ws.length( ) );
		ws.flush( );
		ws.writeLong( -1L );
		assertEquals( 12, ws.length( ) );
		ws.flush( );
		ws.close( );
		ws = writer.openRandomAccessStream( STREAM_NAME );
		assertEquals( 12, ws.length( ) );
		writer.finish( );
	}
}
