/*
* Copyright (C) 2010, 2012.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 or
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
package uk.me.parabola.mkgmap.reader.osm;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import uk.me.parabola.imgfmt.app.Area;
import uk.me.parabola.imgfmt.app.Coord;
import uk.me.parabola.log.Logger;
import uk.me.parabola.util.EnhancedProperties;
public final class CoastlineFileLoader
{
private static final Logger log =
Logger.
getLogger(CoastlineFileLoader.
class);
private final Set<String> coastlineFiles
;
private final Collection<CoastlineWay
> coastlines =
new ArrayList<>();
private final AtomicBoolean coastlinesLoaded =
new AtomicBoolean(false);
private final AtomicBoolean loadingStarted =
new AtomicBoolean(false);
private final EnhancedProperties coastConfig
;
private CoastlineFileLoader
() {
this.
coastlineFiles =
new HashSet<>();
this.
coastConfig =
new EnhancedProperties
();
}
private static final CoastlineFileLoader loader =
new CoastlineFileLoader
();
public static synchronized CoastlineFileLoader getCoastlineLoader
() {
return loader
;
}
public synchronized void setCoastlineFiles
(String[] coastlineFiles
) {
this.
coastlineFiles.
addAll(Arrays.
asList(coastlineFiles
));
}
public void loadCoastlines
() {
boolean loadInThisThread = loadingStarted.
compareAndSet(false,
true);
if (loadInThisThread
) {
// load it
loadCoastlinesImpl
();
} else {
log.
info("Coastline loading performed by another thread");
}
}
private OsmMapDataSource loadFromFile
(String name
) throws FileNotFoundException {
OsmMapDataSource src =
new OsmCoastDataSource
();
src.
config(getConfig
());
log.
info("Started loading coastlines from", name
);
src.
load(name,
false);
log.
info("Finished loading coastlines from", name
);
return src
;
}
private Collection<Way
> loadFile
(String filename
) throws FileNotFoundException {
OsmMapDataSource src = loadFromFile
(filename
);
return src.
getElementSaver().
getWays().
values();
}
private EnhancedProperties getConfig
() {
return coastConfig
;
}
private synchronized void loadCoastlinesImpl
() {
log.
info("Load coastlines");
for (String coastlineFile : coastlineFiles
) {
try {
int nBefore = coastlines.
size();
Collection<Way
> loadedCoastlines = loadFile
(coastlineFile
);
log.
info(loadedCoastlines.
size(),
"coastline ways from", coastlineFile,
"loaded.");
List<Way
> ways = SeaGenerator.
joinWays(loadedCoastlines
);
ListIterator<Way
> wayIter = ways.
listIterator();
while (wayIter.
hasNext()) {
Way way = wayIter.
next();
wayIter.
remove();
coastlines.
add(new CoastlineWay
(way.
getId(), way.
getPoints()));
}
log.
info((coastlines.
size() - nBefore
),
"coastlines loaded from", coastlineFile
);
} catch (FileNotFoundException exp
) {
log.
error("Coastline file " + coastlineFile +
" not found.");
} catch (Exception exp
) {
log.
error("Unexpected exception reading " + coastlineFile, exp
);
}
}
coastlinesLoaded.
set(true);
}
public Collection<Way
> getCoastlines
(Area bbox
) {
if (!coastlinesLoaded.
get()) {
synchronized (this) {
loadCoastlines
();
}
}
Collection<Way
> ways =
new ArrayList<>();
for (CoastlineWay w : coastlines
) {
if (w.
getBbox().
intersects(bbox
)) {
Way x =
new Way
(w.
getOriginalId(), w.
getPoints());
x.
markAsGeneratedFrom(w
);
x.
addTag("natural",
"coastline");
ways.
add(x
);
}
}
return ways
;
}
public static class CoastlineWay
extends Way
{
private final Area bbox
;
public CoastlineWay
(long id,
List<Coord
> points
) {
super(id, points
);
if (points.
isEmpty()) {
throw new IllegalArgumentException("No support for empty ways. WayId: " + id
);
}
if (log.
isDebugEnabled())
log.
debug("Create coastline way", id,
"with", points.
size(),
"points");
bbox =
Area.
getBBox(points
);
}
@
Override
public String getTag
(String key
) {
if ("natural".
equals(key
)) {
return "coastline";
} else {
return null;
}
}
@
Override
public String toTagString
() {
return "[natural=coastline]";
}
@
Override
public Map<String,
String> getTagsWithPrefix
(String prefix,
boolean removePrefix
) {
if ("natural".
startsWith(prefix
)) {
if (removePrefix
) {
return Collections.
singletonMap("natural".
substring(prefix.
length()),
"coastline");
} else {
return Collections.
singletonMap("natural",
"coastline");
}
} else {
return Collections.
emptyMap();
}
}
@
Override
public void removeAllTags
() {
}
@
Override
public Iterable<Entry
<String,
String>> getTagEntryIterator
() {
return Collections.
singletonMap("natural",
"coastline").
entrySet();
}
public Area getBbox
() {
return bbox
;
}
}
}