/*
 * Copyright (c) 2002-2004 David Keiichi Watanabe
 * davew@xlife.org
 *
 * Modified by (c) 2004-2005 heavy_baby
 * heavy_baby@users.sourceforge.jp
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU 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 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.
 */

package jp.sourceforge.cabos;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import com.limegroup.gnutella.Endpoint;
import com.limegroup.gnutella.GUID;
import com.limegroup.gnutella.ManagedConnection;
import com.limegroup.gnutella.RemoteFileDesc;
import com.limegroup.gnutella.RouterService;
import com.limegroup.gnutella.Uploader;
import com.limegroup.gnutella.downloader.HTTPDownloader;
import com.limegroup.gnutella.downloader.ManagedDownloader;
import com.limegroup.gnutella.search.HostData;
import com.limegroup.gnutella.settings.ApplicationSettings;
import com.limegroup.gnutella.settings.ConnectionSettings;
import com.limegroup.gnutella.settings.DownloadSettings;
import com.limegroup.gnutella.settings.FilterSettings;
import com.limegroup.gnutella.settings.SharingSettings;
import com.limegroup.gnutella.settings.UltrapeerSettings;
import com.limegroup.gnutella.settings.UploadSettings;
import com.limegroup.gnutella.util.NetworkUtils;
import com.limegroup.gnutella.util.StringUtils;

public class AqDispatcher {
	/* Instances */

	private static int currentQueryIndex = -1;

	/* Dispatch */

	protected static void dispatchCommand(List v) throws Exception {

		String command = (String) v.get(0);
		String firstElement = (v.size() > 1) ? (String) v.get(1) : "";
		int intValue;
		try {
			intValue = new Integer(firstElement).intValue();
		} catch (Exception e) {
			intValue = 0;
		}

		/* Ultrapeer Settings */

		if (command.equals("setEnableUltrapeer")) {
			UltrapeerSettings.DISABLE_ULTRAPEER_MODE.setValue(intValue == 0);
		}

		/* Query */

		else if (command.equals("query")) {
			GUID guid = new GUID(RouterService.newQueryGUID());
			String queryIndex = ++currentQueryIndex + "";
			AqEventHandler.queriesToIndices.put(guid, queryIndex);
			AqEventHandler.indicesToQueries.put(queryIndex, guid);
			RouterService.query(guid.bytes(), StringUtils
					.createQueryString(firstElement), "", null);
		}

		else if (command.equals("queryWhatIsNew")) {
			GUID guid = new GUID(RouterService.newQueryGUID());
			String queryIndex = ++currentQueryIndex + "";
			AqEventHandler.queriesToIndices.put(guid, queryIndex);
			AqEventHandler.indicesToQueries.put(queryIndex, guid);
			RouterService.queryWhatIsNew(guid.bytes(), null);
		}

		else if (command.equals("removeQuery")) {
			for (int i = 1; i < v.size(); i++) {
				String index = (String) v.get(i);
				GUID guid = (GUID) AqEventHandler.indicesToQueries.get(index);
				if (guid == null)
					continue;
				RouterService.stopQuery(guid);
				AqEventHandler.queriesToIndices.remove(guid);
				AqEventHandler.indicesToQueries.remove(index);
				index = index + ":";
				synchronized (AqEventHandler.queryGUIDs) {
					for (Iterator itr = AqEventHandler.queryGUIDs.keySet()
							.iterator(); itr.hasNext();) {
						String queryString = (String) itr.next();
						if (queryString.startsWith(index))
							itr.remove();
					}
				}
				synchronized (AqEventHandler.responses) {
					for (Iterator itr = AqEventHandler.responses.keySet()
							.iterator(); itr.hasNext();) {
						String queryString = (String) itr.next();
						if (queryString.startsWith(index))
							itr.remove();
					}
				}
				synchronized (AqEventHandler.alts) {
					for (Iterator itr = AqEventHandler.alts.keySet().iterator(); itr
							.hasNext();) {
						String queryString = (String) itr.next();
						if (queryString.startsWith(index))
							itr.remove();
					}
				}

			}
		}

		else if (command.equals("removeAllQueries")) {
			synchronized (AqEventHandler.queriesToIndices) {
				for (Iterator itr = AqEventHandler.queriesToIndices.keySet()
						.iterator(); itr.hasNext(); RouterService
						.stopQuery((GUID) itr.next()))
					;
			}
			AqEventHandler.queriesToIndices.clear();
			AqEventHandler.indicesToQueries.clear();
			AqEventHandler.queryGUIDs.clear();
			AqEventHandler.responses.clear();
			AqEventHandler.alts.clear();
		}

		else if (command.equals("clearAllResults")) {
			for (int i = 1; i < v.size(); i++) {
				String index = (String) v.get(i);
				GUID guid = (GUID) AqEventHandler.indicesToQueries.get(index);
				if (guid == null)
					continue;
				index = index + ":";
				synchronized (AqEventHandler.queryGUIDs) {
					for (Iterator itr = AqEventHandler.queryGUIDs.keySet()
							.iterator(); itr.hasNext();) {
						String queryString = (String) itr.next();
						if (queryString.startsWith(index))
							itr.remove();
					}
				}
				synchronized (AqEventHandler.responses) {
					for (Iterator itr = AqEventHandler.responses.keySet()
							.iterator(); itr.hasNext();) {
						String queryString = (String) itr.next();
						if (queryString.startsWith(index))
							itr.remove();
					}
				}
				synchronized (AqEventHandler.alts) {
					for (Iterator itr = AqEventHandler.alts.keySet().iterator(); itr
							.hasNext();) {
						String queryString = (String) itr.next();
						if (queryString.startsWith(index))
							itr.remove();
					}
				}
			}
		}

		/* Filter Settings */

		else if (command.equals("setAdultFilter")) {
			FilterSettings.FILTER_WHATS_NEW_ADULT.setValue(intValue == 1);
			FilterSettings.FILTER_ADULT.setValue(intValue == 1);
		}

		else if (command.equals("clearWords")) {
			String words[] = new String[0];
			FilterSettings.BANNED_WORDS.setValue(words);
		}

		else if (command.equals("addWord")) {
			List oldWords = Arrays.asList(FilterSettings.BANNED_WORDS
					.getValue());
			List newWords = new ArrayList(oldWords);
			newWords.add(firstElement);
			String[] resultArray = (String[]) newWords
					.toArray(new String[newWords.size()]);
			FilterSettings.BANNED_WORDS.setValue(resultArray);
		}

		else if (command.equals("removeWord")) {
			List oldWords = Arrays.asList(FilterSettings.BANNED_WORDS
					.getValue());
			List newWords = new ArrayList(oldWords);
			newWords.remove(firstElement);
			String[] resultArray = (String[]) newWords
					.toArray(new String[newWords.size()]);
			FilterSettings.BANNED_WORDS.setValue(resultArray);
		}

		else if (command.equals("finishFilterSettings")) {
			RouterService.adjustSpamFilters();
		}

		/* Downloads */

		else if (command.equals("download")) {
			GUID guid = (GUID) AqEventHandler.queryGUIDs.get(firstElement);
			Set preMainRFDs = new HashSet();
			Set preOtherRFDs = new HashSet();

			for (int i = 1; i < v.size(); i++) {
				String index = (String) v.get(i);
				Object main = AqEventHandler.responses.get(index);
				Object other = AqEventHandler.alts.get(index);
				if (main != null && other != null) {
					preMainRFDs.add(main);
					preOtherRFDs.addAll((Set) other);
				}
			}

			RemoteFileDesc[] mainRFDs = (RemoteFileDesc[]) preMainRFDs
					.toArray(new RemoteFileDesc[preMainRFDs.size()]);
			RemoteFileDesc sha1RFD = null;
			for (int i = 0; i < mainRFDs.length; i++) {
				RemoteFileDesc next = mainRFDs[i];
				next.setDownloading(true);
				next.setRetryAfter(0);
				if (next.getSHA1Urn() != null)
					sha1RFD = next;
				preOtherRFDs
						.remove(new Endpoint(next.getHost(), next.getPort()));
			}
			if (sha1RFD == null)
				sha1RFD = mainRFDs[0];

			List otherRFDs = new LinkedList();
			for (Iterator i = preOtherRFDs.iterator(); i.hasNext();) {
				Endpoint next = (Endpoint) i.next();
				otherRFDs.add(new RemoteFileDesc(sha1RFD, next));
			}

			RouterService.download(mainRFDs, otherRFDs, guid, false);
		}

		else if (command.equals("pauseDownload")) {
			for (Iterator i = AqEventHandler.downloads.iterator(); i.hasNext();) {
				ManagedDownloader d = (ManagedDownloader) i.next();
				if (d != null && d.hashCode() == intValue && d.isActive()) {
					d.pause();
					break;
				}
			}
		}

		else if (command.equals("retryDownload")) {
			for (Iterator i = AqEventHandler.downloads.iterator(); i.hasNext();) {
				ManagedDownloader d = (ManagedDownloader) i.next();
				if (d != null && d.hashCode() == intValue && d.isInactive()) {
					d.resume();
					break;
				}
			}
		}

		else if (command.equals("cancelDownload")) {
			for (Iterator i = AqEventHandler.downloads.iterator(); i.hasNext();) {
				ManagedDownloader d = (ManagedDownloader) i.next();
				if (d != null && d.hashCode() == intValue) {
					d.manualCancel();
					break;
				}
			}
		}

		else if (command.equals("restoreIncompleteFiles")) {
			File incompleteDir = SharingSettings.INCOMPLETE_DIRECTORY
					.getValue();
			File[] files = incompleteDir.listFiles();
			for (int i = 0; i < files.length; i++) {
				File f = files[i];
				if (f.getName().startsWith("T-") && f.canRead() && f.canWrite()) {
					try {
						RouterService.download(f);
					} catch (Exception e) {
					}
				}
			}
		}

		/* Download Settings */

		else if (command.equals("setMaxSimDownload")) {
			DownloadSettings.MAX_SIM_DOWNLOAD.setValue(intValue);
		}

		else if (command.equals("setDownloadSpeed")) {
			int oldValue = DownloadSettings.DOWNLOAD_SPEED.getValue();
			DownloadSettings.DOWNLOAD_SPEED.setValue(intValue);
			if (intValue != oldValue)
				HTTPDownloader.applyRate();
		}

		/* Uploads */

		else if (command.equals("cancelUpload")) {
			for (Iterator i = AqEventHandler.uploads.iterator(); i.hasNext();) {
				Uploader u = (Uploader) i.next();
				if (u != null && u.hashCode() == intValue) {
					u.stop();
					break;
				}
			}
		}

		/* Upload Settings */

		else if (command.equals("setMaxUploads")) {
			UploadSettings.HARD_MAX_UPLOADS.setValue(intValue);
		}

		else if (command.equals("setUploadsPerPerson")) {
			UploadSettings.UPLOADS_PER_PERSON.setValue(intValue);
		}

		else if (command.equals("setUploadSpeed")) {
			UploadSettings.UPLOAD_SPEED.setValue(intValue);
		}

		else if (command.equals("setAllowPartialSharing")) {
			UploadSettings.ALLOW_PARTIAL_SHARING.setValue(intValue == 1);
		}

		/* Connections */

		else if (command.equals("closeConnection")) {
			int port = new Integer((String) v.get(2)).intValue();
			for (Iterator i = RouterService.getConnectionManager()
					.getConnections().iterator(); i.hasNext();) {
				ManagedConnection c = (ManagedConnection) i.next();
				if (c != null && c.getAddress().equals(firstElement)
						&& c.getPort() == port) {
					RouterService.removeConnection(c);
					break;
				}
			}
		}

		else if (command.equals("awakeConnection")) {
			RouterService.disconnect();
			RouterService.connect();
		}

		/* Connection Settings */

		else if (command.equals("setConnectionSpeed")) {
			ConnectionSettings.CONNECTION_SPEED.setValue(intValue);
		}

		else if (command.equals("setPort")) {
			int oldPort = ConnectionSettings.PORT.getValue();
			if (intValue != oldPort && NetworkUtils.isValidPort(intValue)) {
				try {
					ConnectionSettings.PORT.setValue(intValue);
					ConnectionSettings.FORCED_PORT.setValue(intValue);
					RouterService.setListeningPort(intValue);
					RouterService.addressChanged();
				} catch (Exception e) {
					ConnectionSettings.PORT.setValue(oldPort);
					ConnectionSettings.FORCED_PORT.setValue(oldPort);
				}
			}
		}

		else if (command.equals("setUPnPType")) {
			boolean oldForce = ConnectionSettings.FORCE_IP_ADDRESS.getValue();

			if (intValue == 0) { // Enable UPnP
				if (!ConnectionSettings.UPNP_IN_USE.getValue())
					ConnectionSettings.FORCE_IP_ADDRESS.setValue(false);
				ConnectionSettings.DISABLE_UPNP.setValue(false);
			} else if (intValue == 1) { // Manual port foward
				ConnectionSettings.DISABLE_UPNP.setValue(false);
				ConnectionSettings.FORCE_IP_ADDRESS.setValue(true);
				ConnectionSettings.UPNP_IN_USE.setValue(false);
			} else { // Disable UPnP
				ConnectionSettings.FORCE_IP_ADDRESS.setValue(false);
				ConnectionSettings.DISABLE_UPNP.setValue(true);
			}

			boolean newForce = ConnectionSettings.FORCE_IP_ADDRESS.getValue();
			
			if (newForce != oldForce)
				RouterService.addressChanged();
		}

		else if (command.equals("setUsesLocalePreferencing")) {
			ConnectionSettings.USE_LOCALE_PREF.setValue(intValue == 1);
		}

		/* doBrowseHost */

		else if (command.equals("doBrowseHost")) {
			GUID guid = new GUID(RouterService.newQueryGUID());
			String queryIndex = ++currentQueryIndex + "";
			AqEventHandler.queriesToIndices.put(guid, queryIndex);
			AqEventHandler.indicesToQueries.put(queryIndex, guid);

			String host = firstElement;
			int port = new Integer((String) v.get(2)).intValue();
			HostData hd = (HostData) AqEventHandler.hosts
					.get(host + ":" + port);

			if (hd != null)
				RouterService.doAsynchronousBrowseHost(host, port, guid,
						new GUID(hd.getClientGUID()), hd.getPushProxies(), hd
								.supportsFWTransfer());
			else
				RouterService.doAsynchronousBrowseHost(host, port, guid, null,
						null, false);
		}

		/* Sharing Settings */

		else if (command.equals("setDirectories")) {
			Set newDirectories = new HashSet();
			for (int i = 1; i < v.size(); i++) {
				String filename = (String) v.get(i);
				if (!filename.equals("")) {
					File f = new File(filename);
					if (f != null)
						newDirectories.add(f);
				}
			}
			Set oldDirectories = SharingSettings.DIRECTORIES_TO_SHARE
					.getValue();
			if (!newDirectories.equals(oldDirectories)) {
				SharingSettings.DIRECTORIES_TO_SHARE.setValue(newDirectories);
				RouterService.getFileManager().loadSettings();
			}
		}

		else if (command.equals("setSaveDirectory")) {
			if (firstElement.equals(""))
				SharingSettings.setSaveDirectory(SharingSettings.DEFAULT_SAVE_DIR);
			else
				SharingSettings.setSaveDirectory(new File(firstElement));
		}

		else if (command.equals("setIncompletePurgeTime")) {
			SharingSettings.INCOMPLETE_PURGE_TIME.setValue(intValue);
		}

		else if (command.equals("setAllowFreeloaders")) {
			if (intValue == 1)
				SharingSettings.FREELOADER_ALLOWED.setValue(100);
			else
				SharingSettings.FREELOADER_ALLOWED.setValue(0);
		}

		else if (command.equals("setFreeloaderFiles")) {
			SharingSettings.FREELOADER_FILES.setValue(intValue);
		}

		else if (command.equals("setAllowCompleteSharing")) {
			SharingSettings.SHARE_DOWNLOADED_FILES_IN_NON_SHARED_DIRECTORIES
					.setValue(intValue == 1);
		}

		/* Proxy Settings */

		else if (command.equals("setProxyType")) {
			ConnectionSettings.CONNECTION_METHOD.setValue(intValue);
		}

		else if (command.equals("setProxyServer")) {
			ConnectionSettings.PROXY_HOST.setValue(firstElement);
		}

		else if (command.equals("setProxyPort")) {
			ConnectionSettings.PROXY_PORT.setValue(intValue);
		}

		else if (command.equals("setProxyUsername")) {
			ConnectionSettings.PROXY_USERNAME.setValue(firstElement);
		}

		else if (command.equals("setProxyPassword")) {
			ConnectionSettings.PROXY_PASS.setValue(firstElement);
		}

		else if (command.equals("setProxyPrivate")) {
			ConnectionSettings.USE_PROXY_FOR_PRIVATE.setValue(intValue == 1);
		}

		else if (command.equals("setRequiresAuthentication")) {
			ConnectionSettings.PROXY_AUTHENTICATE.setValue(intValue == 1);
		}

		/* Application Settings */

		else if (command.equals("setLanguage")) {
			if (firstElement.equals(""))
				ApplicationSettings.LANGUAGE.revertToDefault();
			else
				ApplicationSettings.LANGUAGE.setValue(firstElement);
		}

		/* Initialization Complete */

		else if (command.equals("initComplete")) {
			AqEvent.signalEvent(AqEvent.kLWEventCoreInitialized);
		}

		/* shutdown */

		else if (command.equals("shutdown")) {
			AqMain.shouldShutdown = true;
		}

		/* Catch-All */

		else {
			System.err.println("AqDispatcher: Unhandled command: " + v);
		}
	}
}