package com.aptana.ide.editor.html;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IProgressMonitor;
import com.aptana.ide.core.builder.BuildContext;
import com.aptana.ide.core.builder.BuildParticipant;
import com.aptana.ide.editor.css.CSSColors;
import com.aptana.ide.editor.css.IIndexConstants;
import com.aptana.ide.editor.css.lexing.CSSTokenTypes;
import com.aptana.ide.editor.css.parsing.CSSMimeType;
import com.aptana.ide.editor.css.parsing.nodes.CSSSimpleSelectorNode;
import com.aptana.ide.editor.css.parsing.nodes.CSSTermNode;
import com.aptana.ide.editor.html.parsing.nodes.HTMLElementNode;
import com.aptana.ide.index.core.Index;
import com.aptana.ide.index.core.IndexManager;
import com.aptana.ide.lexer.Lexeme;
import com.aptana.ide.lexer.LexemeList;
import com.aptana.ide.parsing.nodes.IParseNode;
public class CSSClassesAndIdsIndexer extends BuildParticipant
{
private Index fIndex;
private Set<Index> indices;
public CSSClassesAndIdsIndexer()
{
indices = new HashSet<Index>();
}
@Override
public void buildStarting(List<BuildContext> contexts, boolean isBatch, IProgressMonitor monitor)
{
indices.clear();
}
@Override
public void build(BuildContext context, IProgressMonitor monitor)
{
String extension = context.getFile().getFileExtension();
if (extension != null && extension.equalsIgnoreCase("css"))
{
indexCSS(context);
}
else if (extension != null
&& (extension.equalsIgnoreCase("html") || extension.equalsIgnoreCase("htm")
|| extension.equalsIgnoreCase("shtml") || extension.equalsIgnoreCase("xhtml")))
{
indexHTML(context);
}
}
@Override
public void buildFinishing(IProgressMonitor monitor)
{
// Save the indexes now (so it gets saved to disk!)
saveModifiedIndices();
indices.clear();
}
private void saveModifiedIndices()
{
for (Index index : indices)
{
try
{
if (index != null)
index.save();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private void indexHTML(BuildContext context)
{
walkNode(context.getRootNode(), context);
}
private void walkNode(IParseNode parent, BuildContext context)
{
if (parent == null)
return;
if (parent instanceof HTMLElementNode)
{
String cssClass = ((HTMLElementNode) parent).getCSSClass();
if (cssClass != null && cssClass.trim().length() > 0)
{
StringTokenizer tokenizer = new StringTokenizer(cssClass);
while (tokenizer.hasMoreTokens())
addIndex(context, IIndexConstants.CSS_CLASS, tokenizer.nextToken());
}
String id = ((HTMLElementNode) parent).getID();
if (id != null && id.trim().length() > 0)
{
addIndex(context, IIndexConstants.CSS_IDENTIFIER, id);
}
}
else
{
if (parent instanceof CSSSimpleSelectorNode)
{
CSSSimpleSelectorNode node = (CSSSimpleSelectorNode) parent;
IParseNode[] children = node.getChildren();
if (children != null && children.length >= 1)
{
IParseNode listNode = children[0];
children = listNode.getChildren();
for (IParseNode textChild : children)
{
String text = textChild.getText();
if (text != null && text.startsWith("."))
{
addIndex(context, IIndexConstants.CSS_CLASS, text.substring(1));
}
else if (text != null && text.startsWith("#"))
{
addIndex(context, IIndexConstants.CSS_IDENTIFIER, text.substring(1));
}
}
}
}
if (parent instanceof CSSTermNode)
{
CSSTermNode term = (CSSTermNode) parent;
String value = term.getAttribute("value");
if (isColor(value))
{
addIndex(context, IIndexConstants.CSS_COLOR, CSSColors.to6CharHexWithLeadingHash(value.trim()));
}
}
}
for (IParseNode child : parent.getChildren())
{
walkNode(child, context);
}
}
private boolean isColor(String value)
{
if (value == null || value.trim().length() == 0)
return false;
if (CSSColors.namedColorExists(value))
return true;
if (value.startsWith("#") && (value.length() == 4 || value.length() == 7))
return true; // FIXME Check to make sure it's hex values!
return false;
}
private void addIndex(BuildContext context, String category, String word)
{
Index index = getIndex(context);
indices.add(index);
index.addEntry(category, word, context.getFile().getProjectRelativePath().toPortableString());
}
private void indexCSS(BuildContext context)
{
LexemeList ll = context.getLexemeList();
for (Lexeme l : ll.toArray())
{
if (l == null || !l.getLanguage().equals(CSSMimeType.MimeType))
continue;
if (l.typeIndex == CSSTokenTypes.HASH)
{
String cssId = l.getText();
if (cssId.startsWith("#"))
cssId = cssId.substring(1);
addIndex(context, IIndexConstants.CSS_IDENTIFIER, cssId);
}
else if (l.typeIndex == CSSTokenTypes.CLASS)
{
String cssClass = l.getText();
if (cssClass.startsWith("."))
cssClass = cssClass.substring(1);
addIndex(context, IIndexConstants.CSS_CLASS, cssClass);
}
else if (l.typeIndex == CSSTokenTypes.COLOR
|| (l.typeIndex == CSSTokenTypes.IDENTIFIER && CSSColors
.namedColorExists(l.getText().toLowerCase())))
{
addIndex(context, IIndexConstants.CSS_COLOR, CSSColors.to6CharHexWithLeadingHash(l.getText()));
}
}
}
private Index getIndex(BuildContext context)
{
if (fIndex == null)
{
IProject project = context.getFile().getProject();
fIndex = IndexManager.getInstance().getIndex(project.getFullPath().toPortableString());
}
return fIndex;
}
@Override
public void cleanStarting(IProject project)
{
Index index = IndexManager.getInstance().getIndex(project.getFullPath().toPortableString());
index.removeCategories(IIndexConstants.CSS_CLASS, IIndexConstants.CSS_IDENTIFIER);
}
@Override
public boolean isActive(IProject project)
{
return true;
}
}