Index: resources/help/en/options
===================================================================
--- resources/help/en/options	(revision 3351)
+++ resources/help/en/options	(working copy)
@@ -238,6 +238,11 @@
   available within that file. If it is also preceded by the style
   option it will only check that style.
 
+--report-style-stats
+	Issue one info message for each rule in the style file(s)
+	showing how often the rule expression was evaluated and how 
+	often the evaluation returned true.
+	  	
 --levels=levels code
 	Change the way that the levels on the map correspond to the zoom
 	levels in the device. See customisation help. The default is:
Index: src/uk/me/parabola/mkgmap/main/StyleTester.java
===================================================================
--- src/uk/me/parabola/mkgmap/main/StyleTester.java	(revision 3351)
+++ src/uk/me/parabola/mkgmap/main/StyleTester.java	(working copy)
@@ -670,6 +670,28 @@
 					rule.setFinalizeRule(finalizeRule);
 				}
 			}
+
+			@Override
+			public Rule getFinalizeRule() {
+				Rule r = null;
+				for (Rule rule : rules){ 
+					r = rule.getFinalizeRule();
+					break;
+				}
+				return r;
+			}
+
+			@Override
+			public long getNumEval() {
+				// TODO Auto-generated method stub
+				return 0;
+			}
+
+			@Override
+			public long getNumTrue() {
+				// TODO Auto-generated method stub
+				return 0;
+			}
 		}
 
 		/**
Index: src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java	(revision 3351)
+++ src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java	(working copy)
@@ -40,6 +40,8 @@
 	private final List<Action> actions;
 	private final GType type;
 	private Rule finalizeRule;
+	private long numEval; // count how often the expression was evaluated 
+	private long numTrue; // count how often the evaluation returned true
 
 	/** Finalize rules must not have an element type definition so the add method must never be called. */
 	private final static TypeResult finalizeTypeResult = new TypeResult() {
@@ -66,9 +68,10 @@
 	public int resolveType(int cacheId, Element el, TypeResult result) {
 		Element element = el;
 		if (expression != null) {
+			numEval++;
 			if (!expression.eval(cacheId, element))
 				return cacheId;
-				
+			numTrue++;
 			// If this is a continue and we are not to propagate the effects
 			// of the action on the element to further rules, then make
 			// a copy of the element so that the original is unsullied.
@@ -108,8 +111,10 @@
 	public void resolveType(Element el, TypeResult result) {
 		Element element = el;
 		if (expression != null) {
+			numEval++;
 			if (!expression.eval(element))
 				return;
+			numTrue++;
 			// If this is a continue and we are not to propagate the effects
 			// of the action on the element to further rules, then make
 			// a copy of the element so that the original is unsullied.
@@ -159,6 +164,7 @@
 		this.finalizeRule = finalizeRule;
 	}
 
+	
 
 	public Op getOp(){
 		return expression;
@@ -168,4 +174,16 @@
 		this.expression = expression;
 	}
 	
+	public long getNumEval(){
+		return numEval;
+	}
+	
+	public long getNumTrue(){
+		return numTrue;
+	}
+
+	@Override
+	public Rule getFinalizeRule() {
+		return finalizeRule;
+	}
 }
Index: src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java	(revision 3351)
+++ src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java	(working copy)
@@ -32,6 +32,8 @@
 	private Op expression;
 	private final GType gtype;
 	private Rule finalizeRule;
+	private long numEval; // count how often the expression was evaluated 
+	private long numTrue; // count how often the evaluation returned true
 
 	/** Finalize rules must not have an element type definition so the add method must never be called. */
 	private final static TypeResult finalizeTypeResult = new TypeResult() {
@@ -47,7 +49,9 @@
 
 	
 	public void resolveType(Element el, TypeResult result) {
+		numEval++;
 		if (expression.eval(el)) {
+			numTrue++;
 			// expression matches
 			if (finalizeRule != null) {
 				if (gtype.isContinueSearch()) {
@@ -63,7 +67,9 @@
 	}
 
 	public int resolveType(int cacheId, Element el, TypeResult result) {
+		numEval++;
 		if (expression.eval(cacheId, el)){
+			numTrue++;
 			if (finalizeRule != null) {
 				if (gtype.isContinueSearch()) {
 					el = el.copy();
@@ -93,5 +99,16 @@
 	public void setOp(Op expression){
 		this.expression = expression;
 	}
+
+	public long getNumEval(){
+		return numEval;
+	}
 	
+	public long getNumTrue(){
+		return numTrue;
+	}
+	@Override
+	public Rule getFinalizeRule() {
+		return finalizeRule;
+	}
 }
Index: src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java	(revision 3351)
+++ src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java	(working copy)
@@ -260,4 +260,35 @@
 		
 		compiled = false;
 	}
+
+	public long getNumEval(){
+		long count = 0;
+		for (Rule r : rules)
+			count += r.getNumEval();
+		return count;
+	}
+	
+	public long getNumTrue(){
+		long count = 0;
+		for (Rule r : rules)
+			count += r.getNumTrue();
+		return count;
+	}
+	@Override
+	public Rule getFinalizeRule() {
+		if (rules == null) {
+			// this method must be called after prepare() is called so
+			// that we have rules to which the finalize rules can be applied
+			throw new IllegalStateException("First call prepare() before setting the finalize rules");
+		}
+		// all rules have the same finalize rule(s), so we just use the first one to extract it
+		Rule r = null;
+		for (Rule rule : rules){ 
+			r = rule.getFinalizeRule();
+			break;
+		}
+		return r;
+		
+	}
+
 } 
\ No newline at end of file
Index: src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java	(revision 3351)
+++ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java	(working copy)
@@ -124,6 +124,8 @@
 	private final Rule nodeRules;
 	private final Rule lineRules;
 	private final Rule polygonRules;
+	private final Rule relationRules;
+	private Style style;
 
 	private boolean driveOnLeft;
 	private boolean driveOnRight;
@@ -132,6 +134,7 @@
 	private final boolean linkPOIsToWays;
 	private final boolean mergeRoads;
 	private WrongAngleFixer wrongAngleFixer;
+	private boolean reportStyleStats;
 
 	private LineAdder lineAdder = new LineAdder() {
 		public void add(MapLine element) {
@@ -153,11 +156,12 @@
 				nameTagList.add(TagDict.getInstance().xlate(n));
 		} else 
 			nameTagList = null;
-
+		this.style = style;
 		wayRules = style.getWayRules();
 		nodeRules = style.getNodeRules();
 		lineRules = style.getLineRules();
 		polygonRules = style.getPolygonRules();
+		relationRules = style.getRelationRules();
 		
 		housenumberGenerator = new HousenumberGenerator(props);
 
@@ -180,6 +184,7 @@
 		mergeRoads = props.getProperty("no-mergeroads", false) == false;
 
 		wrongAngleFixer = new WrongAngleFixer(bbox);
+		reportStyleStats = props.getProperty("report-style-stats") != null;
 	}
 
 	/** One type result for ways to avoid recreating one for each way. */ 
@@ -504,6 +509,8 @@
 	}
 	
 	public void end() {
+		if (reportStyleStats)
+			style.reportStats();
 		setHighwayCounts();
 		findUnconnectedRoads();
 		rotateClosedWaysToFirstNode();
Index: src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java	(revision 3351)
+++ src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java	(working copy)
@@ -568,7 +568,35 @@
 		}
 		return style;
 	}
+
+	@Override
+	public void reportStats() {
+		if (log.isInfoEnabled() == false)
+			return;
+		reportRulesetStats("relations", relations);
+		reportRulesetStats("points", nodes);
+		reportRulesetStats("lines", lines);
+		reportRulesetStats("polygons", polygons);
+	}
 	
+	private void reportRulesetStats(String filename, RuleSet rs){
+		if (rs == null)
+			return;
+		Rule finalRules = null;
+		for (Rule r : rs){
+			log.info(filename,"stats (rule/evals/true)", r.toString() + "/" +r.getNumEval() + "/" + r.getNumTrue());
+			if (finalRules == null)
+				finalRules = r.getFinalizeRule();
+		}
+		if (finalRules != null){
+			if (finalRules instanceof RuleSet){
+				for (Rule r : (RuleSet) finalRules)
+					log.info(filename,"stats (rule/evals/true)", r.toString() + "/" +r.getNumEval() + "/" + r.getNumTrue());
+			} else  
+				log.info(filename,"stats (rule/evals/true)", finalRules.toString() + "/" +finalRules.getNumEval() + "/" + finalRules.getNumTrue());
+		}
+	}
+	
 	public static void main(String[] args) throws FileNotFoundException {
 		String file = args[0];
 		String name = null;
@@ -578,4 +606,5 @@
 
 		style.dumpToFile(new OutputStreamWriter(System.out));
 	}
+
 }
Index: src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java	(revision 3351)
+++ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java	(working copy)
@@ -150,13 +150,13 @@
 	 */
 	protected void setupHandler(OsmHandler handler) {
 		createElementSaver();
+		createConverter();
+		
 		osmReadingHooks = pluginChain(elementSaver, getConfig());
 
 		handler.setElementSaver(elementSaver);
 		handler.setHooks(osmReadingHooks);
 
-		createConverter();
-
 		handler.setUsedTags(getUsedTags());
 
 		String deleteTagsFileName = getConfig().getProperty("delete-tags-file");
@@ -180,10 +180,12 @@
 	
 	protected OsmReadingHooks pluginChain(ElementSaver saver, EnhancedProperties props) {
 		List<OsmReadingHooks> plugins = new ArrayList<OsmReadingHooks>();
-
 		for (OsmReadingHooks p : getPossibleHooks()) {
-			if (p.init(saver, props))
+			if (p.init(saver, props)){
 				plugins.add(p);
+				if (p instanceof RelationStyleHook)
+					((RelationStyleHook) p).setStyle(style);
+			}
 		}
 
 		OsmReadingHooks hooks;
Index: src/uk/me/parabola/mkgmap/reader/osm/RelationStyleHook.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/RelationStyleHook.java	(revision 3351)
+++ src/uk/me/parabola/mkgmap/reader/osm/RelationStyleHook.java	(working copy)
@@ -28,7 +28,7 @@
 	private Style style;
 	private ElementSaver saver;
 	List<String> nameTagList;
-
+	
 	public RelationStyleHook() {
 	}
 
@@ -35,10 +35,13 @@
 	public boolean init(ElementSaver saver, EnhancedProperties props) {
 		this.saver = saver;
 		nameTagList = LocatorUtil.getNameTags(props);
-		style = StyleImpl.readStyle(props);
 		return super.init(saver, props);
 	}
 
+	public void setStyle(Style style){
+		this.style = style;
+	}
+	
 	public void end() {
 		Rule relationRules = style.getRelationRules();
 		for (Relation rel : saver.getRelations().values()) {
@@ -57,8 +60,6 @@
 			}
 		}
 		super.end();
-		
-		style = null;
 	}
 
 	
Index: src/uk/me/parabola/mkgmap/reader/osm/Rule.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/Rule.java	(revision 3351)
+++ src/uk/me/parabola/mkgmap/reader/osm/Rule.java	(working copy)
@@ -53,5 +53,10 @@
 	 */
 	public void setFinalizeRule(Rule finalizeRule);
 	
+	public Rule getFinalizeRule();
 	
+	public long getNumEval();
+	
+	public long getNumTrue();
+	
 }
Index: src/uk/me/parabola/mkgmap/reader/osm/Style.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/Style.java	(revision 3351)
+++ src/uk/me/parabola/mkgmap/reader/osm/Style.java	(working copy)
@@ -74,4 +74,6 @@
 	 * Get the tags that are used by this style.
 	 */
 	public Set<String> getUsedTags();
+	
+	public void reportStats();
 }
