/**
 * Created on Jul 16, 2005
 * $id:  $
 */

package org.jvnet.lookout.google.desktop.adapter;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.jvnet.lookout.core.adapter.SearchQueryConverter;
import org.jvnet.lookout.core.model.SearchQuery;
import org.jvnet.lookout.core.model.SearchQuery.Parameter;
import org.jvnet.lookout.google.desktop.Plugin;
import org.jvnet.lookout.google.desktop.preference.Preferences;

public class DesktopQueryConverter implements SearchQueryConverter {
    
	//Some links:
	//http://desktop.google.com/features.html#results
	//
    private static String clientServerUrl = null;
    private static String clientSecurityTokenValue = null;
    
    //Parameters and operators
    private static final String searchParameterName = "s";
    private static final String formatParameterName = "format";
    private static final String numberOfResultsParameterName = "num";
    private static final String startIndexParameterName = "start";
    
    //filetype: => filetype%3A
    private static final String fileTypeParameterName = "filetype%3A";
    private static final String emailFileTypeParameterPart = "email";
    private static final String chatFileTypeParameterPart = "chat";
    private static final String webFileTypeParameterPart = "web";
    
    private static final String queryTokenKey = "q";
    
    //Syntax elements
    private static final String intraParameterSeparator = "&";
    private static final String interParameterSeparator = "?";
    private static final String tokenAssignmentOperator = "=";
    private static final String googleOperation = "search";
    
    //Default values
    private static final String formatParameterValue = "xml";
    
    //Query string processing
    private static final String doubleQuoteValueToReplace = "\"";
    private static final String doubleQuoteSubstitute = "%22";
    
    private static final String spaceValueToReplace = " ";
    private static final String spaceValueSubstitute = "+";
    
    //private static final String ANDValueToReplace = " AND ";
    //private static final String ANDSubstitute = " ";
    
    private static org.eclipse.core.runtime.Preferences searchCorePreferences;
    private static org.eclipse.core.runtime.Preferences searchDesktopPreferences;
	
    private static String baseUrl;
    private static String numberOfResultsParameterValue = "10";
    
    public DesktopQueryConverter() {
    	searchCorePreferences = org.jvnet.lookout.core.Plugin.getDefault().getPluginPreferences();
        searchDesktopPreferences = Plugin.getDefault().getPluginPreferences();
    	
    	//Read the the client specifc details    	
    	clientSecurityTokenValue = searchDesktopPreferences.getString(Preferences.ClientSecurityToken);
    	
    	clientServerUrl = searchDesktopPreferences.getString(Preferences.ServerUrl);
    }    

    /**
     * @see org.google.search.adapter.SearchQueryConverter#convert(java.util.Map)
     */
    public String convert(SearchQuery query) {

        Map<Parameter, String> parameters = query.getParameters();
        
        //Get the base URL...
        StringBuffer queryBuffer = new StringBuffer(getBaseUrl());
        
        //Replace characters to comply with Google desktop search syntax
        String processedQueryString = processQueryString(parameters.get(Parameter.KEYWORDS));
        
        queryBuffer.append(processedQueryString);
        
        //Resource File types
        queryBuffer.append(getFileTypeParameterAndValue());
        
        //Check preferences and add any of the needed additional search flags...
        numberOfResultsParameterValue 
        = searchCorePreferences.getString(org.jvnet.lookout.core.preference.Preferences.NumberOfResults);
        
        //Find the batch number...
        int batchNumber = Integer.parseInt(parameters.get(Parameter.BATCH));	
		
        //Process additional parameters
        int numberOfAdditionalTokens = 3;
        
        ////////////////////////////////////////
        //PARAMETERS
        ////////////////////////////////////////
        List<String> additionalTokenKeys = new ArrayList<String>(numberOfAdditionalTokens);
        
        //Format
        additionalTokenKeys.add(formatParameterName);
        
        //Number of results
        additionalTokenKeys.add(numberOfResultsParameterName);
        
        //Number of results
        additionalTokenKeys.add(startIndexParameterName);

        ////////////////////////////////////////
        //VALUES
        ////////////////////////////////////////
        List<String> additionalTokenValues = new ArrayList<String>(numberOfAdditionalTokens);
        //Format
        additionalTokenValues.add(formatParameterValue);
        
        //Number of results
        additionalTokenValues.add(numberOfResultsParameterValue);

        int numberOfResults = (Integer.parseInt(numberOfResultsParameterValue));
        
        //Start index 
        additionalTokenValues.add((numberOfResults * (batchNumber-1)) + "");

        queryBuffer.append(buildStringForTokens(additionalTokenKeys, additionalTokenValues, intraParameterSeparator, true, false));
        
        return queryBuffer.toString();
    }
    
    private String getFileTypeParameterAndValue() {
    	
    	String result = "";
    	
    	if(!searchDesktopPreferences.isDefault(Preferences.ResourceTypeToSearch)) {
    		
    		String resourceToSearch = searchDesktopPreferences.getString(Preferences.ResourceTypeToSearch);
    		StringBuffer resultBuffer = new StringBuffer(spaceValueSubstitute);
    		resultBuffer.append(fileTypeParameterName);
    		
    		if(Preferences.SearchChats.equals(resourceToSearch)) {
    			resultBuffer.append(chatFileTypeParameterPart);        			
    		} else if(Preferences.SearchWebHistory.equals(resourceToSearch)) {
    			resultBuffer.append(webFileTypeParameterPart);        			
    		} else if(Preferences.SearchEmails.equals(resourceToSearch)) {
    			resultBuffer.append(emailFileTypeParameterPart);        			
    		} else if(Preferences.SearchFiles.equals(resourceToSearch)) {
    			String fileTypeToSearch = searchDesktopPreferences.getString(Preferences.FileTypeToSearch);        			
    			resultBuffer.append(fileTypeToSearch);        			
    		} else {
    			//CXB Should log something saying that we did 
    			//not handle this case, so we ignore it
    			return result;
    		}
    		
    		result = resultBuffer.toString();
    	}
    	return result;
    }
    /**
     * Rules:
     * <ul>
     * <li>Replace all spaces with a +</li>
     * <li>Replace all " with %22</li>
     * <li>Remove:
     * <ul>
     * <li>AND</li>
     * <li>and</li>
     * </ul>
     * </li>
     * </ul>
     * 
     * @param rawQueryString
     * @return
     */
    protected String processQueryString(String rawQueryString) {
        
        String processedQueryString = null;
        
        //Define what to replace...
        int numberOfReplacements = 3;
        
        List<String> valuesToReplace = new ArrayList<String>(numberOfReplacements);
        
        //valuesToReplace.add(ANDValueToReplace);
        //valuesToReplace.add(ANDValueToReplace.toLowerCase());
        valuesToReplace.add(spaceValueToReplace);
        valuesToReplace.add(doubleQuoteValueToReplace);
        
        List<String> valuesSubstitutes = new ArrayList<String>(numberOfReplacements);
        //valuesSubstitutes.add(ANDSubstitute);
        //valuesSubstitutes.add(ANDSubstitute);
        valuesSubstitutes.add(spaceValueSubstitute);
        valuesSubstitutes.add(doubleQuoteSubstitute);
        
        //replace the values...
        processedQueryString = replaceValues(rawQueryString, valuesToReplace, valuesSubstitutes);
        
        return processedQueryString;
    }
    
    protected String replaceValues(String string, List<String> valuesToReplace, List<String> valuesSubstitutes) {
        
        for (int i = 0; i < valuesToReplace.size(); i++) {
            String valueToReplace = valuesToReplace.get(i);
            String valueSubstitute = valuesSubstitutes.get(i);        
            string = string.replaceAll(valueToReplace, valueSubstitute);    
        }
        
        return string;
    }
    
    protected String getBaseUrl() {
        
        if(baseUrl == null) {
            
            //Need to build somthing like this...
            //http://127.0.0.1:4664/search&s=1l1ZSRYUCZnNBEmauLuZar3O2Ko?q=
            
            int numberOfTokens = 2;
            
            List<String> tokenKeys = new ArrayList<String>(numberOfTokens);
            tokenKeys.add(searchParameterName);
            tokenKeys.add(queryTokenKey);
            
            List<String> tokenValues = new ArrayList<String>(numberOfTokens);
            tokenValues.add(clientSecurityTokenValue);
            //Will be filled later...
            tokenValues.add("");
            
            baseUrl = 
                clientServerUrl + 
                googleOperation + 
                intraParameterSeparator +
                buildStringForTokens(tokenKeys, tokenValues, interParameterSeparator, false, false);
        }
        
        return baseUrl;
    }
    
    
    protected String buildStringForTokens(
            List<String> tokenKeys, 
            List<String> tokenValues, 
            String separator, 
            boolean prependTokenSeparator, 
            boolean appendTokenSeparator) {
        
        StringBuffer tokenStringBuffer = new StringBuffer();
        
        if(prependTokenSeparator) {
            tokenStringBuffer.append(separator);
        }
        
        for (int i = 0; i < tokenKeys.size(); i++) {
            tokenStringBuffer.append(tokenKeys.get(i));
            tokenStringBuffer.append(tokenAssignmentOperator);
            tokenStringBuffer.append(tokenValues.get(i));
            
            //Do not append to last item. Unless of course it has been requested
            if((appendTokenSeparator) || (i != tokenKeys.size() -1)) {
                tokenStringBuffer.append(separator);
            }
        }
        
        return tokenStringBuffer.toString();
    }
}
