package org.openstreetmap.josm.gui.mappaint;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.data.osm.Node;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
import org.openstreetmap.josm.data.osm.OsmUtils;
import org.openstreetmap.josm.data.osm.Way;
public class ElemStyles
{
public static class StyleSet {
private HashMap<String, IconElemStyle> icons;
private HashMap<String, LineElemStyle> lines;
private HashMap<String, AreaElemStyle> areas;
private HashMap<String, LineElemStyle> modifiers;
private LinkedList<IconElemStyle> iconsList;
private LinkedList<LineElemStyle> linesList;
private LinkedList<AreaElemStyle> areasList;
private LinkedList<LineElemStyle> modifiersList;
public StyleSet()
{
icons = new HashMap<String, IconElemStyle>();
lines = new HashMap<String, LineElemStyle>();
modifiers = new HashMap<String, LineElemStyle>();
areas = new HashMap<String, AreaElemStyle>();
iconsList = new LinkedList<IconElemStyle>();
linesList = new LinkedList<LineElemStyle>();
modifiersList = new LinkedList<LineElemStyle>();
areasList = new LinkedList<AreaElemStyle>();
}
private IconElemStyle getNode(OsmPrimitive primitive)
{
IconElemStyle ret = null;
for (String key: primitive.keySet()) {
String val = primitive.get(key);
IconElemStyle style;
if((style = icons.get("n" + key + "=" + val)) != null)
{
if(ret == null || style.priority > ret.priority) {
ret = style;
}
}
if((style = icons.get("b" + key + "=" + OsmUtils.getNamedOsmBoolean(val))) != null)
{
if(ret == null || style.priority > ret.priority) {
ret = style;
}
}
if((style = icons.get("x" + key)) != null)
{
if(ret == null || style.priority > ret.priority) {
ret = style;
}
}
}
for(IconElemStyle s : iconsList)
{
if((ret == null || s.priority > ret.priority) && s.check(primitive)) {
ret = s;
}
}
return ret;
}
private ElemStyle get(OsmPrimitive primitive, boolean noclosed)
{
AreaElemStyle retArea = null;
LineElemStyle retLine = null;
String linestring = null;
HashMap<String, LineElemStyle> over = new HashMap<String, LineElemStyle>();
for (String key: primitive.keySet()) {
String val = primitive.get(key);
AreaElemStyle styleArea;
LineElemStyle styleLine;
String idx = "n" + key + "=" + val;
if((styleArea = areas.get(idx)) != null && (retArea == null
|| styleArea.priority > retArea.priority) && (!noclosed
|| !styleArea.closed)) {
retArea = styleArea;
}
if((styleLine = lines.get(idx)) != null && (retLine == null
|| styleLine.priority > retLine.priority))
{
retLine = styleLine;
linestring = idx;
}
if((styleLine = modifiers.get(idx)) != null) {
over.put(idx, styleLine);
}
idx = "b" + key + "=" + OsmUtils.getNamedOsmBoolean(val);
if((styleArea = areas.get(idx)) != null && (retArea == null
|| styleArea.priority > retArea.priority) && (!noclosed
|| !styleArea.closed)) {
retArea = styleArea;
}
if((styleLine = lines.get(idx)) != null && (retLine == null
|| styleLine.priority > retLine.priority))
{
retLine = styleLine;
linestring = idx;
}
if((styleLine = modifiers.get(idx)) != null) {
over.put(idx, styleLine);
}
idx = "x" + key;
if((styleArea = areas.get(idx)) != null && (retArea == null
|| styleArea.priority > retArea.priority) && (!noclosed
|| !styleArea.closed)) {
retArea = styleArea;
}
if((styleLine = lines.get(idx)) != null && (retLine == null
|| styleLine.priority > retLine.priority))
{
retLine = styleLine;
linestring = idx;
}
if((styleLine = modifiers.get(idx)) != null) {
over.put(idx, styleLine);
}
}
for(AreaElemStyle s : areasList)
{
if((retArea == null || s.priority > retArea.priority)
&& (!noclosed || !s.closed) && s.check(primitive)) {
retArea = s;
}
}
for(LineElemStyle s : linesList)
{
if((retLine == null || s.priority > retLine.priority)
&& s.check(primitive)) {
retLine = s;
}
}
for(LineElemStyle s : modifiersList)
{
if(s.check(primitive)) {
over.put(s.getCode(), s);
}
}
over.remove(linestring);
if(over.size() != 0 && retLine != null)
{
List<LineElemStyle> s = new LinkedList<LineElemStyle>(over.values());
Collections.sort(s);
retLine = new LineElemStyle(retLine, s);
}
if(retArea != null)
{
if(retLine != null)
return new AreaElemStyle(retArea, retLine);
else
return retArea;
}
return retLine;
}
public ElemStyle get(OsmPrimitive osm)
{
return (!osm.hasKeys()) ? null :
((osm instanceof Node) ? getNode(osm) : get(osm,
osm instanceof Way && !((Way)osm).isClosed()));
}
public ElemStyle getArea(Way osm)
{
if(osm.hasKeys())
{
/* force area mode also for unclosed ways */
ElemStyle style = get(osm, false);
if(style != null && style instanceof AreaElemStyle)
return style;
}
return null;
}
public IconElemStyle getIcon(OsmPrimitive osm)
{
return osm.hasKeys() ? getNode(osm): null;
}
public boolean isArea(OsmPrimitive o)
{
if(o.hasKeys() && !(o instanceof Node))
{
boolean noclosed = o instanceof Way && !((Way)o).isClosed();
Iterator<String> iterator = o.keySet().iterator();
while(iterator.hasNext())
{
String key = iterator.next();
String val = o.get(key);
AreaElemStyle s = areas.get("n" + key + "=" + val);
if(s == null || (s.closed && noclosed)) {
s = areas.get("b" + key + "=" + OsmUtils.getNamedOsmBoolean(val));
}
if(s == null || (s.closed && noclosed)) {
s = areas.get("x" + key);
}
if(s != null && !(s.closed && noclosed))
return true;
}
for(AreaElemStyle s : areasList)
{
if(!(s.closed && noclosed) && s.check(o))
return true;
}
}
return false;
}
public boolean hasAreas()
{
return areas.size() > 0;
}
}
HashMap<String, StyleSet> styleSet;
public ElemStyles()
{
styleSet = new HashMap<String, StyleSet>();
}
public void add(String name, Rule r, Collection<Rule> rules, LineElemStyle style)
{
if(rules != null)
{
style.rules = rules;
getStyleSet(name, true).linesList.add(style);
}
else
{
String key = r.getKey();
style.code = key;
getStyleSet(name, true).lines.put(key, style);
}
}
public void addModifier(String name, Rule r, Collection<Rule> rules, LineElemStyle style)
{
if(rules != null)
{
style.rules = rules;
getStyleSet(name, true).modifiersList.add(style);
}
else
{
String key = r.getKey();
style.code = key;
getStyleSet(name, true).modifiers.put(key, style);
}
}
public void add(String name, Rule r, Collection<Rule> rules, AreaElemStyle style)
{
if(rules != null)
{
style.rules = rules;
getStyleSet(name, true).areasList.add(style);
}
else
{
String key = r.getKey();
style.code = key;
getStyleSet(name, true).areas.put(key, style);
}
}
public void add(String name, Rule r, Collection<Rule> rules, IconElemStyle style)
{
if(rules != null)
{
style.rules = rules;
getStyleSet(name, true).iconsList.add(style);
}
else
{
String key = r.getKey();
style.code = key;
getStyleSet(name, true).icons.put(key, style);
}
}
private StyleSet getStyleSet(String name, boolean create)
{
if(name == null) {
name = Main.pref.get("mappaint.style", "standard");
}
StyleSet s = styleSet.get(name);
if(create && s == null)
{
s = new StyleSet();
styleSet.put(name, s);
}
return s;
}
/* called from class users, never return null */
public StyleSet getStyleSet()
{
return getStyleSet(null, true);
}
public Collection<String> getStyleNames()
{
return styleSet.keySet();
}
}