// Copyright 2010 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.android.stardroid.layers;
import com.google.android.stardroid.renderer.RendererObjectManager.UpdateType;
import com.google.android.stardroid.renderer.util.AbstractUpdateClosure;
import com.google.android.stardroid.renderer.util.UpdateClosure;
import com.google.android.stardroid.search.PrefixStore;
import com.google.android.stardroid.search.SearchResult;
import com.google.android.stardroid.source.AstronomicalSource;
import com.google.android.stardroid.source.ImageSource;
import com.google.android.stardroid.source.LineSource;
import com.google.android.stardroid.source.PointSource;
import com.google.android.stardroid.source.Sources;
import com.google.android.stardroid.source.TextSource;
import com.google.android.stardroid.units.GeocentricCoordinates;
import com.google.android.stardroid.util.MiscUtil;
import android.content.res.Resources;
import android.util.Log;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
/**
* Layer for objects which are {@link AstronomicalSource}s.
*
* @author Brent Bryan
*/
// TODO(brent): merge with AbstractLayer?
public abstract class AbstractSourceLayer extends AbstractLayer {
private static final String TAG = MiscUtil.getTag(AbstractSourceLayer.class);
private final ArrayList<TextSource> textSources = new ArrayList<TextSource>();
private final ArrayList<ImageSource> imageSources = new ArrayList<ImageSource>();
private final ArrayList<PointSource> pointSources = new ArrayList<PointSource>();
private final ArrayList<LineSource> lineSources = new ArrayList<LineSource>();
private final ArrayList<AstronomicalSource> astroSources = new ArrayList<AstronomicalSource>();
private HashMap<String, SearchResult> searchIndex = new HashMap<String, SearchResult>();
private PrefixStore prefixStore = new PrefixStore();
private final boolean shouldUpdate;
private SourceUpdateClosure closure;
public AbstractSourceLayer(Resources resources, boolean shouldUpdate) {
super(resources);
this.shouldUpdate = shouldUpdate;
}
@Override
public synchronized void initialize() {
astroSources.clear();
initializeAstroSources(astroSources);
for (AstronomicalSource astroSource : astroSources) {
Sources sources = astroSource.initialize();
textSources.addAll(sources.getLabels());
imageSources.addAll(sources.getImages());
pointSources.addAll(sources.getPoints());
lineSources.addAll(sources.getLines());
List<String> names = astroSource.getNames();
if (!names.isEmpty()) {
GeocentricCoordinates searchLoc = astroSource.getSearchLocation();
for (String name : names) {
searchIndex.put(name.toLowerCase(), new SearchResult(name, searchLoc));
prefixStore.add(name.toLowerCase());
}
}
}
// update the renderer
updateLayerForControllerChange();
}
@Override
protected void updateLayerForControllerChange() {
refreshSources(EnumSet.of(UpdateType.Reset));
if (shouldUpdate) {
if (closure == null) {
closure = new SourceUpdateClosure(this);
}
addUpdateClosure(closure);
}
}
/**
* Subclasses should override this method and add all their
* {@link AstronomicalSource} to the given {@link ArrayList}.
*/
protected abstract void initializeAstroSources(ArrayList<AstronomicalSource> sources);
/**
* Redraws the sources on this layer, after first refreshing them based on
* the current state of the
* {@link com.google.android.stardroid.control.AstronomerModel}.
*/
protected void refreshSources() {
refreshSources(EnumSet.noneOf(UpdateType.class));
}
/**
* Redraws the sources on this layer, after first refreshing them based on
* the current state of the
* {@link com.google.android.stardroid.control.AstronomerModel}.
*/
protected synchronized void refreshSources(EnumSet<UpdateType> updateTypes) {
for (AstronomicalSource astroSource : astroSources) {
updateTypes.addAll(astroSource.update());
}
if (!updateTypes.isEmpty()) {
redraw(updateTypes);
}
}
/**
* Forcefully resets and redraws all sources on this layer everything on
* this layer.
*/
@Override
protected void redraw() {
refreshSources(EnumSet.of(UpdateType.Reset));
}
private final void redraw(EnumSet<UpdateType> updateTypes) {
super.redraw(textSources, pointSources, lineSources, imageSources, updateTypes);
}
@Override
public List<SearchResult> searchByObjectName(String name) {
Log.d(TAG, "Search planets layer for " + name);
List<SearchResult> matches = new ArrayList<SearchResult>();
SearchResult searchResult = searchIndex.get(name.toLowerCase());
if (searchResult != null) {
matches.add(searchResult);
}
Log.d(TAG, getLayerName() + " provided " + matches.size() + "results for " + name);
return matches;
}
@Override
public Set<String> getObjectNamesMatchingPrefix(String prefix) {
Log.d(TAG, "Searching planets layer for prefix " + prefix);
Set<String> results = prefixStore.queryByPrefix(prefix);
Log.d(TAG, "Got " + results.size() + " results for prefix " + prefix + " in " + getLayerName());
return results;
}
/** Implementation of the {@link UpdateClosure} interface used to update a layer */
public static class SourceUpdateClosure extends AbstractUpdateClosure {
private final AbstractSourceLayer layer;
public SourceUpdateClosure(AbstractSourceLayer layer) {
this.layer = layer;
}
@Override
public void run() {
layer.refreshSources();
}
}
}