package com.limegroup.gnutella.search;

import com.limegroup.gnutella.*;
import com.limegroup.gnutella.messages.*;
import com.limegroup.gnutella.settings.SearchSettings;
import com.limegroup.gnutella.util.*;
import com.limegroup.gnutella.xml.*;

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

/**
 * This class has been modified extensively for Acquisition.
 * David Watanabe
 */

/**
 * Handles incoming search results from the network.  This class parses the 
 * results from <tt>QueryReply</tt> instances and performs the logic 
 * necessary to pass those results up to the UI.
 */
 
public final class SearchResultHandler 
{
    public void start() {
    }

    public void handleQueryReply(QueryReply qr) {
        handleReply(qr);
    }

    /** 
	 * Handles the given query reply. Only one thread may call it at a time.
     *      
	 * @return <tt>true</tt> if the GUI will (probably) display the results,
	 *  otherwise <tt>false</tt> 
     */
    private boolean handleReply(final QueryReply qr) {
		HostData data = new HostData(qr);
        
        // always handle reply to multicast queries.
        if( !data.isReplyToMulticastQuery() ) {
            // note that the minimum search quality will always be greater
            // than -1, so -1 qualities (the impossible case) are never
            // displayed
            /* davew 
            if(data.getQuality() < SearchSettings.MINIMUM_SEARCH_QUALITY.getValue()) {
                return false;
            }
            if(data.getSpeed() < SearchSettings.MINIMUM_SEARCH_SPEED.getValue()) {
                return false;
            }
            */
            // if the other side is firewalled AND
            // we're not on close IPs AND
            // (we are firewalled OR we are a private IP)
            // then drop the reply.
            if(data.isFirewalled() && 
               !NetworkUtils.isVeryCloseIP(qr.getIPBytes()) &&               
               (!RouterService.acceptedIncomingConnection() ||
                NetworkUtils.isPrivateAddress(RouterService.getAddress()))
               )  {
               return false;
            }
        }

        List results = null;
        try {
            results = qr.getResultsAsList();
        } catch (BadPacketException e) {
            return false;
        }
        
        // get xml collection string, then get dis-aggregated docs, then 
        // in loop
        // you can match up metadata to responses
        String xmlCollectionString = "";
        try {
            debug("Trying to do uncompress.....");
            byte[] xmlCompressed = qr.getXMLBytes();
            if (xmlCompressed.length > 1) {
                byte[] xmlUncompressed = LimeXMLUtils.uncompress(xmlCompressed);
                xmlCollectionString = new String(xmlUncompressed);
            }
        }
        catch (Exception e) {
            // so what, i couldn't get xml, no biggie, don't kill everyone for
            // no reason...
            xmlCollectionString = "";
        }
        debug("xmlCollectionString = " + xmlCollectionString);
        List allDocsArray = LimeXMLDocumentHelper.getDocuments(xmlCollectionString, 
															   results.size());
        int z = allDocsArray.size();
        int k = -1;//for counting iterations...initialized to -1

		byte[] replyGUID = data.getMessageGUID();

        Iterator iter = results.iterator();
        while(iter.hasNext()) {
            k++;
            Response response = (Response)iter.next();

            //if (! RouterService.matchesType(replyGUID, response))
            //    continue;
            
            //Throw away results from Mandragore Worm
            if (RouterService.isMandragoreWorm(replyGUID, response))
                continue;
            
            ArrayList docs = null;
            if(xmlCollectionString==null || xmlCollectionString.equals("")){
                //Note:This means no XML in QHD. create docs from between nulls
                LimeXMLDocument doc;//there is only going to be one Document
                try {
                    String xmlStr = response.getMetadata();
                    doc = new LimeXMLDocument(xmlStr);
                }catch(Exception e){//could not create documnet
                    doc = null;
                }
                if(doc==null)
                    docs = null;
                else{
                    docs = new ArrayList();
                    docs.add(doc);
                }
            }
            else{//XML in QHD....make documents from there
                //lets gather the documents
                docs = new ArrayList(z);//size = number of schemas
                LimeXMLDocument[] metaDocs;
                for(int l=0; l<z;l++){//for each schema
                    metaDocs = (LimeXMLDocument[])allDocsArray.get(l);
                    if(metaDocs == null)
                        continue;
                    if(metaDocs[k]!=null)
                        //add doc corresponding to response from outer loop
                        docs.add(metaDocs[k]);
                }    
            }
            
            //Sumeet:TODO1: figure out how the xml is being parsed
            //and choose the xml-document we want - see if we can optimize
            //the above block.
            RemoteFileDesc rfd = null;
            LimeXMLDocument doc = docs==null||docs.size()==0?null
                                                 :(LimeXMLDocument)docs.get(0);
            rfd = new RemoteFileDesc(data.getIP(),
                                     data.getPort(),
                                     response.getIndex(),
                                     response.getName(),
                                     (int)response.getSize(),
                                     data.getClientGUID(),
                                     data.getSpeed(),
                                     data.isChatEnabled(),
                                     data.getQuality(),
                                     data.isBrowseHostEnabled(),
                                     doc,
                                     response.getUrns(),
                                     data.isReplyToMulticastQuery(),
                                     data.isFirewalled(), 
                                     data.getVendorCode(),
                                     System.currentTimeMillis(),
                                     data.getPushProxies()
                                    );
			RouterService.getCallback().handleQueryResult(rfd,data);

        } //end of response loop
        return true;
    }

    private final boolean debugOn = false;
    private void debug(String out) {
        if (debugOn)
            System.err.println(out);
    }
}