/*************************************************************************
* Copyright (c) 2015 Lemberg Solutions
*
* 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.ls.widgets.map.model;
import java.util.ArrayList;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable.Callback;
import android.os.Looper;
import com.ls.widgets.map.MapWidget;
import com.ls.widgets.map.config.OfflineMapConfig;
import com.ls.widgets.map.interfaces.Layer;
public class MapLayer
implements Layer, Callback
{
private long layerId;
private boolean isVisible;
private ArrayList<MapObject> drawables;
private ArrayList<MapObject> touchables;
protected MapWidget parent;
public MapLayer(long theLayerId, MapWidget parent)
{
drawables = new ArrayList<MapObject>();
touchables = new ArrayList<MapObject>();
//Visible by default
isVisible = true;
this.layerId = theLayerId;
this.parent = parent;
}
@Override
public void addMapObject(MapObject object)
{
if (object == null) {
throw new IllegalArgumentException();
}
if (Looper.myLooper() == null) {
throw new RuntimeException("addMapObject should be called from UI thread.");
}
object.setParent(this);
object.setScale(parent.getScale());
drawables.add(object);
if (object.isTouchable()) {
touchables.add(object);
}
parent.invalidate(object.getBounds());
}
@Override
public MapObject getMapObject(Object id)
{
if (id == null) {
throw new IllegalArgumentException();
}
// TODO: Re-factor this as this is extremely not efficient
for (MapObject drawable:drawables) {
if (drawable.getId().equals(id)) {
return drawable;
}
}
return null;
}
@Override
public MapObject getMapObjectByIndex(int index)
{
return drawables.get(index);
}
@Override
public int getMapObjectCount()
{
return drawables != null?drawables.size():0;
}
@Override
public void removeMapObject(Object id)
{
if (id == null) {
throw new IllegalArgumentException();
}
if (Looper.myLooper() == null) {
throw new RuntimeException("removeMapObject should be called from UI thread.");
}
MapObject objectToDelete = null;
for (MapObject mapObject:drawables) {
if (mapObject.getId().equals(id)) {
objectToDelete = mapObject;
break;
}
}
if (objectToDelete != null) {
drawables.remove(objectToDelete);
touchables.remove(objectToDelete);
Rect b = objectToDelete.getDrawable().getBounds();
parent.postInvalidate(b.left, b.top, b.right, b.bottom);
}
}
// public ArrayList<Object> getTouched(int normX, int normY)
// {
// ArrayList<Object> result = new ArrayList<Object>();
//
// for (MapObject touchable:touchables) {
// if (touchable.isTouched(normX, normY)) {
// result.add(touchable.getId());
// }
// }
//
// return result;
// }
//
/**
* Returns Ids of map object that were touched. Intended for internal use
* @param touchRect
* @return
*/
public ArrayList<Object> getTouched(Rect touchRect)
{
ArrayList<Object> result = new ArrayList<Object>();
for (MapObject touchable:touchables) {
if (touchable.isTouched(touchRect)) {
result.add(touchable.getId());
}
}
return result;
}
public boolean isVisible()
{
return isVisible;
}
public void setVisible(boolean visible)
{
isVisible = visible;
}
public void setScale(float scale)
{
int size = drawables.size();
for (int i=0; i < size; ++i) {
MapObject drawable = drawables.get(i);
drawable.setScale(scale);
}
}
public void draw(Canvas canvas, Rect drawingRect)
{
if (!isVisible)
return;
for (int i=0, size=drawables.size(); i<size; ++i) {
MapObject object = drawables.get(i);
if (Rect.intersects(object.getBounds(), drawingRect)) {
object.draw(canvas);
}
}
}
public void clearAll()
{
if (Looper.myLooper() == null) {
throw new RuntimeException("clearAll should be called from UI thread.");
}
drawables.clear();
touchables.clear();
drawables = null;
touchables = null;
drawables = new ArrayList<MapObject>();
touchables = new ArrayList<MapObject>();
}
public boolean equals(Object o)
{
if (o == null) {
return false;
}
if (!(o instanceof MapLayer)) {
return false;
}
MapLayer inMapLayer = (MapLayer) o;
return inMapLayer.layerId == this.layerId;
}
public int hashCode()
{
return (int)(layerId ^ (layerId >>> 32));
}
// Package access methods
OfflineMapConfig getConfig()
{
return parent.getConfig();
}
void invalidate(MapObject object)
{
Rect bounds = object.getBounds();
parent.postInvalidate(bounds.left, bounds.top, bounds.right, bounds.bottom);
}
public void scheduleDrawable(Drawable who, Runnable what, long when)
{
parent.scheduleDrawable(who, what, when);
}
public void unscheduleDrawable(Drawable who, Runnable what) {
parent.unscheduleDrawable(who, what);
}
public void invalidateDrawable(Drawable who) {
Rect bounds = who.getBounds();
parent.postInvalidate(bounds.left, bounds.top, bounds.right, bounds.bottom);
}
public long getId()
{
return layerId;
}
}