//
// BEGIN FLOCK GPL
//
// Copyright Flock Inc. 2005-2008
// http://flock.com
//
// This file may be used under the terms of the
// GNU General Public License Version 2 or later (the "GPL"),
// http://www.gnu.org/licenses/gpl.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// END FLOCK GPL
//

const AMAZON_SEARCH_CID         = Components.ID('{c3cc0113-4df3-4b49-ae86-b9014776dee6}');

const nsISupports                   = Components.interfaces.nsISupports;
const nsIClassInfo                  = Components.interfaces.nsIClassInfo;
const nsIFactory                    = Components.interfaces.nsIFactory;
const nsIProperties                 = Components.interfaces.nsIProperties;
const nsILocalFile                  = Components.interfaces.nsILocalFile;
const nsIFile                       = Components.interfaces.nsIFile;
const nsIIOService                  = Components.interfaces.nsIIOService;
const nsIFileProtocolHandler        = Components.interfaces.nsIFileProtocolHandler;
const nsIRDFRemoteDataSource        = Components.interfaces.nsIRDFRemoteDataSource;
const nsIRDFDataSource              = Components.interfaces.nsIRDFDataSource;
const flockISearchService           = Components.interfaces.flockISearchService;
const nsIXMLHttpRequest             = Components.interfaces.nsIXMLHttpRequest;

const AMAZON_SEARCH_CONTRACTID       = '@flock.com/?flock-search-amazon;1';
const DIRECTORY_SERVICE_CONTRACTID  = '@mozilla.org/file/directory_service;1';
const LOCAL_FILE_CONTRACTID         = '@mozilla.org/file/local;1';
const PREFERENCES_CONTRACTID        = '@mozilla.org/preferences-service;1';
const IO_SERVICE_CONTRACTID         = '@mozilla.org/network/io-service;1';
const XMLHTTPREQUEST_CONTRACTID     = '@mozilla.org/xmlextras/xmlhttprequest;1'

const flockIError = Components.interfaces.flockIError;
const FLOCK_ERROR_CONTRACTID = '@flock.com/error;1'

const AMAZON_SEARCH_API_URL = "http://xml.amazon.com/onca/xml3";
const AMAZON_DEVELOPER_TOKEN = "0XYJJ825QSB9Q7F2XN02";
const AMAZON_ASSOCIATES_ID = "flockcom-20";


function amazonSearchService() {
  var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Components.interfaces.nsIStringBundleService);
  var bundle = sbs.createBundle("chrome://flock/locale/search/search.properties");
  this.serviceName = bundle.GetStringFromName("flock.search.api.amazon");
}

amazonSearchService.prototype.shortName = "amazon";
amazonSearchService.prototype.icon = "chrome://browser/skin/flock/search/amazon.ico";
amazonSearchService.prototype.ref = "urn:flock:search:amazon";
amazonSearchService.prototype.fullResultsUrl = "http://amazon.com/s/ref=nb_ss_gw/102-3108539-8940162?url=search-alias%3Daps&Go.x=0&Go.y=0&Go=Go&field-keywords=";

amazonSearchService.prototype.search = function (aQuery, aNumResults, aListener, aDatasource) {
    var inst = this;
    
    if (!aQuery.length) return;
    // eg. http://xml.amazon.com/onca/xml3?t=[Associates ID goes here]&dev-t=[Developer Token goes here]&KeywordSearch=dogs&mode=books&type=lite&page=1&f=xml
    var escapedQuery = encodeURIComponent(aQuery);
    var url = AMAZON_SEARCH_API_URL + "?" 
       + "t=" + AMAZON_ASSOCIATES_ID
       + "&dev-t=" + AMAZON_DEVELOPER_TOKEN
       + "&BlendedSearch=" + escapedQuery
       + "&Keywords=" + escapedQuery
       + "&type=lite"
       + "&f=xml"
       + "&page=1";

    debug(url + " < call\n");
    this.req = Components.classes[XMLHTTPREQUEST_CONTRACTID].createInstance(nsIXMLHttpRequest);
    this.req instanceof Components.interfaces.nsIJSXMLHttpRequest;
    this.req.open('GET', url, true);
    var req = this.req;    
    //debug('request is ' + req + '\n');
    this.req.onreadystatechange = function (aEvt) {
      if(inst.req.readyState == 4) {
          // debug("\nRESPONSE\n" + inst.xmlhttp.responseText);
          try {
              if(req.status == 200 || req.status == 201) {
                 try {
                     //processor(listener, inst);
                    debug(req.responseText);
                     var rdf = inst.readXML(req.responseXML, aNumResults, aDatasource);
                     var numResults = inst.getNumResults(req.responseXML);
                     aListener.foundResults(numResults, rdf, inst.shortName, aQuery);
                 } catch(e) {
                     debug(e + " " + e.lineNumber+"\n");
                 }
              }
              else {
                  var faultString = req.responseText;
                  // listener.onFault(faultString);
              }
          } catch(e) {
              debug(e + " " + e.fileName + " " + e.lineNumber + "\n");
              //listener.onError(inst.ERROR_PARSER);
          }
      }
    }
    
    this.req.send(null);  
}

amazonSearchService.prototype.getNumResults = function (xmlDoc) {
	return 10;
	try {
		var results = xmlDoc.getElementsByTagName("item"); 
		return results.length;
	} catch (ex) {
	
	}
}

amazonSearchService.prototype.readXML = function (xmlDoc, aNumResults, aDatasource) {
  try {
    var resultSet = xmlDoc.getElementsByTagName("ProductInfo")[0];                                                              
    //var totalResultsAvailable = parseInt(xmlDoc.getElementsByTagName("querycount")[0].firstChild.nodeValue);
    //var totalResultsReturned = parseInt(xmlDoc.getElementsByTagName("item").length);                                      
    //var firstResultPosition = parseInt(resultSet.getAttribute("firstResultPosition"));                                        
    //var start = firstResultPosition;                                                                                          
    //var end = firstResultPosition + totalResultsReturned - 1;                                                                 
    var results = xmlDoc.getElementsByTagName("Details"); 

    // Create an in-memory datasource
    var rdfService = Components.classes["@mozilla.org/rdf/rdf-service;1"]
        .getService(Components.interfaces.nsIRDFService);
    var rdfContainerUtils = Components.classes["@mozilla.org/rdf/container-utils;1"]
        .getService(Components.interfaces.nsIRDFContainerUtils);
    // Fill it with the results
    var rootContainer = rdfContainerUtils.MakeSeq(aDatasource, rdfService.GetResource("urn:flock:search:amazon"));

	var categories = xmlDoc.getElementsByTagName('ProductLine');
	for (var i=0; i < categories.length; i++) {
		// let's create the type container
		var type = categories[i].getElementsByTagName('Mode')[0].firstChild.nodeValue;
		//debug(' >>> amazon type is ' + type + '\n');
		var typeNode = rdfService.GetResource("http://flock.com/rdf#type-" + type);
		var typeContainer = rdfContainerUtils.MakeSeq(aDatasource, typeNode);
		
        // .. and give this category a name
        aDatasource.Assert(typeNode, rdfService.GetResource("http://home.netscape.com/NC-rdf#Name"), rdfService.GetLiteral(type), true);
		// make this of type "category
        aDatasource.Assert(typeNode, rdfService.GetResource("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), rdfService.GetResource("http://flock.com/rdf#category"), true);
        
        
        var relevanceRank = parseInt(categories[i].getElementsByTagName('RelevanceRank')[0].firstChild.nodeValue);        
        if (relevanceRank > 2) continue;
        debug('the relevance rank is ' + relevanceRank + '\n\n\n');
        
        
		var results = categories[i].getElementsByTagName('Details');
		
		// append the items to the category
		for (var j=0; j < results.length; j++) {
			var result = results[j];                                                                                                
			var title = result.getElementsByTagName('ProductName')[0].firstChild.nodeValue;
			var clickUrl = result.getAttribute('url');
			var url = clickUrl;
			var thumbnailUrl = result.getElementsByTagName('ImageUrlSmall')[0].firstChild.nodeValue;
			
			var listPrice = result.getElementsByTagName('ListPrice');
			if (listPrice.length) listPrice = listPrice[0].firstChild.nodeValue;
			
			var amazonPrice = result.getElementsByTagName('OurPrice');
			if (amazonPrice.length) amazonPrice = amazonPrice[0].firstChild.nodeValue;
			
			var usedPrice = result.getElementsByTagName('UsedPrice');
			if (usedPrice.length) usedPrice = usedPrice[0].firstChild.nodeValue;
			
			var subject = rdfService.GetResource(url);
			
			var predicate = rdfService.GetResource("http://home.netscape.com/NC-rdf#Name");
			var name = rdfService.GetLiteral(title);                
			aDatasource.Assert(subject, predicate, name, true);
	
			var predicate = rdfService.GetResource("http://home.netscape.com/NC-rdf#URL");
			var name = rdfService.GetLiteral(url);
			aDatasource.Assert(subject, predicate, name, true);
			
            if (thumbnailUrl && thumbnailUrl.length) {
			  var predicate = rdfService.GetResource("http://home.netscape.com/NC-rdf#favicon");
			  var name= rdfService.GetLiteral(thumbnailUrl);
			  aDatasource.Assert(subject, predicate, name, true);
			}
            
			if (listPrice) {
			    var predicate = rdfService.GetResource("http://home.netscape.com/NC-rdf#Price");
    			var name= rdfService.GetLiteral(listPrice);
    			aDatasource.Assert(subject, predicate, name, true);
			}
			
			typeContainer.AppendElement(subject);

		}
		
		rootContainer.AppendElement(typeNode);
	}
        
	  } catch(ex) {
		//debug('amazon Exception occurred while reading XML (i=' + i + '; start=' + start + ';end=' + end + '): ' + exception);
		debug('>>>> amazon error ' + ex + '\n');
	  }
	  
	  return aDatasource;
	}


amazonSearchService.prototype.flags = nsIClassInfo.SINGLETON;
amazonSearchService.prototype.classDescription = "Amazon Search Service";
amazonSearchService.prototype.getInterfaces = function (count) {
    var interfaceList = [flockISearchService, nsIClassInfo];
    count.value = interfaceList.length;
    return interfaceList;
}
amazonSearchService.prototype.getHelperForLanguage = function (count) {return null;}

// the nsISupports implementation
amazonSearchService.prototype.QueryInterface =
function (iid) {
    if (!iid.equals(flockISearchService) && 
        !iid.equals(nsIClassInfo) &&
        !iid.equals(nsISupports))
        throw Components.results.NS_ERROR_NO_INTERFACE;
    if (iid.equals(nsIRDFDataSource) && !this.dataSourceSetup) {
    }
    return this;
}

// Module implementation
var FlockSearchModule = new Object();

FlockSearchModule.registerSelf =
function (compMgr, fileSpec, location, type)
{
    compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);

    compMgr.registerFactoryLocation(AMAZON_SEARCH_CID, 
                                    "Amazon Search JS Component",
                                    AMAZON_SEARCH_CONTRACTID, 
                                    fileSpec, 
                                    location,
                                    type);
    //necessary category registration
    var catmgr = Components.classes["@mozilla.org/categorymanager;1"]
        .getService (Components.interfaces.nsICategoryManager);
    catmgr.addCategoryEntry('flockISearchService', 'amazon', AMAZON_SEARCH_CONTRACTID, true, true);
}

FlockSearchModule.getClassObject =
function (compMgr, cid, iid) {
    if (!cid.equals(AMAZON_SEARCH_CID))
        throw Components.results.NS_ERROR_NO_INTERFACE;
    
    if (!iid.equals(Components.interfaces.nsIFactory))
        throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
    
    return SeachServiceFactory;
}

FlockSearchModule.canUnload =
function(compMgr)
{
    return true;
}
    
/* factory object */
var SeachServiceFactory = new Object();

SeachServiceFactory.createInstance =
function (outer, iid) {
    if (outer != null)
        throw Components.results.NS_ERROR_NO_AGGREGATION;
    return (new amazonSearchService()).QueryInterface(iid);
}

/* entrypoint */
function NSGetModule(compMgr, fileSpec) {
    return FlockSearchModule;
}
