// Copyright (c) 2002 Alexandre Brillant
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library 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 Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.


package jason.service.admin;

import jason.core.*;
import jason.core.pool.AbstractTask;
import jason.core.pool.Task;

import java.io.*;
import java.net.*;
import java.util.*;

/**
 * Admin
 * Service that offers administration capacity for @ws. 
 * It can for known user stops and starts special service. It
 * can be invoked due to a crash or a configuration changement
 *
 * Next release could include information about working
 *
 * @author Alexandre Brillant <abrillant@wanadoo.fr>
 * @version 1.1 */
public class AdminService extends SocketService {

    public static String TYPE = "admin";

    public AdminService() {
	super();
	initActions();
	try {
	    setType( new ServiceType( ServiceType.JASON_SERVICE, new String[] { TYPE } ) );
	} catch( ServiceException exc ) {
	    fireCriticalErrorDetected( exc );
	}
    }

    // Deciding what action to do depending on the command name
    private void initActions() {
	htActions = new Hashtable();
	htActions.put( "START", new StartAction() );
	htActions.put( "STOP", new StopAction() );
    }

    protected Task getTaskForSocket( Socket host ) throws ServiceException {
	return new AdminProcessing( host );
    }

    /**
     * Scan the command and send a response to output */
    private void parseCommand( String line, OutputStream out ) throws IOException {
	try {
	    StringTokenizer stz = new StringTokenizer( line );
	    String name = stz.nextToken();
	    String password = stz.nextToken();
	    String command = stz.nextToken();
	    String param = stz.nextToken();

	    String adminName = getProperty( "admin" );
	    String adminPassword = getProperty( "password" );

	    if ( !adminName.equals( name ) | !adminPassword.equals( password ) )
		sendResponse( out, "Unknown user" );
	    else {
		// Process command
		AdminAction action = (AdminAction)htActions.get( command );
		if ( action == null ) 
		    action = new DefaultAction();
		action.actionPerformed( command, param );
	    }
	} catch( Exception exc ) {
	    exc.printStackTrace();
	    sendResponse( out, "Error" );
	}
    }

    // Send a response
    private void sendResponse( OutputStream out, String message ) throws IOException {
	out.write( message.getBytes() );
	out.write( "\n".getBytes() );
	out.flush();
    }

    private void sendResponse( String message ) throws IOException {
	sendResponse( out, message );
    }

    private OutputStream out;
    private Hashtable htActions;

    // Inner interface for admin action
    interface AdminAction {
	public void actionPerformed( String command, String param ) throws IOException;
    }

    // Invalid action
    class DefaultAction implements AdminAction {
	public void actionPerformed( String command, String param ) throws IOException {
	    sendResponse( "Unknown command" );
	}
    }

    // Stop a service
    class StopAction implements AdminAction {
	public void actionPerformed( String command, String param ) throws IOException {
	    Service[] services = getServiceContext().getServices();
	    for ( int i = 0; i < services.length; i++ )
		if ( param.equals( services[ i ].getName() ) ) {
		    services[ i ].stop();
		    sendResponse( "ok" );
		    return;
		}
	    sendResponse( "Don't know service " + param );
	}
    }

    // Start a service
    class StartAction implements AdminAction {
	public void actionPerformed( String command, String param ) throws IOException {
	    Service[] services = getServiceContext().getServices();
	    for ( int i = 0; i < services.length; i++ )
		if ( param.equals( services[ i ].getName() ) ) {
		    services[ i ].start();
		    sendResponse( "ok" );
		    return;
		}
	    sendResponse( "Don't know service " + param );
	}
    }

    /////////////////////////////

    class AdminProcessing extends AbstractTask {
	private Socket host;

	public AdminProcessing( Socket host ) {
	    this.host = host;
	}

	public void run() {
	    try {
		InputStream in = host.getInputStream();
		out = host.getOutputStream();
		BufferedReader br = new BufferedReader( new InputStreamReader( in ) );
		String command = br.readLine();
		sendInformationMessage( command );
		parseCommand( command, out );
		// We needn't maintain connection
		host.close();
	    } catch( IOException ex ) {
		sendErrorMessage( ex.getMessage() );
	    }
	}
    }

}