/*
 * Written and copyright 2001-2003 Tobias Minich. Distributed under the GNU
 * General Public License; see the README file. This code comes with NO
 * WARRANTY.
 * 
 * Torrent.java
 * 
 * Created on 23.03.2004
 *
 */
package org.gudy.azureus2.ui.console.commands;

import java.io.PrintStream;
import java.util.Iterator;
import java.util.List;

import org.gudy.azureus2.core3.download.DownloadManager;
import org.gudy.azureus2.core3.download.DownloadManagerState;
import org.gudy.azureus2.core3.tracker.host.TRHost;
import org.gudy.azureus2.core3.tracker.host.TRHostTorrent;
import org.gudy.azureus2.core3.util.ByteFormatter;
import org.gudy.azureus2.core3.util.TorrentUtils;
import org.gudy.azureus2.ui.console.ConsoleInput;
import org.gudy.azureus2.ui.console.UserProfile;

/**
 * base class for objects which need to operate on specific torrents.
 * this class allows the torrent to be identified by hash, number or
 * 'all' and will pass the appropriate torrent(s) to the subclasses 'performCommand' method 
 * @author tobi
 */
public abstract class TorrentCommand extends IConsoleCommand {
	private final String action;
	
	/**
	 * initializes the torrent command
	 * @param commandNames (the first item in the array is regarded as the primary command name)
	 * @param action a description to be used when this command is executed
	 */
	public TorrentCommand(String main_name, String short_name, String action)
	{
		super(main_name, short_name);
		this.action = action;
	}

	protected String getAction()
	{
		return action;
	}
	protected abstract boolean performCommand(ConsoleInput ci, DownloadManager dm, List<String> args);
	
	/**
	 * Stub for commands that operate on a hosted torrent rather than downloadmanager
	 * @param ci
	 * @param args
	 * @return
	 */
	protected boolean performCommand(ConsoleInput ci, TRHostTorrent torrent, List<String> args)
	{
		return( false );
	}

	public void execute(String commandName, ConsoleInput ci, List<String> args)
	{
		if (!args.isEmpty()) {
		    String subcommand = (String) args.remove(0);
			if (ci.torrents.isEmpty()) {
				ci.out.println("> Command '" + getCommandName() + "': No torrents in list (Maybe you forgot to 'show torrents' first).");
			} else {
				String name;
				DownloadManager dm;
				try {
					int number = Integer.parseInt(subcommand);
					if ((number > 0) && (number <= ci.torrents.size())) {
						dm = (DownloadManager) ci.torrents.get(number - 1);
						if (dm.getDisplayName() == null)
							name = "?";
						else
							name = dm.getDisplayName();
						performCommandIfAllowed(ci, args, dm, "#" + subcommand, name);
					} else
						ci.out.println("> Command '" + getCommandName() + "': Torrent #" + subcommand + " unknown.");
				} catch (NumberFormatException e) {
					if ("all".equalsIgnoreCase(subcommand)) {
						Iterator torrent = ci.torrents.iterator();
						while (torrent.hasNext()) {
							dm = (DownloadManager) torrent.next();
							if (dm.getDisplayName() == null)
								name = "?";
							else
								name = dm.getDisplayName();
							performCommandIfAllowed(ci, args, dm, subcommand, name);
						}
					} else if ("hash".equalsIgnoreCase(subcommand)) {
						String hash = (String) args.remove(0); 
						List torrents = ci.getGlobalManager().getDownloadManagers();
						boolean foundit = false;
						Iterator torrent = torrents.iterator();
						while (torrent.hasNext()) {
							dm = (DownloadManager) torrent.next();
							if (hash.equals(TorrentUtils.nicePrintTorrentHash(dm.getTorrent(), true))) {
								if (dm.getDisplayName() == null)
									name = "?";
								else
									name = dm.getDisplayName();
								// FIXME: check user permission here and fix it to take torrent hash instead of subcommand
								
								performCommandIfAllowed(ci, args, dm, hash, name);
								foundit = true;
								break;
							}
						}
						if ( !foundit ){
							
								// second check for 
							
							TRHost host = ci.getCore().getTrackerHost();
						
							if ( host != null ){
								
								TRHostTorrent[] h_torrents = host.getTorrents();
								
								for (int i=0;i<h_torrents.length;i++){
									
									TRHostTorrent ht = h_torrents[i];
									
									if (hash.equals(TorrentUtils.nicePrintTorrentHash(ht.getTorrent(), true))) {
										
										name = TorrentUtils.getLocalisedName( ht.getTorrent());
										
										// FIXME: check user permission here and fix it to take torrent hash instead of subcommand
										
										performCommandIfAllowed(ci, args, ht, hash, name);
										foundit = true;
										break;

									}
								}
							}
						}
						
						if ( !foundit ){
							ci.out.println("> Command '" + getCommandName() + "': Hash '" + hash + "' unknown.");
						}
					} else {
						ci.out.println("> Command '" + getCommandName() + "': Subcommand '" + subcommand + "' unknown.");
					}
				}
			}
		} else {
			ci.out.println("> Missing subcommand for '" + getCommandName() + "'");
			printHelp(ci.out, args);			
		}
	}
	
	/**
	 * checks the role of the user. if the user is a 'guest', they are not able to 
	 * perform any actions on the torrents. they are a 'read only' role.
	 * if they are a 'user' role, they are only able to modify their own torrents.
	 * users with the 'admin' role can modify anybody's torrents
	 * @param ci
	 * @param args
	 * @param dm
	 * @param name
	 * @param subcommand
	 */
	private void performCommandIfAllowed(ConsoleInput ci, List args, DownloadManager dm, String desc, String name) {
		if( ! UserProfile.ADMIN.equals( ci.getUserProfile().getUserType() ) )
		{
			if( UserProfile.USER.equals( ci.getUserProfile().getUserType() ) )
			{
				String owner = dm.getDownloadState().getAttribute(DownloadManagerState.AT_USER);
				if(! ci.getUserProfile().getUsername().equals(owner) )
				{
					ci.out.println("> " + getAction() + " torrent " + desc + " (" + name + ") failed: Permission Denied. Users can only modify their own torrents");
					return;
				}
			}
			else
			{
				ci.out.println("> " + getAction() + " torrent " + desc + " (" + name + ") failed: Permission Denied. Guests cannot modify torrents");
				return;
			}
		}
		if (performCommand(ci, dm, args))
			ci.out.println("> " + getAction() + " Torrent " + desc + " (" + name + ") succeeded.");
		else
			ci.out.println("> " + getAction() + " Torrent " + desc + " (" + name + ") failed.");		
		
	}

	private void performCommandIfAllowed(ConsoleInput ci, List args, TRHostTorrent torrent, String desc, String name) {
		if( ! UserProfile.ADMIN.equals( ci.getUserProfile().getUserType() ) )
		{
			if( UserProfile.USER.equals( ci.getUserProfile().getUserType() ) )
			{
				// TODO: we don't currently record user against host-torrent...
			}
			else
			{
				ci.out.println("> " + getAction() + " torrent " + desc + " (" + name + ") failed: Permission Denied. Guests cannot modify torrents");
				return;
			}
		}
		if (performCommand(ci, torrent, args))
			ci.out.println("> " + getAction() + " Torrent " + desc + " (" + name + ") succeeded.");
		else
			ci.out.println("> " + getAction() + " Torrent " + desc + " (" + name + ") failed.");		
		
	}
	
	/**
	 * prints out the syntax of this command
	 */
	public void printHelpExtra(PrintStream out, List args) {
		out.println("> " + getCommandName() + " syntax: " + getCommandName() + " (<#>|all|hash <hash>)");
	}
}
