/**
 * Created on Jul 16, 2005
 * $id:  $
 */
package org.jvnet.lookout.google.desktop.adapter;

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

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.jvnet.lookout.core.util.Utilities;
import org.jvnet.lookout.google.desktop.Plugin;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class SearchResultHandler extends DefaultHandler {
    
    //XML tags
    protected static final String RESULTS_TAG = "results"; 
    protected static final String RESULT_TAG = "result"; 
    protected static final String CATEGORY_TAG = "category"; 
    protected static final String TITLE_TAG = "title"; 
    protected static final String URL_TAG = "url"; 
    protected static final String SNIPPET_TAG = "snippet"; 
    protected static final String CACHE_URL_TAG = "cache_url"; 
    protected static final String COUNT_TAG = "count"; 
    
    protected enum ElementType {
        
        //Used for when we do not want to process an element
        NOT_PROCESSED,
        
        //Used
        RESULTS, RESULT, CATEGORY, TITLE, URL, SNIPPET, CACHE_URL,
        
        //Not used
        THUMBNAIL, TIME, ID, ICON, FROM } 
    
    protected List searchResults;
    protected int totalNumberOfSearchResults;
    
    protected DesktopSearchResultBean currentResult;
    protected ElementType currentElementType;
    
    /**
     * The flag that denotes if successful processing took place
     */
    private boolean successfullyProcessed;
    
    public SearchResultHandler() {
        super();
    }
    
    public List getSearchResults() {
    	return this.searchResults;    	
    }
    
    public void setSearchResults(List searchResults) {
        this.searchResults = searchResults;
    }
    
    public int getTotalNumberOfSearchResults() {
        return this.totalNumberOfSearchResults;
    }
    
    protected void setTotalNumberOfSearchResults(int totalNumberOfSearchResults) {
        this.totalNumberOfSearchResults = totalNumberOfSearchResults;
    }
    
    /**
     * Should be called after a parsing is done to cleanup the internal structures. 
     */
    public void cleanup() {
        searchResults = null;
    }
    
    /**
     * Should be called before parsing is done to setup the internal structures.
     */
    public void setup() {
        searchResults = new ArrayList(0);     
        successfullyProcessed = true;
    }
    
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        
        if(RESULT_TAG.equals(qName)) {
            currentResult = new DesktopSearchResultBean();
            currentElementType = ElementType.RESULT;
        } else if(CATEGORY_TAG.equals(qName)) {
            currentElementType = ElementType.CATEGORY;            
        }  else if(CACHE_URL_TAG.equals(qName)) {
            currentElementType = ElementType.CACHE_URL;            
        }  else if(URL_TAG.equals(qName)) {
            currentElementType = ElementType.URL;            
        }  else if(SNIPPET_TAG.equals(qName)) {
            currentElementType = ElementType.SNIPPET;            
        }  else if(TITLE_TAG.equals(qName)) {
            currentElementType = ElementType.TITLE;            
        } else if(RESULTS_TAG.equals(qName)) {
            String count = attributes.getValue(COUNT_TAG);
            
            if(null != count) {
                totalNumberOfSearchResults = Integer.parseInt(count);
            } else {
                MultiStatus status = Utilities.createPluginStatus(
                		Plugin.getDefault(),
                		//CXB_EXTERNALIZE
                		"Cannot process results from Google Desktop Search",
                		IStatus.ERROR,
                		new IllegalArgumentException
                		//CXB_EXTERNALIZE
                		("Total number of results was not specified in the Google Desktop Search response.")
                );                	
                Plugin.getDefault().getLog().log(status);
                
                //This is a problem... 
        		successfullyProcessed = false;           		
            }
            
            currentElementType = ElementType.RESULTS;
        } else {
            currentElementType = ElementType.NOT_PROCESSED;
        }        
    }
    
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if(RESULT_TAG.equals(qName)) {
            
            searchResults.add(currentResult);
            
            //Reset these iteration memebers...
            currentResult = null;
            currentElementType = ElementType.NOT_PROCESSED;
        } 
    }
    
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        
        String value = new String(ch, start, length);
        switch (currentElementType) {
    
        //The merging done below is needed because special chars like & are read
        //seprately (in a different call to characters) so there are times 
        //when multiple calls to characters is made in order to process the contents
        //of 1 element. So we need to merge them.
        //the merge also takes cares of removing any new lines or trailing spaces that
        //may be left in the content of the element due to formatting.
        
        case CATEGORY:
            value = mergeValue(currentResult.getCategory(), value);
            currentResult.setCategory(value);
            break;
            
        case SNIPPET:
            value = mergeValue(currentResult.getSnippet(), value);
            currentResult.setSnippet(value);
            break;
            
        case TITLE:
            value = mergeValue(currentResult.getTitle(), value);
            currentResult.setTitle(value);
            break;
            
        case URL:
            value = mergeValue(currentResult.getUrl(), value);
            currentResult.setUrl(value);    
            break;
            
        case CACHE_URL:            
            value = mergeValue(currentResult.getCachedUrl(), value);
            currentResult.setCachedUrl(value);                
            break;
            
        case FROM:
            //no op
            break;
            
        case ICON:
            //no op
            break;
            
        case ID:
            //no op
            break;
            
        case RESULT:
            //no op
            break;
            
        case RESULTS:
            //no op
            break;
            
        case THUMBNAIL:
            //no op
            break;
            
        case TIME:
            //no op
            break;
            
        case NOT_PROCESSED:
            //no op
            break;
            
        default: {
            MultiStatus status = Utilities.createPluginStatus(
            		Plugin.getDefault(),
            		//CXB_EXTERNALIZE
            		"Could not handle content when processing XML response from Google Desktop Search",
            		IStatus.WARNING,
            		new IllegalArgumentException
            		//CXB_EXTERNALIZE
            		("Content of type: '" + currentElementType + "' is not recognized")
            );                	
            Plugin.getDefault().getLog().log(status);   
        	break;
        }
        }            
    }
    
    protected String mergeValue(String curValue, String newValue) {
        return (((null == curValue) ? "" : curValue) + newValue).trim();
    }

	public boolean getSuccessfullyProcessed() {
		return successfullyProcessed;
	}
    
}
