/*
 * 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.IOException;
import java.util.Locale;
import java.util.Set;

import com.limegroup.gnutella.FileDesc;
import com.limegroup.gnutella.GUID;
import com.limegroup.gnutella.InsufficientDataException;
import com.limegroup.gnutella.ManagedConnection;
import com.limegroup.gnutella.RemoteFileDesc;
import com.limegroup.gnutella.Uploader;
import com.limegroup.gnutella.downloader.ManagedDownloader;
import com.limegroup.gnutella.search.HostData;
import com.limegroup.gnutella.util.StringUtils;
import com.limegroup.gnutella.xml.LimeXMLDocument;

public class AqEvent {
	/* State */

	private static final String kSep = "<aq/>";

	/* Event Codes */

	protected static final int kLWEventQueryResult = 1;

	protected static final int kLWEventConnectionInitialized = 2;

	protected static final int kLWEventConnectionClosed = 3;

	protected static final int kLWEventConnectionsUpdated = 4;

	protected static final int kLWEventAddDownload = 5;

	protected static final int kLWEventRemoveDownload = 6;

	protected static final int kLWEventUpdateDownloadStats = 7;

	protected static final int kLWEventDownloadsUpdated = 8;

	protected static final int kLWEventAddUpload = 9;

	protected static final int kLWEventRemoveUpload = 10;

	protected static final int kLWEventUpdateUploadStats = 11;

	protected static final int kLWEventUploadsUpdated = 12;

	protected static final int kLWEventAddSharedFile = 13;

	protected static final int kLWEventCoreConnected = 97;

	protected static final int kLWEventCoreSettingRequest = 98;

	protected static final int kLWEventCoreInitialized = 99;

	/* Signal */

	private static String decodeXMLString(String string) {
		if (string == null)
			return "";

		string = StringUtils.replace(string, "&amp;", "&");
		string = StringUtils.replace(string, "&lt;", "<");
		string = StringUtils.replace(string, "&gt;", ">");
		string = StringUtils.replace(string, "&apos;", "\'");
		string = StringUtils.replace(string, "&quot;", "\"");

		return string;
	}

	protected static void signalEvent(int type) {
		signalEvent(type, null, null, null);
	}

	protected static void signalEvent(int type, Object obj) {
		signalEvent(type, obj, null, null);
	}

	protected static void signalEvent(int type, Object obj, Object obj1) {
		signalEvent(type, obj, obj1, null);
	}

	protected static void signalEvent(int type, Object obj, Object obj2,
			Object obj3) {
		String event = null;

		try {
			switch (type) {

			/* Queries */

			case kLWEventQueryResult: {
				RemoteFileDesc r = (RemoteFileDesc) obj;
				HostData hd = (HostData) obj2;
				Set locs = (Set) obj3;

				/* index */

				String queryIndex;
				synchronized (AqEventHandler.queriesToIndices) {
					queryIndex = (String) AqEventHandler.queriesToIndices
							.get(new GUID(hd.getMessageGUID()));
				}

				/* note RFD */

				String localIndex = ++AqEventHandler.currentLocalIndex + "";
				String putIndex = queryIndex + ":" + localIndex;
				synchronized (AqEventHandler.queryGUIDs) {
					AqEventHandler.queryGUIDs.put(putIndex, new GUID(hd
							.getMessageGUID()));
				}
				synchronized (AqEventHandler.responses) {
					AqEventHandler.responses.put(putIndex, r);
				}
				synchronized (AqEventHandler.alts) {
					AqEventHandler.alts.put(putIndex, locs);
				}

				/* bitrate & xml metadata */

				int bitrate = 0;
				int seconds = 0;
				String artist = "";
				String album = "";
				String title = "";

				if (r.getXMLDocument() != null) {
					LimeXMLDocument xml = r.getXMLDocument();

					String bitrateValue = xml
							.getValue("audios__audio__bitrate__");
					if (bitrateValue != null) {
						try {
							bitrate = new Integer(bitrateValue).intValue();
						} catch (Exception e) {
						}
						if (bitrate > 320)
							bitrate = 0;
					}

					String secondsValue = xml
							.getValue("audios__audio__seconds__");
					if (secondsValue != null) {
						try {
							seconds = new Integer(secondsValue).intValue();
						} catch (Exception e) {
						}
						if (seconds > 86400)
							seconds = 0; // 60 * 60 * 24
					}

					artist = decodeXMLString(xml
							.getValue("audios__audio__artist__"));
					album = decodeXMLString(xml
							.getValue("audios__audio__album__"));
					title = decodeXMLString(xml
							.getValue("audios__audio__title__"));

					/* license */

					if (xml.getLicenseString() != null)
						artist = "<" + xml.getLicenseString() + "> " + artist;
				}

				/* browse host */

				String address = hd.getIP() + ":" + hd.getPort();

				int bh = (hd.isBrowseHostEnabled()) ? 1 : 0;

				if (bh == 1)
					AqEventHandler.hosts.put(address, hd);

				event = (type + kSep + queryIndex + kSep + localIndex + kSep
						+ locs.size() + kSep + address + kSep + bh + kSep
						+ r.getSHA1Urn() + kSep + r.getFileName() + kSep
						+ r.getSpeed() + kSep + r.getSize() + kSep + bitrate
						+ kSep + seconds + kSep + artist + kSep + album + kSep + title);
				break;
			}

			/* Connections */

			case kLWEventConnectionInitialized: {
				ManagedConnection c = (ManagedConnection) obj;

				/* display language */

				String displayLanguage = (new Locale(c.getLocalePref(), ""))
						.getDisplayLanguage();

				/* connection type */

				String connectionType;
				if (c.isSupernodeClientConnection())
					connectionType = "Leaf";
				else if (c.isClientSupernodeConnection())
					connectionType = "Ultrapeer";
				else if (c.isSupernodeSupernodeConnection())
					connectionType = "Peer";
				else
					connectionType = "Standard";

				event = (type + kSep + c.getAddress() + kSep + c.getPort()
						+ kSep + c.getUserAgent() + kSep + displayLanguage
						+ kSep + connectionType);
				break;
			}

			case kLWEventConnectionClosed: {
				ManagedConnection c = (ManagedConnection) obj;

				event = (type + kSep + c.getAddress() + kSep + c.getPort());
				break;
			}

			/* Downloads */

			case kLWEventAddDownload: {
				ManagedDownloader d = (ManagedDownloader) obj;

				event = (type + kSep + d.hashCode() + kSep
						+ d.getSaveFile().getName() + kSep + d.getState()
						+ kSep + d.getContentLength() + kSep
						+ d.getAmountRead() + kSep + d.getDownloadSHA1());
				break;
			}

			case kLWEventRemoveDownload: {
				ManagedDownloader d = (ManagedDownloader) obj;

				event = (type + kSep + d.hashCode());

				AqEventHandler.stateCache.remove("" + d.hashCode());

				/* Delete Aborted Download */

				if (d.isManualCanceled() && d.getFile() != null)
					d.getFile().delete();
				break;
			}

			case kLWEventUpdateDownloadStats: {
				ManagedDownloader d = (ManagedDownloader) obj;

				/* bandwidth */

				float b = d.getMeasuredBandwidth() * 1024;
				float b1 = d.getAverageBandwidth() * 1024;

				/* path */

				String p = (d.getFile() != null) ? d.getFile().toString() : "";

				event = (type + kSep + d.hashCode() + kSep + d.getState()
						+ kSep + d.getContentLength() + kSep
						+ d.getAmountRead() + kSep + b + kSep + b1 + kSep
						+ d.getActiveHostCount() + kSep + d.getBusyHostCount()
						+ kSep + d.getPossibleHostCount() + kSep
						+ d.getQueuedHostCount() + kSep + p + kSep + d
						.getActiveHosts());

				String representationInfo = "" + d.hashCode();
				if (event.equals((String) AqEventHandler.stateCache
						.get(representationInfo)))
					event = null;
				else
					AqEventHandler.stateCache.put(representationInfo, event);

				break;
			}

			/* Uploads */

			case kLWEventAddUpload: {
				Uploader u = (Uploader) obj;

				String p = (u.getFileDesc() != null) ? u.getFileDesc()
						.getPath() : "";

				int bh = (u.isBrowseHostEnabled()) ? 1 : 0;

				event = (type + kSep + u.hashCode() + kSep + u.getFileName()
						+ kSep + u.getHost() + kSep + u.getGnutellaPort()
						+ kSep + u.getUserAgent() + kSep + u.getState() + kSep
						+ u.getAmountRequested() + kSep + p + kSep + bh);
				break;
			}

			case kLWEventRemoveUpload: {
				Uploader u = (Uploader) obj;

				event = (type + kSep + u.hashCode());

				AqEventHandler.stateCache.remove("" + u.hashCode());

				break;
			}

			case kLWEventUpdateUploadStats: {
				Uploader u = (Uploader) obj;

				float b = 0;
				float b1 = 0;
				try {
					b = u.getMeasuredBandwidth() * 1024;
					b1 = u.getAverageBandwidth() * 1024;
				} catch (InsufficientDataException e) {
				}

				event = (type + kSep + u.hashCode() + kSep + u.getState()
						+ kSep + u.getFileSize() + kSep
						+ u.getTotalAmountUploaded() + kSep + b + kSep + b1);

				String representationInfo = "" + u.hashCode();
				if (event.equals((String) AqEventHandler.stateCache
						.get(representationInfo)))
					event = null;
				else
					AqEventHandler.stateCache.put(representationInfo, event);

				break;
			}

			/* Sharing */

			case kLWEventAddSharedFile: {
				FileDesc f = (FileDesc) obj;

				event = (type + kSep + f.getSHA1Urn());
				break;
			}

			/* Default */

			default: {
				String s1 = (obj != null) ? (kSep + obj) : "";
				String s2 = (obj2 != null) ? (kSep + obj2) : "";
				String s3 = (obj3 != null) ? (kSep + obj3) : "";

				event = (type + s1 + s2 + s3);
				break;
			}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		if (AqMain.writer != null && event != null) {
			synchronized (AqMain.writer) {
				try {
					AqMain.writer.write(event);
					AqMain.writer.write("\n");
					AqMain.writer.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}
}