Index: src/uk/me/parabola/mkgmap/reader/osm/SeaGenerator.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/SeaGenerator.java	(revision 4594)
+++ src/uk/me/parabola/mkgmap/reader/osm/SeaGenerator.java	(working copy)
@@ -286,6 +286,7 @@
 		System.err.println("  land-tag=TAG=VAL    tag to use for land polygons (default natural=land)");
 		if (forPrecompSea)
 			return;
+
 		System.err.println("  no-sea-sectors      disable use of \"sea sectors\"");
 		System.err.println("  extend-sea-sectors  extend coastline to reach border");
 		System.err.println("  close-gaps=NUM      close gaps in coastline that are less than this distance (metres)");
@@ -294,7 +295,7 @@
 		System.err.println("  fbthres=NUM         min points contained in a polygon to be flood blocked (default 20)");
 		System.err.println("  fbratio=NUM         min ratio (points/area size) for flood blocking (default 0.5)");
 	}
-	
+
     /**
      * Read the index from stream and populate the index grid. 
      * @param fileStream already opened stream
@@ -602,9 +603,9 @@
 		}
 		
 		// check if the land tags need to be changed
-		boolean changeLadTag = landTag != null && ("natural".equals(landTag[0]) && !"land".equals(landTag[1]));
+		boolean changeLandTag = landTag != null && ("natural".equals(landTag[0]) && !"land".equals(landTag[1]));
 		for (Way w : landWays) {
-			if (changeLadTag) {
+			if (changeLandTag) {
 				w.deleteTag("natural");
 				w.addTag(landTag[0], landTag[1]);
 			}
@@ -760,7 +761,7 @@
 			} else if (w.getPoints().size() > 1){
 				beginMap.put(w.getFirstPoint(), w);
 			} else {
-				log.info("Discarding coastline way", w.getId(), "because it consists of less than 2 points");
+				log.info("Discarding coastline", w.getBasicLogInformation(), "because it consists of less than 2 points");
 			}
 		}
 		segments.clear();
@@ -785,7 +786,7 @@
 
 	// merge the ways and maintain maps and list
 	private static void merge(Map<Coord, Way> beginMap, List<Way> joined, Way w1, Way w2) {
-		log.info("merging: ", beginMap.size(), w1.getId(), w2.getId());
+		log.info("merging:", beginMap.size(), w1.getBasicLogInformation(), "with", w2.getBasicLogInformation());
 		Way wm;
 		if (FakeIdGenerator.isFakeId(w1.getId())) {
 			wm = w1;
@@ -831,7 +832,7 @@
 		}
 		
 		// clip all shoreline segments
-		clipShorlineSegments();
+		clipShorelineSegments();
 
 		if(shoreline.isEmpty()) {
 			// No sea required
@@ -877,11 +878,11 @@
 
 			createLandPolygons(hitMap);
 			processIslands(seaRelation);
-			processAntiIslands(true);
+			checkIslands(true);
 
 			Way sea = createSeaWay(true);
 
-			log.info("sea: ", sea);
+			log.info("sea:", sea);
 			saver.addWay(sea);
 			if(seaRelation != null)
 				seaRelation.addElement("outer", sea);
@@ -888,7 +889,7 @@
 		} else {
 			// background is land
 			createSeaPolygons(hitMap);
-			processAntiIslands(false);
+			checkIslands(false);
 			
 			// generate a land polygon so that the tile's
 			// background colour will match the land colour on the
@@ -931,26 +932,59 @@
 	}
 
 	/**
-	 * These are bits of sea have been generated as polygons.
-	 * if the tile is also sea based, then check that surrounded by an island
-	 * @param seaRelation if set, add as inner
+	 * Check whether land is enclosed in land or sea within sea.
 	 * @param seaBased true if the tile is also sea with land [multi-]polygons
 	 */
-	private void processAntiIslands(boolean seaBased) {
+	private void checkIslands(boolean seaBased) {
 		for (Way ai : antiIslands) {
-			if (seaBased) {
-				boolean containedByLand = false;
-				for (Way i : islands) {
-					if (i.containsPointsOf(ai)) {
-						containedByLand = true;
-						break;
-					}
+			Way containingLand = null;
+			Way containingSea = null;
+			for (Way i : islands) {
+				if (i.containsPointsOf(ai) && ((containingLand == null) || (containingLand.containsPointsOf(i))))
+					containingLand = i;
+			}
+			for (Way ai2 : antiIslands) {
+				if ((ai2 != ai) && ai2.containsPointsOf(ai) && ((containingSea == null) || containingSea.containsPointsOf(ai2)))
+					containingSea = ai2;
+			}
+			if ((containingSea != null) && (containingLand != null)) {
+				if (containingSea.containsPointsOf(containingLand))
+					containingSea = null;
+				else if (containingLand.containsPointsOf(containingSea))
+					containingLand = null;
+				else {
+					log.warn("inner sea", ai.getBasicLogInformation(), "is surrounded by both water", containingSea.getBasicLogInformation(), "and land", containingLand.getBasicLogInformation());
+					containingSea = null;
+					containingLand = null;
 				}
-				if (!containedByLand) {
-					// found an anti-island that is not contained by land
-					log.warn("inner sea", ai , "is surrounded by water");
+			}
+			if ((containingLand == null) & (seaBased | (containingSea != null)))
+				log.error("inner sea", ai.getBasicLogInformation(), "is surrounded by water", containingSea == null ? "" : containingSea.getBasicLogInformation());
+		}
+		for (Way i : islands) {
+			Way containingLand = null;
+			Way containingSea = null;
+			for (Way ai : antiIslands) {
+				if (ai.containsPointsOf(i) && ((containingSea == null) || containingSea.containsPointsOf(ai)))
+					containingSea = ai;
+			}
+			for (Way i2 : islands) {
+				if ((i2 != i) && i2.containsPointsOf(i) && ((containingLand == null) || (containingLand.containsPointsOf(i2))))
+					containingLand = i2;
+			}
+			if ((containingSea != null) && (containingLand != null)) {
+				if (containingSea.containsPointsOf(containingLand))
+					containingSea = null;
+				else if (containingLand.containsPointsOf(containingSea))
+					containingLand = null;
+				else {
+					log.warn("island", i.getBasicLogInformation(), "is surrounded by both water", containingSea.getBasicLogInformation(), "and land", containingLand.getBasicLogInformation());
+					containingSea = null;
+					containingLand = null;
 				}
 			}
+			if ((containingSea == null) && (containingLand != null))
+				log.error("island", i.getBasicLogInformation(), "is surrounded by land", containingLand.getBasicLogInformation());
 		}
 	}
 
@@ -990,7 +1024,7 @@
 	 * @param shoreline All the the ways making up the coast.
 	 * @param bounds The map bounds.
 	 */
-	private void clipShorlineSegments() {
+	private void clipShorelineSegments() {
 		List<Way> toBeRemoved = new ArrayList<>();
 		List<Way> toBeAdded = new ArrayList<>();
 		for (Way segment : shoreline) {
@@ -997,7 +1031,7 @@
 			List<Coord> points = segment.getPoints();
 			List<List<Coord>> clipped = LineClipper.clip(tileBounds, points);
 			if (clipped != null) {
-				log.info("clipping", segment);
+				log.info("clipping", segment.getBasicLogInformation());
 				toBeRemoved.add(segment);
 				for (List<Coord> pts : clipped) {
 					Way shore = new Way(segment.getOriginalId(), pts);
@@ -1032,7 +1066,7 @@
 		while (it.hasNext()) {
 			Way w = it.next();
 			if (w.hasIdenticalEndPoints()) {
-				log.debug("closed after concatenating", w);
+				log.debug("closed after concatenating", w.getBasicLogInformation());
 				addClosedShore(w);
 				it.remove();
 			}
@@ -1112,12 +1146,12 @@
 		if (Way.clockwise(w.getPoints()))
 			addAsSea(w);
 		else
-		    	addAsLand(w);
+			addAsLand(w);
 	}
 
 	private void addAsSea(Way w) {
 		w.addTag("natural", "sea");
-		log.info("adding anti-island", w);
+		log.info("adding anti-island", w.getBasicLogInformation());
 		antiIslands.add(w);
 		w.setFullArea(SEA_SIZE);
 		saver.addWay(w);
@@ -1125,7 +1159,7 @@
 
 	private void addAsLand(Way w) {
 		w.addTag(landTag[0], landTag[1]);
-		log.info("adding island", w);
+		log.info("adding island", w.getBasicLogInformation());
 		islands.add(w);
 		saver.addWay(w);
 	}
@@ -1141,10 +1175,11 @@
 			Way w = new Way(FakeIdGenerator.makeFakeId());
 			Double hFirst = hits.first();
 			Double hStart = hFirst, hEnd;
+			w.markAsGeneratedFrom(hitMap.get(hFirst));
 			boolean finished = false;
 			do {
 				Way segment = hitMap.get(hStart);
-				log.info("current hit:", hStart, "adding:", segment);
+				log.info("current hit:", hStart, "adding:", segment.getBasicLogInformation());
 				segment.getPoints().forEach(w::addPointIfNotEqualToLastPoint);
 				hits.remove(hStart);
 				hEnd = getEdgeHit(tileBounds, segment.getLastPoint());
@@ -1179,10 +1214,11 @@
 			Way w = new Way(FakeIdGenerator.makeFakeId());
 			Double hFirst = hits.last();
 			Double hStart = hFirst, hEnd;
+			w.markAsGeneratedFrom(hitMap.get(hFirst));
 			boolean finished = false;
 			do {
 				Way segment = hitMap.get(hStart);
-				log.info("current hit:", hStart, "adding:", segment);
+				log.info("current hit:", hStart, "adding:", segment.getBasicLogInformation());
 				segment.getPoints().forEach(w::addPointIfNotEqualToLastPoint);
 				hits.remove(hStart);
 				hEnd = getEdgeHit(tileBounds, segment.getLastPoint());
@@ -1247,7 +1283,7 @@
 			Double hEnd = getEdgeHit(tileBounds, pEnd);
 			if (hStart != null && hEnd != null) {
 				// nice case: both ends touch the boundary 
-				log.debug("hits: ", hStart, hEnd);
+				log.debug("hits:", hStart, hEnd);
 				hitMap.put(hStart, w);
 				hitMap.put(hEnd, null); // put this for verifyHits which then deletes it
 			} else {
@@ -1271,6 +1307,7 @@
 				List<Coord> points = w.getPoints();
 				if (allowSeaSectors) {
 					Way seaOrLand = new Way(FakeIdGenerator.makeFakeId());
+					seaOrLand.markAsGeneratedFrom(w);
 					seaOrLand.getPoints().addAll(points);
 					int startLat = pStart.getHighPrecLat();
 					int startLon = pStart.getHighPrecLon();
@@ -1293,7 +1330,7 @@
 					}
 					seaOrLand.addPoint(Coord.makeHighPrecCoord(cornerLat, cornerLon));
 					seaOrLand.addPoint(pStart);
-					log.info("seaSector: ", generateSeaBackground, startLatIsCorner, Way.clockwise(seaOrLand.getPoints()), seaOrLand);
+					log.info("seaSector:", generateSeaBackground, startLatIsCorner, Way.clockwise(seaOrLand.getPoints()), seaOrLand.getBasicLogInformation());
 				} else if (extendSeaSectors) {
 					// join to nearest tile border
 					if (null == hStart) {
@@ -1304,7 +1341,7 @@
 						hEnd = getNextEdgeHit(tileBounds, pEnd);
 						w.getPoints().add(getPoint(tileBounds, hEnd));
 					}
-					log.debug("hits (second try): ", hStart, hEnd);
+					log.debug("hits (second try):", hStart, hEnd);
 					hitMap.put(hStart, w);
 					hitMap.put(hEnd, null); // put this for verifyHits which then deletes it
 				} else {
@@ -1330,6 +1367,7 @@
 		NavigableSet<Double> hits = hitMap.navigableKeySet();
 		Iterator<Double> iter = hits.iterator();
 		int lastStatus = 0, thisStatus;
+		Double lastHit = 0.0;
 		while (iter.hasNext()) {
 			Double aHit = iter.next();
 			Way segment = hitMap.get(aHit);
@@ -1341,14 +1379,15 @@
 				thisStatus = +1;
 			}
 			if (thisStatus == lastStatus)
-				log.error("Adjacent coastlines hit tile edge in same direction", aHit, segment);
+				log.error("Adjacent coastlines hit tile edge in same direction at", getPoint(tileBounds, lastHit).toDegreeString(), "and", getPoint(tileBounds, aHit).toDegreeString(), segment);
 			lastStatus = thisStatus;
+			lastHit = aHit;
 		}
 	}
 
 	// create the point where the shoreline hits the sea bounds
 	private static Coord getPoint(Area a, double edgePos) {
-		log.info("getPoint: ", a, edgePos);
+		log.info("getPoint:", a, edgePos);
 		int aMinLongHP = a.getMinLong() << Coord.DELTA_SHIFT;
 		int aMaxLongHP = a.getMaxLong() << Coord.DELTA_SHIFT;
 		int aMinLatHP = a.getMinLat() << Coord.DELTA_SHIFT;
