1package com.xtremelabs.robolectric.res;
2
3import android.view.View;
4import org.w3c.dom.Document;
5import org.w3c.dom.Node;
6import org.w3c.dom.NodeList;
7
8import javax.xml.xpath.XPathConstants;
9import javax.xml.xpath.XPathExpression;
10import javax.xml.xpath.XPathFactory;
11import java.io.File;
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.Map;
15import java.util.Set;
16
17public class AttrResourceLoader extends XmlLoader {
18    Map<String, String> classAttrEnumToValue = new HashMap<String, String>();
19    Set<String> knownClassAttrs = new HashSet<String>();
20
21    public AttrResourceLoader(ResourceExtractor resourceExtractor) {
22        super(resourceExtractor);
23    }
24
25    @Override
26    protected void processResourceXml(File xmlFile, Document document, boolean isSystem) throws Exception {
27        XPathExpression stringsXPath = XPathFactory.newInstance().newXPath().compile("/resources/declare-styleable/attr/enum");
28        NodeList stringNodes = (NodeList) stringsXPath.evaluate(document, XPathConstants.NODESET);
29        for (int i = 0; i < stringNodes.getLength(); i++) {
30            Node node = stringNodes.item(i);
31            String viewName = node.getParentNode().getParentNode().getAttributes().getNamedItem("name").getNodeValue();
32            String enumName = node.getParentNode().getAttributes().getNamedItem("name").getNodeValue();
33            String name = node.getAttributes().getNamedItem("name").getNodeValue();
34            String value = node.getAttributes().getNamedItem("value").getNodeValue();
35
36            classAttrEnumToValue.put(key(viewName, enumName, name, isSystem), value);
37            knownClassAttrs.add(key(viewName, enumName, isSystem));
38        }
39    }
40
41    public String convertValueToEnum(Class<? extends View> viewClass, String namespace, String attrName, String attrValue) {
42        boolean isSystem = "android".equals(namespace);
43        String className = findKnownAttrClass(attrName, viewClass, isSystem);
44        return classAttrEnumToValue.get(key(className, attrName, attrValue, isSystem));
45    }
46
47    public boolean hasAttributeFor(Class<? extends View> viewClass, String namespace, String attrName) {
48        boolean isSystem = "android".equals(namespace);
49        return findKnownAttrClass(attrName, viewClass, isSystem) != null;
50    }
51
52    private String findKnownAttrClass(String attrName, Class<?> clazz, boolean isSystem) {
53        while (clazz != null) {
54            String className = clazz.getName();
55            if (isSystem) {
56                className = clazz.getSimpleName();
57            }
58            if (knownClassAttrs.contains(key(className, attrName, isSystem))) {
59                return className;
60            }
61            clazz = clazz.getSuperclass();
62        }
63        return null;
64    }
65
66    private String key(String viewName, String attrName, String name, boolean isSystem) {
67        return key(viewName, attrName, isSystem) + "#" + name;
68    }
69
70    private String key(String viewName, String attrName, boolean isSystem) {
71        return (isSystem ? "android:" : "") + viewName + "#" + attrName;
72    }
73}
74