package org.neo4j.tutor.search;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import org.neo4j.api.core.EmbeddedNeo;
import org.neo4j.api.core.Node;
import org.neo4j.api.core.Relationship;
import org.neo4j.api.core.Transaction;

public class Search
{
	private static SearchEngine searchEngine;
	private static EmbeddedNeo neo = null;
	
	public static void main( String args[] )
	{
		neo = new EmbeddedNeo( MyRelationshipTypes.class, "var/search", true );
		boolean shellEnabled = false;
		Transaction tx = Transaction.begin();
		try
		{
			searchEngine = new SearchEngine( neo );
			readTranslationProperties();
			if ( args.length == 1 )
			{
				if ( args[0].equals( "setup" ) )
				{
					setupSomeTestData();
					getDocuments();
					dumpInformation();
					System.out.println();
				}
				else if ( args[0].equals( "clean" ) )
				{
					getDocuments();
					cleanTestData();
					System.out.println( "Cleaned." );
				}
				else if ( args[0].equals( "dump" ) )
				{
					getDocuments();
					dumpInformation();
				}
				else if ( args[0].equals( "shell" ) )
				{
					Runtime.getRuntime().addShutdownHook( new ShutdownHook() );	
					neo.enableRemoteShell( Collections.EMPTY_MAP );
					shellEnabled = true;
				}
				else
				{
					usage();
				}
				tx.success();
				return;
			}
			if ( args.length != 2 )
			{
				usage();
				return;
			}
			getDocuments();
			String lang = args[0];
			String keyword = args[1];
			System.out.println( "Performing search: " + lang + " " + keyword );
			Iterable<Node> documents = searchEngine.searchDocuments( lang, 
				keyword );
			if ( !documents.iterator().hasNext() )
			{
				System.out.println( "No documents found." );
			}
			else
			{
				System.out.println( "Search returned: " );
				for ( Node document : documents )
				{
					System.out.print( "Document[" + document.getId() + "] " );
				}
				System.out.println();
			}
			tx.success();
		}
		catch ( Exception e )
		{
			e.printStackTrace();
		}
		finally
		{
			tx.finish();
			if ( !shellEnabled )
			{
				neo.shutdown();
			}
		}
	}

	private static Node[] documents = new Node[0];
	
	private static void readTranslationProperties()
	{
		Properties props = new Properties();
		try
		{
			props.load( new FileInputStream( new File( 
				"etc/translations.properties" ) ) );
		}
		catch ( IOException e )
		{
			System.out.println( "Error reading translation file: " + e );
		}
		searchEngine.injectTranslations( props );
	}
	
	private static void setupSomeTestData()
	{
		int documentsToCreate = 3;
		for ( int i = 0; i < documentsToCreate; i++ )
		{
			Node document = neo.createNode();
			neo.getReferenceNode().createRelationshipTo( document,
				MyRelationshipTypes.DOCUMENT );
			Node keyword = searchEngine.getRandomKeyword();
			if ( keyword != null )
			{
				document.createRelationshipTo( keyword, 
					MyRelationshipTypes.HAS_KEYWORD );
			}
		}
	}
	
	private static void getDocuments()
	{
		List<Node> docList = new ArrayList<Node>();
		for ( Relationship rel : neo.getReferenceNode().getRelationships( 
			MyRelationshipTypes.DOCUMENT ) )
		{
			docList.add( rel.getEndNode() );
		}
		documents = docList.toArray( new Node[ docList.size() ] );
	}

	private static void dumpInformation()
	{
		for ( Node document : documents )
		{
			System.out.print( "Document[" + document.getId() + "]: " );
			for ( Relationship rel : document.getRelationships( 
				MyRelationshipTypes.HAS_KEYWORD ) )
			{
				Node keywordNode = rel.getEndNode();
				System.out.print( keywordNode.getProperty( 
					AbstractSearchEngine.LANGUAGE_ID ) + "," + 
					keywordNode.getProperty( 
						AbstractSearchEngine.KEYWORD_NAME ) );
			}
			System.out.println();
		}
	}
	
	private static void cleanTestData()
	{
		searchEngine.clean();
		for ( Node node : documents )
		{
			for ( Relationship rel : node.getRelationships() )
			{
				rel.delete();
			}
			node.delete();
		}
	}

	private static void usage()
	{
		System.out.println( "\nUsage: Search setup -- create test data" );
		System.out.println( "Usage: Search clean -- clean test data"  );
		System.out.println( "Usage: Search dump -- dump test data"  );
		System.out.println( "Usage: Search <lang> <keyword> -- search" );
		System.out.println( "Usage: Search shell -- enable shell" );
	}

	private static class ShutdownHook extends Thread
	{
		ShutdownHook()
		{
		}
		
		public void run()
		{
			neo.shutdown();
		}
	}
}
