/*
 * Acquisition
 * http://www.xlife.org/
 *
 * Copyright (c) 2002-2003 David Keiichi Watanabe
 * davew@xlife.org
 *
 * 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.
 */

/* Java */
import java.io.*;
import java.util.*;

/* LimeWire */
import com.limegroup.gnutella.*;
import com.limegroup.gnutella.downloader.*;
import com.limegroup.gnutella.messages.*;
import com.limegroup.gnutella.search.*;
import com.limegroup.gnutella.security.*;
import com.limegroup.gnutella.xml.*;


public class AqEvent 
{
/* State */

    public static boolean shouldSignalEvents = true;
    public static final String kSep = "<aq/>";


/* Event Codes */

    public static final int kLWEventConnectionInitialized 	= 1;
    public static final int kLWEventConnectionClosed      	= 2;
    public static final int kLWEventUpdateConnectionStats 	= 3;
    public static final int kLWEventConnectionsUpdated    	= 14;

    public static final int kLWEventQueryResult            	= 5;

    public static final int kLWEventAddUpload             	= 6;
    public static final int kLWEventRemoveUpload          	= 7;
    public static final int kLWEventUpdateUploadStats     	= 8;
    public static final int kLWEventUploadsUpdated        	= 12;

    public static final int kLWEventAddDownload           	= 9;
    public static final int kLWEventRemoveDownload        	= 10;
    public static final int kLWEventUpdateDownloadStats   	= 11;
    public static final int kLWEventDownloadsUpdated      	= 13;

    public static final int kLWEventAddSharedFile		= 15;
    public static final int kLWEventAddSharedDirectory		= 16;


/* Util */

    public static String replaceStringWithString(String string, String target, String replacement) {
        int position;
        while (-1 < (position = string.indexOf(target))) {
            string = string.substring(0, position) + replacement + string.substring(position + target.length());
        }
        return string;
    }

    public static String correctedString(String string) {
        if (string == null) return null;
        
        //System.err.println("correctedString A: " + string);
        
        string = AqEvent.replaceStringWithString(string, "&apos;", "'");
        string = AqEvent.replaceStringWithString(string, "apos;", "'");
        string = AqEvent.replaceStringWithString(string, "&amp;", "");
        string = AqEvent.replaceStringWithString(string, "amp;", "");

        //System.err.println("correctedString B: " + string);
        return string;
    }


/* Signal */

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

    public static void signalEvent(int type, Object obj, Object obj2) 
    {
        if (!shouldSignalEvents) return;
        String event = null;
        
        switch(type)
        {

        /* Connections */
        
            case kLWEventConnectionInitialized:
            {
                ManagedConnection c = (ManagedConnection)obj;
                String ua = c.getUserAgent();

                String connectionType;
                if (c.isClientSupernodeConnection() || c.isSupernodeConnection())
                    connectionType = "Ultrapeer";
                else if (c.isSupernodeClientConnection())
                    connectionType = "Leaf";
                /* the following two cases should no longer occur */
                else if (ua != null)
                    connectionType = "Peer";
                else 
                    connectionType = "0.4 Peer";
                
                if (ua == null) ua = "";
                
                event = (
                    type 
                    + kSep + c.getIPString()
                    + kSep + c.getListeningPort()
                    + kSep + ua
                    + kSep + connectionType
                );
                break;
            }
            
            case kLWEventConnectionClosed:
            {
                ManagedConnection c = (ManagedConnection)obj;
                event = (
                    type 
                    + kSep + c.getIPString()
                    + kSep + c.getListeningPort()
                );
                break;
            }
            
            case kLWEventUpdateConnectionStats:
            {
                ManagedConnection c = (ManagedConnection)obj;

                ConnectionManager cm = RouterService.getConnectionManager();
                int total = cm.getNumInitializedConnections() + cm.getNumInitializedClientConnections();
                int negotiating = cm.getNumConnections() - total;
                if (negotiating < 0) negotiating = 0;

                event = (
                    type
                    + kSep + c.getIPString()
                    + kSep + c.getListeningPort()
                    + kSep + c.getNumFiles()
                    + kSep + negotiating
                );
                break;
            }

            case kLWEventConnectionsUpdated:
            {
                event = (
                    type
                    + ""
                );
                break;
            }
            
        /* Queries */
        
            case kLWEventQueryResult:
            {
                RemoteFileDesc r = (RemoteFileDesc)obj;
                HostData hd = (HostData)obj2;
                
                /* quality ranges from -1 to 3, where -1 is unreachable (both firewalled) */

                    int quality = hd.getQuality();
                    if (quality < 0) quality = 0;
                    if (quality == 3 && hd.getSpeed() > 2000 && hd.isMeasuredSpeed()) quality = 4;
                    
                /* index */

                    int queryIndex = AqEventHandler.queries.indexOf(new GUID(hd.getMessageGUID()).toString());

                /* note RFD */
                    
                    AqEventHandler.responses.add(r);
                    int localIndex = AqEventHandler.responses.size() - 1;
                
                /* bitrate & xml metadata */

                    int bitrate = 0;
                    String artist = null;
                    String album = null;
                    String year = null;
                    String title = null;
                    
                    LimeXMLDocument xml = (LimeXMLDocument)r.getXMLDoc();
                    if (xml != null) {
                        String value = xml.getValue("audios__audio__bitrate__");
                        if (value != null) {
                            try {
                                bitrate = new Integer(value).intValue();
                            } catch (Exception e) {
                                bitrate = 0;
                            }
                        }
    
                        artist = AqEvent.correctedString(xml.getValue("audios__audio__artist__"));
                        album  = AqEvent.correctedString(xml.getValue("audios__audio__album__"));
                        year   = xml.getValue("audios__audio__year__");
                        title  = AqEvent.correctedString(xml.getValue("audios__audio__title__"));
                    }

                    //System.err.println(artist + " " + album + " " + year);

                    /*
                    try {
                        String xmlString = xml.getXMLString();
                        System.err.println(xmlString);
                        //System.err.println(xml.getXMLString());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    */
                
                    if (bitrate > 1000) bitrate = 0;
                    if (artist == null) artist = "";
                    if (album == null) album = "";
                    if (year == null) year = "";
                    if (title == null) title = "";
                    
                /* browse host */
                
                    GUID cguid = new GUID(hd.getClientGUID());
                    int bh = (hd.isBrowseHostEnabled()) ? 1 : 0;
                    
                    if (!AqEventHandler.hosts.containsKey(hd.getIP() + hd.getPort())) {
                        AqEventHandler.hosts.put(hd.getIP() + hd.getPort(), cguid);
                    }
                
                /* sha1 */
                    
                    String sha1 = "";
                    
                    if (r.getSHA1Urn() != null) {
                        sha1 = r.getSHA1Urn().toString();
                    }

                event = (
                    type
                    + kSep + queryIndex
                    + kSep + hd.getIP()
                    + kSep + hd.getPort()
                    + kSep + ""
                    + kSep + quality
                    + kSep + hd.getSpeed()
                    + kSep + r.getIndex()
                    + kSep + r.getSize()
                    + kSep + r.getFileName()
                    + kSep + sha1
                    + kSep + bitrate
                    + kSep + localIndex
                    + kSep + bh
                    + kSep + artist
                    + kSep + album
                    + kSep + year
                    + kSep + title
                );
                break;
            }
            
        /* Uploads */
        
            case kLWEventAddUpload:
            {
                Uploader u = (Uploader)obj;
                String ua = u.getUserAgent();
                String p = "";
 
                if (u.getFileDesc() != null) {
                    p = u.getFileDesc().getPath();
                }
                
                if (ua == null) ua = "";
                
                event = (
                    type
                    + kSep + u.getHost()
                    + kSep + u.getIndex()
                    + kSep + u.getFileName()
                    + kSep + ua
                    + kSep + u.getState()
                    + kSep + u.getAmountRequested()
                    + kSep + p
                    + kSep + ((u.isBrowseHostEnabled()) ? 1 : 0)
                    + kSep + u.getGnutellaPort()
                );

                break;
            }

            case kLWEventRemoveUpload:
            {
                Uploader u = (Uploader)obj;
                event = (
                    type
                    + kSep + u.getHost()
                    + kSep + u.getIndex()
                    + kSep + u.getFileName()
                    + kSep + u.getState()
                );
                break;
            }

            case kLWEventUpdateUploadStats:
            {
                Uploader u = (Uploader)obj;
                
                float b  = 0;
                float b1 = 0;

                try {
                    b = u.getMeasuredBandwidth() * 1024;
                    b1 = u.getAverageBandwidth() * 1024;
                } catch (Exception e) {
                }
                
                event = (
                    type
                    + kSep + u.getHost()
                    + kSep + u.getIndex()
                    + kSep + u.getFileName()
                    + kSep + u.getState()
                    //+ kSep + u.getAmountRequested()
                    //+ kSep + u.amountUploaded()
                    + kSep + u.getFileSize()
                    + kSep + u.getTotalAmountUploaded()
                    + kSep + b
                    + kSep + b1
                );
                break;
            }
            
            case kLWEventUploadsUpdated:
            {
                event = (
                    type
                    + ""
                );
                break;
            }

        /* Downloads */
        
            case kLWEventAddDownload:
            {
                ManagedDownloader d = (ManagedDownloader)obj;
                int index = AqEventHandler.downloads.indexOf(d);
                event = (
                    type
                    + kSep + index
                    + kSep + d.getFileName()
                    + kSep + d.getState()
                    + kSep + d.getContentLength()
                    + kSep + d.getAmountRead()
                );
                break;
            }
            
            case kLWEventRemoveDownload:
            {
                ManagedDownloader d = (ManagedDownloader)obj;
                int index = AqEventHandler.downloads.indexOf(d);
                event = (
                    type
                    + kSep + index
                );
                break;
            }

            case kLWEventUpdateDownloadStats:
            {
                ManagedDownloader d = (ManagedDownloader)obj;
                int index = AqEventHandler.downloads.indexOf(d);

                String p = "";
                if (d.getDownloadFragment() != null) {
                    p = d.getDownloadFragment().getAbsolutePath();
                }

                float b  = 0;
                float b1 = 0;

                try {
                    b = d.getMeasuredBandwidth() * 1024;
                    b1 = d.getAverageBandwidth() * 1024;
                } catch (Exception e) {
                }
                
                /* queues */
                String q = "0";
                
                if (d.getState() == Downloader.REMOTE_QUEUED) {
                    q = d.getQueuePosition();
                }
                
                int l = d.getContentLength();
                if (l < 0) l = 1;
                
                /* hosts */
                
                String hosts = "";
                Iterator i = d.getHosts();
                while (i.hasNext()) {
                    Endpoint e = (Endpoint)i.next();
                    hosts = hosts + e.getHostname() + ":" + e.getPort() + ",";
                }
                
                event = (
                    type
                    + kSep + index
                    + kSep + d.getState()
                    + kSep + l
                    + kSep + d.getAmountRead()
                    + kSep + b
                    + kSep + b1
                    + kSep + d.numberOfDownloaders()
                    + kSep + d.numberOfThreads()
                    + kSep + d.numberOfBusy()
                    + kSep + d.numberOfFiles()
                    + kSep + d.numberOfQueued()
                    + kSep + p
                    + kSep + q
                    + kSep + hosts
                );
                break;
            }

            case kLWEventDownloadsUpdated:
            {
                event = (
                    type
                    + ""
                );
                break;
            }
            
        /* Sharing */
            
            case kLWEventAddSharedFile:
            {
                FileDesc f = (FileDesc)obj;
                
                event = (
                    type
                    + kSep + f.getSHA1Urn()
                    + kSep + f.getName()
                    + kSep + f.getSize()
                    /*
                    + kSep + f.numberOfAlternateLocations()
                    + kSep + f.getHitCount()
                    + kSep + f.getAttemptedUploads()
                    + kSep + f.getCompletedUploads()
                    */
                );
                break;
            }

            case kLWEventAddSharedDirectory:
            {
                File f = (File)obj;

                event = (
                    type
                    + kSep + f.getAbsolutePath()
                );
                break;
            }
        }
        
        if (event != null) {
            synchronized (System.out) {
                System.out.println(event);
            }
        }
    }
}