/*******************************************************************************
* Copyright (c) 2014 Open Door Logistics (www.opendoorlogistics.com)
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v3
* which accompanies this distribution, and is available at http://www.gnu.org/licenses/lgpl.txt
******************************************************************************/
package com.opendoorlogistics.studio.components.geocoder.model;
import gnu.trove.map.hash.TLongObjectHashMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.TreeSet;
import com.opendoorlogistics.api.geometry.LatLong;
import com.opendoorlogistics.api.tables.ODLColumnType;
import com.opendoorlogistics.api.tables.ODLDatastore;
import com.opendoorlogistics.api.tables.ODLDatastoreAlterable;
import com.opendoorlogistics.api.tables.ODLTable;
import com.opendoorlogistics.api.tables.ODLTableAlterable;
import com.opendoorlogistics.api.tables.ODLTableDefinition;
import com.opendoorlogistics.api.tables.ODLTableDefinitionAlterable;
import com.opendoorlogistics.api.tables.ODLTableReadOnly;
import com.opendoorlogistics.core.tables.memory.ODLDatastoreImpl;
final public class GeocodeModel {
private final ODLDatastore<? extends ODLTable> ds;
private final TLongObjectHashMap<String> addressByRowId = new TLongObjectHashMap<>();
private int row = -1;
private List<SearchResultPoint> searchResults;
private TreeSet<Integer> selectedResultIndices;
private HashSet<GeocodeModelListener> listeners = new HashSet<>();
public static final int LAT_COL = 1;
public static final int LNG_COL = 2;
public GeocodeModel(ODLDatastore<? extends ODLTable> ds) {
this.ds = ds;
}
public void addListener(GeocodeModelListener listener) {
listeners.add(listener);
}
public void fireListeners(boolean recordChanged, boolean searchResultsChanged) {
for (GeocodeModelListener listener : listeners) {
listener.modelChanged(recordChanged, searchResultsChanged);
}
}
private ODLTable table() {
return ds.getTableAt(0);
}
public Double getLatitude() {
Double ret = (Double) getValueAt(LAT_COL);
if (ret != null) {
return ret;
}
return null;
}
public Double getLongitude() {
Double ret = (Double) getValueAt(LNG_COL);
if (ret != null) {
return ret;
}
return null;
}
public String getAddress() {
ODLTableReadOnly table = ds.getTableAt(0);
if (table != null && row >= 0 && row < table.getRowCount()) {
// take from the cache of addresses if present as we may have modified it
// but don't want to modify in the actual datastore
long rowId = table.getRowId(row);
String address = addressByRowId.get(rowId);
if (address != null) {
return address;
} else {
address = cacheAddressValue(table, rowId);
}
}
return "";
}
private String cacheAddressValue(ODLTableReadOnly table, long rowId) {
Object val = table.getValueAt(row, 0);
String ret= val != null ? val.toString() : "";
addressByRowId.put(rowId, ret);
return ret;
}
public void resetAddress(){
ODLTableReadOnly table = ds.getTableAt(0);
if (table != null && row >= 0 && row < table.getRowCount()) {
// reset the cached value with the datastore value
long rowId = table.getRowId(row);
cacheAddressValue(table,rowId);
fireListeners(true, true);
}
}
public boolean hasPoint() {
ODLTable table = ds.getTableAt(0);
return table != null && row >= 0 && row < table.getRowCount();
}
private Object getValueAt(int col) {
ODLTableReadOnly table = ds.getTableAt(0);
if (table != null && row >= 0 && row < table.getRowCount()) {
return table.getValueAt(row, col);
}
return null;
}
private void setValueAt(Object val, int col) {
ODLTable table = ds.getTableAt(0);
if (table != null && row >= 0 && row < table.getRowCount()) {
table.setValueAt(val, row, col);
fireListeners(false, false);
}
}
public void setAddress(String s) {
ODLTableReadOnly table = ds.getTableAt(0);
if (table != null && row >= 0 && row < table.getRowCount()) {
long rowId = table.getRowId(row);
// save locally, not to the datastore
addressByRowId.put(rowId, s);
}
}
public void setGeocode(LatLong ll) {
setGeocode(ll.getLatitude(), ll.getLongitude());
}
public void setGeocode(Double latitude, Double longitude) {
setValueAt(latitude, LAT_COL);
setValueAt(longitude, LNG_COL);
}
public void gotoNextRecord() {
if (!hasNextRecord()) {
throw new IndexOutOfBoundsException();
}
row++;
clearResultsOnRecordChange();
}
private void clearResultsOnRecordChange() {
searchResults = new ArrayList<>();
selectedResultIndices = new TreeSet<>();
fireListeners(true, true);
}
public void gotoPreviousRecord() {
if (!hasPreviousRecord()) {
throw new IndexOutOfBoundsException();
}
row--;
clearResultsOnRecordChange();
}
public boolean hasNextRecord() {
ODLTable table = table();
return table != null && row < table.getRowCount() - 1;
}
// private int nextRow(){
// ODLTable table = table();
// if(table!=null && row < table.getRowCount()-1){
// if(skipAlreadyGeocoded==false){
// return row+1;
// }
//
// for(int i =row+1 ; i<table.getRowCount() ; i++){
// if(table.getValueAt(i, LAT_COL)==null || table.getValueAt(i, LNG_COL)==null){
// return i;
// }
// }
// }
// return -1;
// }
public boolean hasPreviousRecord() {
return table() != null && row > 0;
}
public void setSearchResults(List<SearchResultPoint> list) {
if (list != null) {
searchResults = Collections.unmodifiableList(list);
} else {
searchResults = null;
}
fireListeners(false, true);
}
public List<SearchResultPoint> getSearchResults() {
return searchResults;
}
public Iterable<Integer> getSelectedResultIndices() {
return selectedResultIndices;
}
public int getSelectedResultsCount() {
return selectedResultIndices.size();
}
public void setSelectedResultIndices(Iterable<Integer> selectedResultIndices) {
this.selectedResultIndices.clear();
for (int i : selectedResultIndices) {
this.selectedResultIndices.add(i);
}
fireListeners(false, false);
}
public int getRowCount() {
ODLTable table = table();
if (table != null) {
return table.getRowCount();
}
return 0;
}
public int getRow() {
return row;
}
public static ODLDatastore<? extends ODLTableDefinition> getDsDefn() {
ODLDatastoreAlterable<ODLTableAlterable> ret = createEmptyDs();
return ret;
}
public static ODLDatastoreAlterable<ODLTableAlterable> createEmptyDs() {
ODLDatastoreAlterable<ODLTableAlterable> ret = ODLDatastoreImpl.alterableFactory.create();
ODLTableDefinitionAlterable table = ret.createTable("Points", -1);
table.addColumn(-1, "Address", ODLColumnType.STRING, 0);
table.addColumn(-1, "Latitude", ODLColumnType.DOUBLE, 0);
table.addColumn(-1, "Longitude", ODLColumnType.DOUBLE, 0);
return ret;
}
}