/***************************************************************************
 *   Copyright (C) by Fabrizio Montesi <famontesi@gmail.com>               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 *                                                                         *
 *   For details about the authors of this software, see the AUTHORS file. *
 ***************************************************************************/

package joliex.io;

import java.io.BufferedReader;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.channels.Channels;
import java.nio.channels.ClosedByInterruptException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import jolie.net.CommMessage;
import jolie.runtime.JavaService;
import jolie.runtime.Value;
import jolie.runtime.embedding.RequestResponse;

public class ConsoleService extends JavaService
{
	private Map< String, String > sessionTokens;
	private boolean sessionListeners = false;
	private boolean enableTimestamp = false;
	private final String timestampFormatDefault = "dd/MM/yyyy HH:mm:ss";
	private String timestampFormat = timestampFormatDefault;

	private class ConsoleInputThread extends Thread
	{
		private boolean keepRun = true;

		public void kill()
		{
			keepRun = false;
			this.interrupt();
		}

		@Override
		public void run()
		{
			BufferedReader stdin
				= new BufferedReader(
					new InputStreamReader(
						Channels.newInputStream(
							(new FileInputStream( FileDescriptor.in )).getChannel() ) ) );
			try {
				String line;
				while( keepRun ) {
					line = stdin.readLine();

					if ( sessionListeners ) {
						Iterator it = sessionTokens.keySet().iterator();

						while( it.hasNext() ) {
							Value v = Value.create();
							v.getFirstChild( "token" ).setValue( it.next() );
							v.setValue( line );
							sendMessage( CommMessage.createRequest( "in", "/", v ) );
						}
					} else {
						sendMessage( CommMessage.createRequest( "in", "/", Value.create( line ) ) );
					}
				}
			} catch( ClosedByInterruptException ce ) {
			} catch( Exception e ) {
				e.printStackTrace();
			} finally {
				try {
					stdin.close();
				} catch( IOException e ) {
					interpreter().logWarning( e );
				}
			}
		}
	}
	private ConsoleInputThread consoleInputThread;

	@RequestResponse
	public void registerForInput( Value request )
	{
		if ( request.getFirstChild( "enableSessionListener" ).isDefined() ) {
			if ( request.getFirstChild( "enableSessionListener" ).boolValue() ) {
				sessionListeners = true;
				sessionTokens = new HashMap<String, String>();

			}
		}
		consoleInputThread = new ConsoleInputThread();
		consoleInputThread.start();
	}

	@Override
	protected void finalize()
	{
		consoleInputThread.kill();
	}

	@RequestResponse
	public void print( String s )
	{
		if ( enableTimestamp ) {
			try {
				SimpleDateFormat sdf = new SimpleDateFormat( timestampFormat );
				final Date now = new Date();
				String ts = sdf.format( now );
				System.out.print( ts + " " + s );
			} catch( Exception e ) {
				System.out.print( "Bad Format " + s );
			}
		} else {
			System.out.print( s );
		}
	}

	@RequestResponse
	public void println( String s )
	{
		if ( enableTimestamp ) {
			try {
				SimpleDateFormat sdf = new SimpleDateFormat( timestampFormat );
				final Date now = new Date();
				String ts = sdf.format( now );
				System.out.println( ts + " " + s );
			} catch( Exception e ) {
				System.out.println( "Bad Format " + s );
			}
		} else {
			System.out.println( s );
		}
	}

	@RequestResponse
	public void enableTimestamp( Value request )
	{
		boolean enable = request.boolValue();
		if ( enable ) {
			enableTimestamp = true;
			if ( request.getFirstChild( "format" ).isDefined() ) {
				timestampFormat = request.getFirstChild( "format" ).strValue();
			} else {
				timestampFormat = timestampFormatDefault;
			}
		} else {
			enableTimestamp = false;
			timestampFormat = timestampFormatDefault;
		}

	}

	@RequestResponse
	public void subscribeSessionListener( Value request )
	{
		String token = request.getFirstChild( "token" ).strValue();

		if ( sessionListeners ) {
			sessionTokens.put( token, token );

		}
	}

	@RequestResponse
	public void unsubscribeSessionListener( Value request )
	{
		String token = request.getFirstChild( "token" ).strValue();

		if ( sessionListeners ) {
			sessionTokens.remove( token );
		}
	}
}

@@ -3805,16 +3805,17 @@
 HashMap%3C
+ 
 String, 
@@ -3824,14 +3824,14 @@
 ring
+ 
 %3E();%0A
-%0A
 %09%09%09%7D
@@ -3961,38 +3961,105 @@
 ()%0A%09
-%7B%0A%09%09consoleInputThread.kill();
+%09throws Throwable%0A%09%7B%0A%09%09try %7B%0A%09%09%09consoleInputThread.kill();%0A%09%09%7D finally %7B%0A%09%09%09super.finalize();%0A%09%09%7D
 %0A%09%7D%0A

Call super.finalize in ConsoleService.