/* * Copyright (C) 2010 LluĂ­s Esquerda * * 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 net.homelinux.penecoptero.android.citybikes.app; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Queue; import net.homelinux.penecoptero.android.citybikes.utils.CircleHelper; import org.json.JSONArray; import org.json.JSONObject; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; import android.util.Log; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapView; public class StationsDBAdapter implements Runnable { public static final String CENTER_LAT_KEY = "sCenterLat"; public static final String CENTER_LNG_KEY = "sCenterLng"; public static final String RADIUS_KEY = "sRadius"; public static final String VIEW_ALL_KEY = "sViewAll"; public static final String PREF_NAME = "citybikes"; public static final int FETCH = 0; public static final int UPDATE_MAP = 1; public static final int UPDATE_MAP_LESS = 2; public static final int UPDATE_DATABASE = 3; public static final int NETWORK_ERROR = 4; public static final String TIMESTAMP_FORMAT = "HH:mm:ss dd/MM/yyyy"; private StationOverlayList stationsDisplayList; private List<StationOverlay> stationsMemoryMap; private RESTHelper mRESTHelper; private MapView mapView; private Context mCtx; private Handler handlerOut; private Bundle threadData; private Queue<Integer> toDo; private String RAWstations; private String last_updated; private long last_updated_time; private GeoPoint center; private boolean getBike = true; public StationsDBAdapter(Context ctx, MapView mapView, Handler handler, StationOverlayList stationsDisplayList) { this.mCtx = ctx; this.mapView = mapView; this.handlerOut = handler; this.stationsDisplayList = stationsDisplayList; this.mRESTHelper = new RESTHelper(false, null, null); this.toDo = new LinkedList(); } public StationsDBAdapter(Context ctx, Handler handler) { this.mRESTHelper = new RESTHelper(false, null, null); this.handlerOut = handler; this.toDo = new LinkedList(); this.mCtx = ctx; } public String fetchStations(String provider) throws Exception { return mRESTHelper.restGET(provider); } public String getLastUpdated() { return last_updated; } public Long getLastUpdatedTime(){ return last_updated_time; } public void setCenter(GeoPoint point) { this.center = point; } public void loadStations() throws Exception { this.retrieve(); if (this.center != null) buildMemory(new JSONArray(this.RAWstations), this.center); else buildMemory(new JSONArray(this.RAWstations)); } public void buildMemory(JSONArray stations) throws Exception { this.stationsMemoryMap = new LinkedList<StationOverlay>(); JSONObject station = null; int lat, lng, bikes, free, id; String timestamp, name; GeoPoint point; BookmarkManager bm = new BookmarkManager(mCtx); for (int i = 0; i < stations.length(); i++) { station = stations.getJSONObject(i); id = station.getInt("id"); name = station.getString("name"); lat = Integer.parseInt(station.getString("y")); lng = Integer.parseInt(station.getString("x")); bikes = station.getInt("bikes"); free = station.getInt("free"); timestamp = station.getString("timestamp"); point = new GeoPoint(lat, lng); Station stat = new Station(id, name, bikes, free, timestamp, mCtx, point); if (bm.isBookmarked(stat)) stat.setBookmarked(true); StationOverlay memoryStation = new StationOverlay(stat, getBike); stationsMemoryMap.add(memoryStation); } } public StationOverlay getStationFromAll( int id ){ Iterator<StationOverlay> i = stationsMemoryMap.iterator(); while(i.hasNext()){ StationOverlay st = i.next(); if (st.getStation().getId() == id) return st; } return null; } public List<StationOverlay> getMemory() throws Exception { return stationsMemoryMap; } public List<StationOverlay> getMemory(int radius) throws Exception { List<StationOverlay> res = new LinkedList<StationOverlay>(); StationOverlay tmp; Iterator<StationOverlay> i = stationsMemoryMap.iterator(); while (i.hasNext()) { tmp = i.next(); if ((tmp.getStation().getMetersDistance() + tmp.getStation().getMetersDistance() * 0.35) <= radius || tmp.getStation().isBookmarked() ) { res.add(tmp); } } return res; } public void updateDistances(GeoPoint center) { Iterator<StationOverlay> i = stationsMemoryMap.iterator(); while (i.hasNext()) { StationOverlay memoryStation = i.next(); memoryStation.getStation().setMetersDistance(CircleHelper.gp2m(center, memoryStation.getCenter())); memoryStation.getStation().populateStrings(); } } public void buildMemory(JSONArray stations, GeoPoint center) throws Exception { this.stationsMemoryMap = new LinkedList<StationOverlay>(); JSONObject station = null; int lat, lng, bikes, free, id; String timestamp, name; GeoPoint point; BookmarkManager bm = new BookmarkManager(mCtx); for (int i = 0; i < stations.length(); i++) { station = stations.getJSONObject(i); id = station.getInt("id"); name = station.getString("name"); lat = Integer.parseInt(station.getString("lat")); lng = Integer.parseInt(station.getString("lng")); bikes = station.getInt("bikes"); free = station.getInt("free"); timestamp = station.getString("timestamp"); point = new GeoPoint(lat, lng); Station stat = new Station(id, name, bikes, free, timestamp, mCtx, point); if (bm.isBookmarked(stat)) stat.setBookmarked(true); StationOverlay memoryStation = new StationOverlay(stat, getBike); memoryStation.getStation().setMetersDistance(CircleHelper.gp2m(center, point)); memoryStation.getStation().populateStrings(); stationsMemoryMap.add(memoryStation); } Collections.sort(stationsMemoryMap, new Comparator() { public int compare(Object o1, Object o2) { if (o1 instanceof StationOverlay && o2 instanceof StationOverlay) { StationOverlay stat1 = (StationOverlay) o1; StationOverlay stat2 = (StationOverlay) o2; if (stat1.getStation().getMetersDistance() > stat2.getStation().getMetersDistance()) return 1; else return -1; } else { if (o1 instanceof HomeOverlay) { return 1; } else if (o2 instanceof HomeOverlay) { return -1; } else { return 0; } } } }); } public void reorder() { Collections.sort(stationsMemoryMap, new Comparator() { public int compare(Object o1, Object o2) { if (o1 instanceof StationOverlay && o2 instanceof StationOverlay) { StationOverlay stat1 = (StationOverlay) o1; StationOverlay stat2 = (StationOverlay) o2; if (stat1.getStation().getMetersDistance() > stat2.getStation().getMetersDistance()) return 1; else return -1; } else { if (o1 instanceof HomeOverlay) { return 1; } else if (o2 instanceof HomeOverlay) { return -1; } else { return 0; } } } }); } public void store() { SharedPreferences settings = this.mCtx.getSharedPreferences(PREF_NAME, 0); SharedPreferences.Editor editor = settings.edit(); editor.putString("stations", this.RAWstations); editor.putString("last_updated", this.last_updated); editor.putLong("last_updated_time",this.last_updated_time); editor.commit(); } public void retrieve() throws Exception { SharedPreferences settings = this.mCtx.getSharedPreferences(PREF_NAME, 0); RAWstations = settings.getString("stations", "[]"); last_updated = settings.getString("last_updated", null); last_updated_time = settings.getLong("last_updated_time", 0); String network_url = settings.getString("network_url", ""); } public void sync(boolean all, Bundle data) throws Exception { this.threadData = data; toDo.add(FETCH); if (all) toDo.add(UPDATE_MAP); else toDo.add(UPDATE_MAP_LESS); toDo.add(UPDATE_DATABASE); Thread awesomeThread = new Thread(this); awesomeThread.start(); } public void populateStations() throws Exception { stationsDisplayList.clearStationOverlays(); Iterator<StationOverlay> i = stationsMemoryMap.iterator(); while (i.hasNext()) { stationsDisplayList.addStationOverlay(i.next()); } mapView.postInvalidate(); } public void populateStations(GeoPoint center, int radius) throws Exception { stationsDisplayList.clearStationOverlays(); Iterator<StationOverlay> i = stationsMemoryMap.iterator(); this.reorder(); StationOverlay tmp; while (i.hasNext()) { tmp = i.next(); if ((tmp.getStation().getMetersDistance() + tmp.getStation().getMetersDistance() * 0.35) <= radius || tmp.getStation().isBookmarked() ) { stationsDisplayList.addStationOverlay(tmp); } } mapView.postInvalidate(); } public void changeMode (boolean getBike){ this.getBike = getBike; Iterator i = stationsMemoryMap.iterator(); while (i.hasNext()){ Object tmp = i.next(); if ( tmp instanceof StationOverlay){ StationOverlay st = (StationOverlay) tmp; st.updateStatus(getBike); } } } @Override public void run() { while (!toDo.isEmpty()) { Integer action = toDo.poll(); switch (action) { case FETCH: try { SharedPreferences settings = this.mCtx.getSharedPreferences(PREF_NAME,0); String network_url = settings.getString("network_url",""); RAWstations = fetchStations(network_url); SimpleDateFormat sdf = new SimpleDateFormat( TIMESTAMP_FORMAT); Calendar cal = Calendar.getInstance(); last_updated = sdf.format(cal.getTime()); last_updated_time = cal.getTime().getTime(); buildMemory(new JSONArray(RAWstations), this.center); } catch (Exception fetchError) { handlerOut.sendEmptyMessage(NETWORK_ERROR); fetchError.printStackTrace(); try { retrieve(); buildMemory(new JSONArray(RAWstations), this.center); } catch (Exception internalError) { // FUCK EVERYTHING! } } handlerOut.sendEmptyMessage(FETCH); break; case UPDATE_MAP: try { populateStations(); } catch (Exception populateError) { } handlerOut.sendEmptyMessage(UPDATE_MAP); break; case UPDATE_MAP_LESS: try { GeoPoint center = new GeoPoint(threadData .getInt(CENTER_LAT_KEY), threadData .getInt(CENTER_LNG_KEY)); populateStations(center, threadData.getInt(RADIUS_KEY)); } catch (Exception populateError) { } handlerOut.sendEmptyMessage(UPDATE_MAP); break; case UPDATE_DATABASE: store(); handlerOut.sendEmptyMessage(UPDATE_DATABASE); break; } } } }