content: /*
   * Copyright (c) 2009 Andrejs Jermakovics.
   * 
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * which accompanies this distribution, and is available at
   * http://www.eclipse.org/legal/epl-v10.html
   *
   * Contributors:
   *     Andrejs Jermakovics - initial implementation
   */
  package it.unibz.instasearch.ui;
  
  import it.unibz.instasearch.InstaSearchPlugin;
  import it.unibz.instasearch.indexing.SearchQuery;
  import it.unibz.instasearch.indexing.SearchResultDoc;
  import it.unibz.instasearch.prefs.PreferenceConstants;
  import it.unibz.instasearch.ui.ResultContentProvider.MatchLine;
  
  import java.util.Collection;
  import java.util.Locale;
  
  import org.eclipse.jface.resource.ImageDescriptor;
  import org.eclipse.jface.resource.ImageRegistry;
  import org.eclipse.jface.resource.JFaceResources;
  import org.eclipse.jface.util.IPropertyChangeListener;
  import org.eclipse.jface.util.PropertyChangeEvent;
  import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider;
  import org.eclipse.jface.viewers.LabelProvider;
  import org.eclipse.jface.viewers.StyledString;
  import org.eclipse.jface.viewers.StyledString.Styler;
  import org.eclipse.search.ui.text.Match;
  import org.eclipse.swt.graphics.Color;
  import org.eclipse.swt.graphics.Image;
  import org.eclipse.swt.graphics.RGB;
  import org.eclipse.ui.ISharedImages;
  import org.eclipse.ui.PlatformUI;
  import org.eclipse.ui.model.WorkbenchLabelProvider;
  
  class ResultLabelProvider extends LabelProvider implements IStyledLabelProvider, IPropertyChangeListener {
  	
      private static final String ECLIPSE_SEARCH_UI_MATCH_HIGHLIGHT = "org.eclipse.search.ui.match.highlight";
  	private static final String HIGHLIGHT_COLOR_NAME = "it.unibz.instasearch.ui.HighlightColor";
  	private static final String IMG_OBJ_TEXT_SEARCH_LINE = "org.eclipse.search.ui.line_match";
  	private static final String MORE_RESULTS_LABEL = "More...";
  	private static final String FIND_SIMILAR_LABEL = "Find similar...";
  	private static final String DOWN_ARROW_IMG_KEY = "down_arrow";
  	
  	private ImageRegistry imageRegistry = new ImageRegistry();
  	private Styler highlightStyle;
  	
  	private WorkbenchLabelProvider labelProvider;
  	private ResultContentProvider contentProvider;
  	
  	private Image matchImage;
  	private boolean showMatchCount;
  	private boolean showFullPath;
  	
  	public ResultLabelProvider(ResultContentProvider contentProvider) {
  	    Color searchColor = JFaceResources.getColorRegistry().get(ECLIPSE_SEARCH_UI_MATCH_HIGHLIGHT);
  	    
  		JFaceResources.getColorRegistry().put(HIGHLIGHT_COLOR_NAME, (searchColor!=null?searchColor.getRGB():new RGB(206, 204, 247)));
  		
  		this.labelProvider = new WorkbenchLabelProvider();
  		this.highlightStyle = StyledString.createColorRegistryStyler(null, HIGHLIGHT_COLOR_NAME);
  		this.contentProvider = contentProvider;
  		this.matchImage = InstaSearchUI.getSharedImage(IMG_OBJ_TEXT_SEARCH_LINE);
  		
  		imageRegistry.put(DOWN_ARROW_IMG_KEY, InstaSearchPlugin.getImageDescriptor(DOWN_ARROW_IMG_KEY));
  		
  		this.showMatchCount = InstaSearchPlugin.getBoolPref(PreferenceConstants.P_SHOW_MATCH_COUNT);
  		this.showFullPath = InstaSearchPlugin.getBoolPref(PreferenceConstants.P_SHOW_FULL_PATH);
  		
  		InstaSearchPlugin.addPreferenceChangeListener(this);
  	}
  	
  	public StyledString getStyledText(Object element) {
  				
  		if(element instanceof SearchResultDoc) {
  			SearchResultDoc doc = (SearchResultDoc) element;
  			
  			return decorateFile(doc);
  			
  		} else if(element instanceof MatchLine) {
  			MatchLine lineMatches = (MatchLine) element;
  			return decorateLineMatches(lineMatches);
  			
  		} else if( element instanceof SearchQuery ) {
  			// we have search query in 2 cases:
  			SearchQuery query = (SearchQuery) element;
  			
  			if( !query.isLimited() )
  				return new StyledString(MORE_RESULTS_LABEL);
  			else
  				return new StyledString(FIND_SIMILAR_LABEL);	
  		}
  		
  		return new StyledString(element.toString());
  	}
  	
  	private StyledString decorateFile(SearchResultDoc doc) {
  		
  		String fileName = doc.getFileName();
  		StyledString str = new StyledString(fileName);
  		
  		Collection<String> searchTerms = contentProvider.getSearchTerms();
  		
  		for(String searchTerm: searchTerms) // highlight matches 
  		{
  			int termPos = fileName.toLowerCase(Locale.ENGLISH).indexOf(searchTerm);
  			
  			if( termPos != -1 )
  				str.setStyle(termPos, searchTerm.length(), highlightStyle);
  		}
  		
  		int matchCount = doc.getMatchCount();
  		
  		if( matchCount > 1 && showMatchCount ) 
  		{
  			str.append(" (", StyledString.COUNTER_STYLER);
  			str.append(Integer.toString(matchCount), StyledString.COUNTER_STYLER);
  			str.append(" matches)", StyledString.COUNTER_STYLER);
  		}
  		
  		str.append(" - ", StyledString.QUALIFIER_STYLER);
  		str.append(doc.getProjectName(), StyledString.QUALIFIER_STYLER);
  		
  		if( showFullPath ) 
  		{
  			String filePath = getCompactFilePath(doc, fileName);
  			
  			if( !"".equals(filePath) ) 
  			{
  				str.append(" - ", StyledString.QUALIFIER_STYLER);
  				str.append(filePath, StyledString.QUALIFIER_STYLER);
  			}
  		}
  		
  		if( InstaSearchPlugin.isDebug() )
  		{
  			str.append(" - [", StyledString.DECORATIONS_STYLER);
  			str.append(String.format("%.03f", doc.getScore()), StyledString.DECORATIONS_STYLER);
  			str.append("]", StyledString.DECORATIONS_STYLER);
  		}
  		
  		return str;
  	}
  
  	/**
  	 * File path without the project name and without the filename
  	 * 
  	 * @param doc
  	 * @param fileName
  	 * @return
  	 */
  	private String getCompactFilePath(SearchResultDoc doc, String fileName) {
  		
  		String projectName = doc.getProjectName();
  		String filePath = doc.getFilePath();
  		
  		int end = filePath.length()-1, start = filePath.indexOf(projectName);
  		if( start == -1 ) 
  			start = 0;
  		else 
  			start = start + projectName.length() + 1;
  		
  		if( filePath.endsWith(fileName) )
  			end = filePath.length() - fileName.length() - 1;
  		
  		if( start > end )
  			return "";
  			
  		filePath = filePath.substring(start, end);
  		
  		return filePath;
  	}
  	
  	private StyledString decorateLineMatches(MatchLine lineMatches) {
  		
  		String line = lineMatches.getLine();
  		StyledString str = new StyledString(line);
  		
  		for(Match m: lineMatches.getMatches()) 
  		{
  			str.setStyle(m.getOffset(), m.getLength(), highlightStyle);
  		}
  		
  		StyledString ret = new StyledString();
  		ret.append(lineMatches.getLineNumber() + ": ", StyledString.QUALIFIER_STYLER);
  		ret.append(str);
  		
  		return ret;
  	}
  	
  	public Image getImage(Object element) {
  		try {
  			if(element instanceof SearchResultDoc) {
  				SearchResultDoc doc = (SearchResultDoc) element;
  				
  				Image image = null;
  				
  				if( !doc.isInJar() )
  					image = labelProvider.getImage(doc.getFile());
  				
  				if( image == null )
  					image = getFileImage(doc);
  				
  				if( image == null )
  					image = InstaSearchUI.getSharedImage(ISharedImages.IMG_OBJ_FILE);
  				
  				return image;
  				
  			} else if( element instanceof MatchLine )
  				return matchImage ;
  			else if( element instanceof Exception )
  				return InstaSearchUI.getSharedImage(ISharedImages.IMG_OBJS_WARN_TSK);
  			else if( element instanceof SearchQuery )
  				return imageRegistry.get(DOWN_ARROW_IMG_KEY);
  			
  		} catch(Exception e) {
  			InstaSearchPlugin.log(e);
  			return InstaSearchUI.getSharedImage(ISharedImages.IMG_OBJS_WARN_TSK);
  		}
  		
  		return InstaSearchUI.getSharedImage(ISharedImages.IMG_OBJS_INFO_TSK); // no results
  	}
  
  	private Image getFileImage(SearchResultDoc doc) 
  	{
  		String ext = doc.getFileExtension();
  		Image fileImage = imageRegistry.get(ext);
  		
  		if( fileImage == null ) {
  			ImageDescriptor imageDescriptor = PlatformUI.getWorkbench().getEditorRegistry().getImageDescriptor(doc.getFileName());
  			fileImage = imageDescriptor.createImage(true); 
  			imageRegistry.put(ext, fileImage); // cache created images for extensions
  		}
  		
  		return fileImage;
  	}
  	
  	public void propertyChange(PropertyChangeEvent event) {
  		// update preferences
  		if( PreferenceConstants.P_SHOW_MATCH_COUNT.equals(event.getProperty()))
  			showMatchCount = InstaSearchPlugin.getBoolPref(PreferenceConstants.P_SHOW_MATCH_COUNT);
  		else if( PreferenceConstants.P_SHOW_FULL_PATH.equals(event.getProperty()))
  			showFullPath = InstaSearchPlugin.getBoolPref(PreferenceConstants.P_SHOW_FULL_PATH);
  	}
  	
  	@Override
  	public void dispose()
  	{
  		super.dispose();
  		imageRegistry.dispose();
  		InstaSearchPlugin.removePreferenceChangeListener(this);
  	}
  }