package ch.wootbarrel.coinmapp.db; import android.app.ProgressDialog; import android.content.ContentValues; import android.content.Context; import android.content.SharedPreferences; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.os.Handler; import android.os.Looper; import android.widget.Toast; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.lang.reflect.Type; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.List; import ch.wootbarrel.coinmapp.MapEntry; /** * Created by n3utrino on 20.12.13. * <p/> * datasource to the map entities */ public class CoinmapDataSource { public static final String LAST_UPDATE = "last_update"; public static final String DB_PREFS = "dbPrefs"; private static String[] allColumns = {CoinmapDbHelper.COLUMN_ID, CoinmapDbHelper.COLUMN_CITY, CoinmapDbHelper.COLUMN_ADDR, CoinmapDbHelper.COLUMN_PHONE, CoinmapDbHelper.COLUMN_TITLE, CoinmapDbHelper.COLUMN_LON, CoinmapDbHelper.COLUMN_LAT, CoinmapDbHelper.COLUMN_WEB, CoinmapDbHelper.COLUMN_ICON, CoinmapDbHelper.COLUMN_OSM_ID}; private final SharedPreferences prefs; private final ProgressDialog progressDialog; private SQLiteDatabase database; private CoinmapDbHelper helper; private Gson gson = new Gson(); public CoinmapDataSource(Context ctx, ProgressDialog progressDialog) { this.progressDialog = progressDialog; helper = new CoinmapDbHelper(ctx); prefs = ctx.getSharedPreferences(DB_PREFS, Context.MODE_PRIVATE); open(); if (isUpdateDue()) { initializeDb(ctx); } close(); } private boolean isUpdateDue() { long last = prefs.getLong(LAST_UPDATE, 0); return System.currentTimeMillis() - last > 1000 * 60 * 60 * 24; // Update every 24H } private void initializeDb(final Context ctx) { final Handler toastHandler = new Handler(Looper.getMainLooper()); //Initial Import Show Progress bar if (getAllEntries().size() == 0) { toastHandler.post(new Runnable() { @Override public void run() { progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setIndeterminate(true); progressDialog.setCancelable(false); progressDialog.show(); } }); fetchAndParseData(ctx, toastHandler); } else { new Thread() { @Override public void run() { fetchAndParseData(ctx, toastHandler); } }.start(); } } private void updateProgressDialog(final String message) { final Handler toastHandler = new Handler(Looper.getMainLooper()); toastHandler.post(new Runnable() { @Override public void run() { progressDialog.setMessage(message); } }); } private void setProgressMax(final int progressMax) { final Handler toastHandler = new Handler(Looper.getMainLooper()); toastHandler.post(new Runnable() { @Override public void run() { progressDialog.setIndeterminate(false); progressDialog.setMax(progressMax); } }); } private void setProgress(final int progress) { final Handler toastHandler = new Handler(Looper.getMainLooper()); toastHandler.post(new Runnable() { @Override public void run() { progressDialog.setProgress(progress); } }); } private void fetchAndParseData(final Context ctx, Handler toastHandler) { StringBuilder builder = new StringBuilder(); BufferedReader is; try { updateProgressDialog("Fetching Data"); URL dataUrl = new URL("http://coinmap.org/data/data-overpass-bitcoin.json"); URLConnection connection = dataUrl.openConnection(); connection.addRequestProperty("User-Agent", "CoinmApp;1.0;Android"); is = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8")); final int lastSize = getAllEntries().size(); String line; try { while (null != (line = is.readLine())) { builder.append(line); } } catch (IOException e) { e.printStackTrace(); } Type collectionType = new TypeToken<List<MapEntry>>() { }.getType(); updateProgressDialog("Parsing JSON"); List<MapEntry> mapEntries = gson.fromJson(builder.toString(), collectionType); this.clearData(); updateProgressDialog("Inserting Entries"); setProgressMax(mapEntries.size()); int i = 1; this.database.beginTransaction(); for (MapEntry entry : mapEntries) { this.insertMapEntry(entry); setProgress(i); i++; } this.database.setTransactionSuccessful(); final int newSize = (getAllEntries().size() - lastSize); prefs.edit().putLong(LAST_UPDATE, System.currentTimeMillis()).commit(); toastHandler.post(new Runnable() { @Override public void run() { Toast.makeText(ctx, "Updating Data. Success - " + newSize + " new shops", Toast.LENGTH_LONG).show(); } }); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { toastHandler.post(new Runnable() { @Override public void run() { Toast.makeText(ctx, "Updating Data. Failed - maybe no connection", Toast.LENGTH_LONG).show(); } }); e.printStackTrace(); } finally { database.endTransaction(); } } private void clearData() { database.delete(CoinmapDbHelper.TABLE_MAP_ENTRIES, null, null); } public void open() throws SQLException { database = helper.getWritableDatabase(); } public void close() { helper.close(); } public void deleteMapEntry(MapEntry mapEntry) { long id = mapEntry.id; System.out.println("Comment deleted with id: " + id); database.delete(CoinmapDbHelper.TABLE_MAP_ENTRIES, CoinmapDbHelper.COLUMN_ID + " = " + id, null); } public long insertMapEntry(MapEntry mapEntry) { ContentValues values = new ContentValues(); values.put(CoinmapDbHelper.COLUMN_ADDR, mapEntry.addr); values.put(CoinmapDbHelper.COLUMN_CITY, mapEntry.city); values.put(CoinmapDbHelper.COLUMN_ICON, mapEntry.icon); values.put(CoinmapDbHelper.COLUMN_PHONE, mapEntry.phone); values.put(CoinmapDbHelper.COLUMN_TITLE, mapEntry.title); values.put(CoinmapDbHelper.COLUMN_LAT, mapEntry.lat); values.put(CoinmapDbHelper.COLUMN_LON, mapEntry.lon); return database.insert(CoinmapDbHelper.TABLE_MAP_ENTRIES, null, values); } public String topCategory() { Cursor cursor = database.rawQuery("select icon, count(*) as cnt from " + CoinmapDbHelper.TABLE_MAP_ENTRIES + " where icon <> 'bitcoin' group by icon order by cnt desc", null); if (cursor.moveToFirst()) { String icon = cursor.getString(0); int count = cursor.getInt(1); return count + " " + icon; } return ""; } public List<MapEntry> getAllEntries() { List<MapEntry> entries = new ArrayList<MapEntry>(); Cursor cursor = database.query(CoinmapDbHelper.TABLE_MAP_ENTRIES, allColumns, null, null, null, null, null); cursor.moveToFirst(); while (!cursor.isAfterLast()) { MapEntry comment = cursorToEntry(cursor); entries.add(comment); cursor.moveToNext(); } // make sure to close the cursor cursor.close(); return entries; } private MapEntry cursorToEntry(Cursor cursor) { MapEntry entry = new MapEntry(); entry.id = cursor.getLong(0); entry.city = cursor.getString(1); entry.addr = cursor.getString(2); entry.phone = cursor.getString(3); entry.title = cursor.getString(4); entry.lon = Double.parseDouble(cursor.getString(5)); entry.lat = Double.parseDouble(cursor.getString(6)); entry.web = cursor.getString(7); entry.icon = cursor.getString(8); return entry; } }