Bimba.git

commit 6bc508f90816a4ea86f925dc168f2d6a4be1256c

Author: Adam Pioterek <adam.pioterek@protonmail.ch>

favourites

%!v(PANIC=String method: strings: negative Repeat count)


diff --git a/.idea/misc.xml b/.idea/misc.xml
index 635999df1e86791ad3787e455b4524e4d8879b93..ba7052b8197ddf8ba8756022d905d03055c7ad60 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -24,7 +24,7 @@         
       </value>
     </option>
   </component>
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
     <output url="file://$PROJECT_DIR$/build/classes" />
   </component>
   <component name="ProjectType">




diff --git a/app/build.gradle b/app/build.gradle
index ddb34020f421af5d25578b83df9a2e7b365efb62..32d9dd851397095766b302faa0bacf997d79bdc8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,5 +1,6 @@
 apply plugin: 'com.android.application'
 apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
 
 android {
     compileSdkVersion 27
@@ -30,21 +31,17 @@     implementation 'com.android.support:appcompat-v7:27.1.0'
     implementation 'com.android.support:cardview-v7:27.1.0'
     implementation 'com.android.support:design:27.1.0'
     implementation 'com.android.support:support-vector-drawable:27.1.0'
-    testImplementation 'junit:junit:4.12'
     implementation 'com.android.support.constraint:constraint-layout:1.0.2'
     implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
     implementation 'com.github.arimorty:floatingsearchview:2.1.1'
     implementation 'com.google.code.gson:gson:2.8.1'
     implementation 'com.squareup.okhttp3:okhttp:3.8.1'
     implementation 'com.github.ghost1372:Mzip-Android:0.4.0'
-    implementation 'com.univocity:univocity-parsers:2.5.9'
-    implementation 'net.sf.supercsv:super-csv:2.4.0'
     implementation 'io.requery:sqlite-android:3.22.0'
+    testImplementation 'junit:junit:4.12'
 }
 repositories {
     maven { url "https://maven.google.com" }
     maven { url 'https://jitpack.io' }
     mavenCentral()
 }
-
-apply plugin: 'kotlin-android-extensions'




diff --git a/app/src/main/java/ml/adamsprogs/bimba/activities/DashActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/activities/DashActivity.kt
index b468c5c6a00ffbb89e7324e729f38ec0ffb1ac7b..af04bc1b7093bbfe79b6cc8dc371bffa983ef5c6 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/DashActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/DashActivity.kt
@@ -1,36 +1,29 @@
 package ml.adamsprogs.bimba.activities
 
 import android.annotation.SuppressLint
+import android.app.Activity
 import android.content.*
 import android.os.*
-import android.support.design.widget.Snackbar
-import android.support.v7.app.*
-import android.text.Html
-import com.arlib.floatingsearchview.FloatingSearchView
-import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
-import ml.adamsprogs.bimba.models.*
-import kotlin.concurrent.thread
-import android.app.Activity
-import android.support.design.widget.NavigationView
+import android.support.design.widget.*
 import android.support.v4.widget.*
 import android.support.v7.widget.*
+import android.support.v7.app.*
+import android.text.Html
 import android.view.*
 import android.view.inputmethod.InputMethodManager
-import ml.adamsprogs.bimba.*
-import android.os.Bundle
-import android.util.Log
+import kotlin.concurrent.thread
+import kotlin.collections.ArrayList
 import kotlinx.android.synthetic.main.activity_dash.*
-import ml.adamsprogs.bimba.datasources.TimetableDownloader
-import ml.adamsprogs.bimba.datasources.VmClient
-import ml.adamsprogs.bimba.models.suggestions.GtfsSuggestion
-import ml.adamsprogs.bimba.models.suggestions.LineSuggestion
-import ml.adamsprogs.bimba.models.suggestions.StopSuggestion
-import android.support.v7.widget.DefaultItemAnimator
-import android.content.Intent
 import java.util.*
-import kotlin.collections.ArrayList
 
-//todo cards https://enoent.fr/blog/2015/01/18/recyclerview-basics/
+import ml.adamsprogs.bimba.models.*
+import ml.adamsprogs.bimba.*
+import ml.adamsprogs.bimba.datasources.*
+import ml.adamsprogs.bimba.models.suggestions.*
+
+import com.arlib.floatingsearchview.FloatingSearchView
+import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion
+
 //todo searchView integration
 class DashActivity : AppCompatActivity(), MessageReceiver.OnTimetableDownloadListener,
         FavouritesAdapter.OnMenuItemClickListener, Favourite.OnVmPreparedListener,
@@ -194,8 +187,8 @@         }
     }
 
     private fun notifyTimetableValidity(daysTillInvalid: Int) {
-        val message = when(daysTillInvalid) {
-            -1 -> getString (R.string.timetable_validity_finished)
+        val message = when (daysTillInvalid) {
+            -1 -> getString(R.string.timetable_validity_finished)
             0 -> getString(R.string.timetable_validity_today)
             1 -> getString(R.string.timetable_validity_tomorrow)
             else -> return
@@ -210,6 +203,9 @@     }
 
     private fun prepareFavourites() {
         favourites = FavouriteStorage.getFavouriteStorage(context)
+        favourites.forEach {
+            it.addOnVmPreparedListener(this)
+        }
         val layoutManager = LinearLayoutManager(context)
         favouritesList = favourites_list
         adapter = FavouritesAdapter(context, favourites, this, this)
@@ -219,12 +215,11 @@         favouritesList.layoutManager = layoutManager
     }
 
     override fun onVmPrepared() {
-        Log.i("VM", "DataSetChange")
         favouritesList.adapter.notifyDataSetChanged()
     }
 
     private fun getSuggestions() {
-        suggestions = (timetable.getStopSuggestions(context) + timetable.getLineSuggestions()).sorted() //todo<p:v+1> + bike stations, &c
+        suggestions = (timetable.getStopSuggestions(context) + timetable.getLineSuggestions()).sorted() //todo<p:v+1> + bike stations, train stations, &c
     }
 
     private fun prepareListeners() {
@@ -263,7 +258,7 @@         favourites.deregisterOnVm(receiver, context)
         unregisterReceiver(receiver)
     }
 
-    fun deAccent(str: String): String {
+    private fun deAccent(str: String): String {
         var result = str.replace('ę', 'e')
         result = result.replace('ó', 'o')
         result = result.replace('ą', 'a')
@@ -304,7 +299,7 @@     }
 
     override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
         if (requestCode == REQUEST_EDIT_FAVOURITE) {
-            if (resultCode == Activity.RESULT_OK) {
+            if (resultCode == Activity.RESULT_OK) { // todo change favourite content (shown) immediately
                 val name = data.getStringExtra(EditFavouriteActivity.EXTRA_NEW_NAME)
                 val positionBefore = data.getIntExtra(EditFavouriteActivity.EXTRA_POSITION_BEFORE, -1)
                 //adapter.favourites = favourites.favouritesList
@@ -335,9 +330,12 @@
     override fun onItemClicked(position: Int) {
         if (actionMode != null) {
             toggleSelection(position)
+        } else {
+            val intent = Intent(context, StopActivity::class.java)
+            intent.putExtra(StopActivity.SOURCE_TYPE, StopActivity.SOURCE_TYPE_FAV)
+            intent.putExtra(StopActivity.EXTRA_FAVOURITE, favourites[position])
+            startActivity(intent)
         }
-
-        //todo else -> StopActivity
     }
 
     override fun onItemLongClicked(position: Int): Boolean {




diff --git a/app/src/main/java/ml/adamsprogs/bimba/datasources/TimetableDownloader.kt b/app/src/main/java/ml/adamsprogs/bimba/datasources/TimetableDownloader.kt
index 012c1a1a943fcd85a366c4d3cf6538c91bfaa6d2..cad776b9fd5704eaa69c0979307298bacd3f6942 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/datasources/TimetableDownloader.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/datasources/TimetableDownloader.kt
@@ -12,8 +12,6 @@ import android.os.Build
 import com.google.gson.Gson
 import com.google.gson.JsonArray
 import com.google.gson.JsonObject
-import com.univocity.parsers.csv.CsvParser
-import com.univocity.parsers.csv.CsvParserSettings
 import ir.mahdi.mzip.zip.ZipArchive
 import ml.adamsprogs.bimba.NetworkStateReceiver
 import ml.adamsprogs.bimba.NotificationChannels
@@ -122,7 +120,7 @@         }
     }
 
     private fun createIndices() {
-        val settings = CsvParserSettings()
+        /*val settings = CsvParserSettings()
         settings.format.setLineSeparator("\r\n")
         settings.format.quote = '"'
         settings.isHeaderExtractionEnabled = true
@@ -161,6 +159,7 @@         println(Calendar.getInstance().timeInMillis)
 
         serialiseIndex(stopsIndex, stopIndexFile)
         serialiseIndex(tripsIndex, tripIndexFile)
+        */
     }
 
     private fun serialiseIndex(index: HashMap<String, List<Long>>, file: File) {




diff --git a/app/src/main/java/ml/adamsprogs/bimba/datasources/VmClient.kt b/app/src/main/java/ml/adamsprogs/bimba/datasources/VmClient.kt
index 2cd8d9151394dc88ddc6fa01411f15edf001a85f..0c1acdd386bc2ab37ca55ab20d16371c1b5a5cc8 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/datasources/VmClient.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/datasources/VmClient.kt
@@ -37,7 +37,7 @@                 downloadVM()
         }
     }
     private val requests = HashMap<AgencyAndId, Set<Request>>()
-    private val vms = HashMap<AgencyAndId, HashSet<Plate>>() //HashSet<Departure>?
+    private val vms = HashMap<AgencyAndId, Set<Plate>>() //HashSet<Departure>?
     private val timetable = try {
         Timetable.getTimetable(this)
     } catch (e: NullPointerException) {
@@ -154,7 +154,7 @@     }
 
     private fun downloadVM(stopSegment: StopSegment) {
         if (!NetworkStateReceiver.isNetworkAvailable(this)) {
-            vms[stopSegment.stop] = stopSegment.plates!!.map { Plate(it, null) }.toSet() as HashSet<Plate>
+            vms[stopSegment.stop] = HashSet(stopSegment.plates!!.map { Plate(it, null) }.toSet())
             stopSegment.plates!!.forEach {
                 sendResult(it, null)
             }
@@ -221,10 +221,10 @@         val departuresForPlate = HashMap>()
         departuresForPlate[timetable.getServiceForToday()] = departures
         val vm = vms[plateId.stop] ?: HashSet()
         try {
-            vm.remove(vm.filter { it.id == plateId }[0])
+            (vm as HashSet).remove(vm.filter { it.id == plateId }[0])
         } catch (e: IndexOutOfBoundsException) {
         }
-        vm.add(Plate(plateId, departuresForPlate))
+        (vm as HashSet).add(Plate(plateId, departuresForPlate))
         vms[plateId.stop] = vm
         if (departures.isEmpty())
             sendResult(plateId, null)




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/Favourite.kt b/app/src/main/java/ml/adamsprogs/bimba/models/Favourite.kt
index 1381ac50abf19a581df0055d375aaeeb96ee03de..ddb83ca5ab2770ba195ebd500488fa3badb5f9eb 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/Favourite.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/Favourite.kt
@@ -16,13 +16,13 @@ class Favourite : Parcelable, MessageReceiver.OnVmListener {
     private var isRegisteredOnVmListener: Boolean = false
     var name: String
         private set
-    var timetables: HashSet<StopSegment>
+    var segments: HashSet<StopSegment>
         private set
-    private var vmDepartures = HashMap<Plate.ID, Set<Departure>>()
+    private var vmDepartures = HashMap<Plate.ID, List<Departure>>()
     val timetable = Timetable.getTimetable()
 
     val size
-        get() = timetables.sumBy {
+        get() = segments.sumBy {
             it.size
         }
 
@@ -44,12 +44,12 @@         val array = parcel.readParcelableArray(StopSegment::class.java.classLoader)
         array.forEach {
             set.add(it as StopSegment)
         }
-        this.timetables = set
+        this.segments = set
     }
 
     constructor(name: String, timetables: HashSet<StopSegment>) {
         this.name = name
-        this.timetables = timetables
+        this.segments = timetables
 
     }
 
@@ -59,20 +59,20 @@     }
 
     override fun writeToParcel(dest: Parcel?, flags: Int) {
         dest?.writeString(name)
-        val parcelableSegments = timetables.map { it }.toTypedArray()
+        val parcelableSegments = segments.map { it }.toTypedArray()
         dest?.writeParcelableArray(parcelableSegments, flags)
     }
 
     private fun filterVmDepartures() {
         this.vmDepartures.forEach {
-            val newSet = it.value
-                    .filter { it.timeTill(true) >= 0 }.toSet()
-            this.vmDepartures[it.key] = newSet
+            val newVms = it.value
+                    .filter { it.timeTill(true) >= 0 }.sortedBy { it.timeTill() }
+            this.vmDepartures[it.key] = newVms
         }
     }
 
     fun delete(plateId: Plate.ID) {
-        timetables.forEach {
+        segments.forEach {
             it.remove(plateId)
         }
     }
@@ -83,7 +83,7 @@             receiver.addOnVmListener(this)
             isRegisteredOnVmListener = true
 
 
-            timetables.forEach {
+            segments.forEach {
                 val intent = Intent(context, VmClient::class.java)
                 intent.putExtra("stop", it)
                 intent.action = "request"
@@ -97,7 +97,7 @@         if (isRegisteredOnVmListener) {
             receiver.removeOnVmListener(this)
             isRegisteredOnVmListener = false
 
-            timetables.forEach {
+            segments.forEach {
                 val intent = Intent(context, VmClient::class.java)
                 intent.putExtra("stop", it)
                 intent.action = "remove"
@@ -122,7 +122,7 @@     }
 
     fun nextDeparture(): Departure? {
         filterVmDepartures()
-        if (timetables.isEmpty() && vmDepartures.isEmpty())
+        if (segments.isEmpty() && vmDepartures.isEmpty())
             return null
 
         if (vmDepartures.isNotEmpty()) {
@@ -142,7 +142,7 @@                 .filter { it.timeTill(true) >= 0 }
                 .minBy { it.timeTill(true) }
     }
 
-    private fun nowDepartures(): ArrayList<Departure> {
+    private fun nowDepartures(): List<Departure> {
         val today = timetable.getServiceForToday()
         val tomorrowCal = Calendar.getInstance()
         tomorrowCal.add(Calendar.DAY_OF_MONTH, 1)
@@ -154,18 +154,14 @@         }
 
         val departures = fullTimetable()
 
-        println(departures.keys.joinToString(","))
         val todayDepartures = departures[today]!!
-        val tomorrowDepartures = ArrayList<Departure>()
-        val twoDayDepartures = ArrayList<Departure>()
+        val tomorrowDepartures = ArrayList<Departure>() /** todo as in {@link Departure.rollDeparture rollDeparture} **/
         if (tomorrow != -1) {
             departures[tomorrow]!!.mapTo(tomorrowDepartures) { it.copy() }
             tomorrowDepartures.forEach { it.tomorrow = true }
         }
 
-        todayDepartures.forEach { twoDayDepartures.add(it) }
-        tomorrowDepartures.forEach { twoDayDepartures.add(it) }
-        return twoDayDepartures
+        return todayDepartures + tomorrowDepartures
     }
 
     fun allDepartures(): Map<AgencyAndId, List<Departure>> {
@@ -180,27 +176,20 @@         val departures = fullTimetable()
         return Departure.rollDepartures(departures)
     }
 
-    fun fullTimetable(): Map<AgencyAndId, List<Departure>> {
-        val departureSet = HashSet<Map<AgencyAndId, List<Departure>>>()
-        timetables.forEach { departureSet.add(timetable.getStopDeparturesBySegment(it)) }
-        val departures = HashMap<AgencyAndId, List<Departure>>()
-        departureSet.forEach {
-            val map = it
-            it.keys.forEach {
-                departures[it] = (departures[it] ?: ArrayList()) + (map[it] ?: ArrayList())
-            }
-        }
-        return departures
-    }
+    fun fullTimetable() = timetable.getStopDeparturesBySegments(segments)
 
     override fun onVm(vmDepartures: Set<Departure>?, plateId: Plate.ID) {
-        if (timetables.any { it.contains(plateId) }) {
+        if (segments.any { it.contains(plateId) }) {
             if (vmDepartures == null)
                 this.vmDepartures.remove(plateId)
             else
-                this.vmDepartures[plateId] = vmDepartures
+                this.vmDepartures[plateId] = vmDepartures.sortedBy { it.timeTill() }
         }
         filterVmDepartures()
+        //todo<p:1> think about tick
+        onVmPreparedListeners.forEach {
+            it.onVmPrepared()
+        }
     }
 
     interface OnVmPreparedListener {




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/FavouriteEditRowAdapter.kt b/app/src/main/java/ml/adamsprogs/bimba/models/FavouriteEditRowAdapter.kt
index d05a401a423698f043129f70e99908351a55a3b5..7e78913947deebee44524e88984d9e3d0b71f4bc 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/FavouriteEditRowAdapter.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/FavouriteEditRowAdapter.kt
@@ -17,9 +17,9 @@
     override fun onBindViewHolder(holder: ViewHolder, position: Int) {
         val timetable = Timetable.getTimetable()
         val favourites = FavouriteStorage.getFavouriteStorage()
-        val id = favourite.timetables.flatMap { it.plates!! }.sortedBy { "${it.line}${it.stop}"}[position]
+        val id = favourite.segments.flatMap { it.plates!! }.sortedBy { "${it.line}${it.stop}"}[position]
         val plate = Plate(id,null)
-        val favouriteElement = "${timetable.getStopName(plate.id.stop)} ( ${timetable.getStopCode(plate.id.stop)}):\n${timetable.getLineNumber(plate.id.line)} → ${plate.id.headsign}"
+        val favouriteElement = "${timetable.getStopName(plate.id.stop)} ( ${timetable.getStopCode(plate.id.stop)}):\n${plate.id.line} → ${plate.id.headsign}"
         holder.rowTextView.text = favouriteElement
 //        holder?.splitButton?.setOnClickListener {
 //            favourites.detach(favourite.name, id, favouriteElement)




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/FavouriteStorage.kt b/app/src/main/java/ml/adamsprogs/bimba/models/FavouriteStorage.kt
index 0dbb60de3e15c7f9188a53bbc9f41de42ea939db..dd8b3a8b0b317c5234e6a68f30999ca0fbe39985 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/FavouriteStorage.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/FavouriteStorage.kt
@@ -80,7 +80,7 @@     private fun serialize() {
         val rootObject = JsonObject()
         for ((name, favourite) in favourites) {
             val timetables = JsonArray()
-            for (timetable in favourite.timetables) {
+            for (timetable in favourite.segments) {
                 val segment = JsonObject()
                 segment.addProperty("stop", timetable.stop.id)
                 val plates = JsonArray()
@@ -119,7 +119,7 @@         if (names.size < 2)
             return
         val newFavourite = Favourite(names[0], HashSet())
         for (name in names) {
-            newFavourite.timetables.addAll(favourites[name]!!.timetables)
+            newFavourite.segments.addAll(favourites[name]!!.segments)
             favourites.remove(name)
         }
         favourites[names[0]] = newFavourite




diff --git a/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt b/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt
index b22b2f48b568c1569d7f6f920ef74ea0dddf115e..9bac859e4e93f8dd60b4cdd8e4017e9371238983 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt
@@ -1,31 +1,14 @@
 package ml.adamsprogs.bimba.models
 
+import android.annotation.SuppressLint
 import android.content.Context
-import android.database.Cursor
-import android.database.CursorIndexOutOfBoundsException
+import android.database.*
 import android.database.sqlite.SQLiteDatabase
-import com.google.gson.Gson
-import com.google.gson.JsonObject
-import com.univocity.parsers.csv.CsvParser
-import com.univocity.parsers.csv.CsvParserSettings
-import ml.adamsprogs.bimba.R
-import ml.adamsprogs.bimba.getColour
-import ml.adamsprogs.bimba.getSecondaryExternalFilesDir
-import ml.adamsprogs.bimba.models.gtfs.AgencyAndId
-import ml.adamsprogs.bimba.models.gtfs.Route
-import ml.adamsprogs.bimba.models.gtfs.Trip
-import ml.adamsprogs.bimba.models.suggestions.LineSuggestion
-import ml.adamsprogs.bimba.models.suggestions.StopSuggestion
-import ml.adamsprogs.bimba.secondsAfterMidnight
-import org.supercsv.cellprocessor.ift.CellProcessor
-import org.supercsv.io.CsvMapReader
-import org.supercsv.prefs.CsvPreference
-import java.io.File
-import java.io.FileReader
-import kotlin.collections.ArrayList
-import kotlin.collections.HashMap
-import kotlin.collections.HashSet
-import kotlin.system.measureTimeMillis
+import ml.adamsprogs.bimba.*
+import ml.adamsprogs.bimba.models.gtfs.*
+import ml.adamsprogs.bimba.models.suggestions.*
+import java.io.*
+import kotlin.collections.*
 import java.util.Calendar as JCalendar
 
 class Timetable private constructor() {
@@ -50,7 +33,6 @@
     private lateinit var db: SQLiteDatabase
     private var _stops: List<StopSuggestion>? = null
     private lateinit var filesDir: File
-    private val tripsCache = HashMap<String, Array<String>>()
 
     fun refresh() {
     }
@@ -144,61 +126,6 @@         4586 -> (AWF73, {10 → Franowo, 29 → Franowo, 6 → Miłostowo, 5 → Stomil, 18 → Franowo, 15 → Franowo, 12 → Starołęka, 74 → Os. Orła Białego})
         */
     }
 
-    private fun parseStopTimesWithStopIndex(stopIds: List<String>, process: (Array<String>) -> Unit) {
-        val lines = readIndex(stopIds, File(filesDir, "gtfs_files/stop_index.yml"))
-        parseStopTimesWithIndex(lines, process)
-    }
-
-    private fun parseStopTimesWithTripIndex(tripIds: List<String>, process: (Array<String>) -> Unit) {
-        val lines = readIndex(tripIds, File(filesDir, "gtfs_files/trip_index.yml"))
-        parseStopTimesWithIndex(lines, process)
-    }
-
-    private fun readIndex(ids: List<String>, indexFile: File): List<Long> {
-        val index = HashMap<String, List<Long>>()
-
-        val reader = indexFile.bufferedReader() //fixme 5s
-        val json = Gson().fromJson(reader.readText(), JsonObject::class.java)
-        reader.close()
-
-        json.entrySet().forEach {
-            //fixme 3s
-            index[it.key] = ArrayList()
-            it.value.asJsonArray.mapTo(index[it.key] as ArrayList) { it.asLong }
-        }
-        return index.filter { it.key in ids }.flatMap { it.value }.sorted()
-    }
-
-    private fun parseStopTimesWithIndex(lines: List<Long>, process: (Array<String>) -> Unit) {
-        val settings = CsvParserSettings()
-        settings.format.setLineSeparator("\r\n")
-        settings.format.quote = '"'
-        settings.isHeaderExtractionEnabled = true
-        val parser = CsvParser(settings)
-
-        parser.beginParsing(File(filesDir, "gtfs_files/stop_times.txt"))
-        lines.forEach {
-            //fixme 3s
-//            println("At line ${parser.context.currentLine()}, skipping ${lines[lineKey] - parser.context.currentLine() - 1} lines to line ${lines[lineKey]}")
-            parser.context.skipLines(it - parser.context.currentLine() - 1)
-            val line = parser.parseNext()
-            process(line)
-        }
-
-    }
-
-    private fun createTripCache() {
-        val settings = CsvParserSettings()
-        settings.format.setLineSeparator("\r\n")
-        settings.format.quote = '"'
-        settings.isHeaderExtractionEnabled = true
-        val parser = CsvParser(settings)
-        val stopsFile = File(filesDir, "gtfs_files/trips.txt")
-        parser.parseAll(stopsFile).forEach {
-            tripsCache[it[2]] = it
-        }
-    }
-
     fun getStopName(stopId: AgencyAndId): String {
         val cursor = db.rawQuery("select stop_name from stops where stop_id = ?",
                 arrayOf(stopId.id))
@@ -219,118 +146,82 @@
         return code
     }
 
-    fun getLineNumber(lineId: AgencyAndId): String {
-        val file = File(filesDir, "gtfs_files/routes.txt")
-        val mapReader = CsvMapReader(FileReader(file), CsvPreference.STANDARD_PREFERENCE)
-        val header = mapReader.getHeader(true)
-
-        var row: Map<String, Any>? = null
-        val processors = Array<CellProcessor?>(header.size, { null })
-        while ({ row = mapReader.read(header, processors); row }() != null) {
-            if ((row!!["route_id"] as String) == lineId.id) {
-                mapReader.close()
-                return row!!["route_short_name"] as String
-            }
-        }
-        mapReader.close()
-        throw IllegalArgumentException("Route $lineId not in store")
-    }
-
     fun getStopDepartures(stopId: AgencyAndId): Map<AgencyAndId, List<Departure>> {
         val map = HashMap<AgencyAndId, ArrayList<Departure>>()
-        val measure = measureTimeMillis {
-
-            val cursor = db.rawQuery("select route_id, service_id, departure_time, " +
-                    "wheelchair_accessible, stop_sequence, trip_id, trip_headsign, route_desc " +
-                    "from stop_times natural join trips natural join routes where stop_id = ?",
-                    arrayOf(stopId.id))
-
-            while (cursor.moveToNext()) {
-                val line = AgencyAndId(cursor.getString(0))
-                val service = AgencyAndId(cursor.getInt(1).toString())
-                val mode = calendarToMode(service)
-                val time = parseTime(cursor.getString(2))
-                val lowFloor = cursor.getInt(3) == 1
-                val stopSequence = cursor.getInt(4)
-                val tripId = createTripId(cursor.getString(5))
-                val headsign = cursor.getString(6)
-                val desc = cursor.getString(7)
+        val cursor = db.rawQuery("select route_id, service_id, departure_time, " +
+                "wheelchair_accessible, stop_sequence, trip_id, trip_headsign, route_desc " +
+                "from stop_times natural join trips natural join routes where stop_id = ?",
+                arrayOf(stopId.id))
 
-                val modifications = Route.createModifications(desc)
+        while (cursor.moveToNext()) {
+            val line = AgencyAndId(cursor.getString(0))
+            val service = AgencyAndId(cursor.getInt(1).toString())
+            val mode = calendarToMode(service)
+            val time = parseTime(cursor.getString(2))
+            val lowFloor = cursor.getInt(3) == 1
+            val stopSequence = cursor.getInt(4)
+            val tripId = createTripId(cursor.getString(5))
+            val headsign = cursor.getString(6)
+            val desc = cursor.getString(7)
 
-                val modification = explainModification(tripId, stopSequence, modifications)
-                val departure = Departure(line, mode, time, lowFloor, modification, headsign)
-                if (map[service] == null)
-                    map[service] = ArrayList()
-                map[service]!!.add(departure)
-            }
+            val modifications = Route.createModifications(desc)
 
-            cursor.close()
-            map.forEach { it.value.sortBy { it.time } }
+            val modification = explainModification(tripId, stopSequence, modifications)
+            val departure = Departure(line, mode, time, lowFloor, modification, headsign)
+            if (map[service] == null)
+                map[service] = ArrayList()
+            map[service]!!.add(departure)
         }
 
-        //println(measure)
+        cursor.close()
+        map.forEach { it.value.sortBy { it.time } }
 
         return map
     }
 
-    fun getTrip(id: String): Trip {
-        val cursor = db.rawQuery("select * from trips where trip_id = ?", arrayOf(id))
+    fun getStopDeparturesBySegments(segments: HashSet<StopSegment>): Map<AgencyAndId, List<Departure>> {
+        val wheres = segments.flatMap {
+            it.plates?.map {
+                "(stop_id = ${it.stop} and route_id = '${it.line}' and trip_headsign = '${it.headsign}')"
+            } ?: listOf()
+        }.joinToString(" or ")
 
-        val trip = Trip(
-                AgencyAndId(cursor.getString(0)),
-                AgencyAndId(cursor.getInt(1).toString()),
-                createTripId(cursor.getString(2)),
-                cursor.getString(3),
-                cursor.getInt(4),
-                AgencyAndId(cursor.getInt(5).toString()),
-                cursor.getInt(6) == 1
-        )
+        val cursor = db.rawQuery("select route_id, service_id, departure_time, " +
+                "wheelchair_accessible, stop_sequence, trip_id, trip_headsign, route_desc " +
+                "from stop_times natural join trips natural join routes where $wheres", null)
 
+        val map = parseDeparturesCursor(cursor)
         cursor.close()
-        return trip
+        return map
     }
 
-    fun getStopDeparturesBySegment(segment: StopSegment) = getStopDeparturesBySegment(segment, getTripsForStop(segment.stop))
-
-    private fun getStopDeparturesBySegment(segment: StopSegment, trips: Map<String, Trip>): HashMap<AgencyAndId, List<Departure>> {
-        println("getStopDeparturesBySegment: ${JCalendar.getInstance().timeInMillis}")
-        /*val departures = HashMap<AgencyAndId, ArrayList<Departure>>()
+    private fun parseDeparturesCursor(cursor: Cursor): Map<AgencyAndId, List<Departure>> {
+        val map = HashMap<AgencyAndId, ArrayList<Departure>>()
 
-        val tripsInStop = HashMap<String, Pair<Int, Int>>()
+        while (cursor.moveToNext()) {
+            val line = AgencyAndId(cursor.getString(0))
+            val service = AgencyAndId(cursor.getInt(1).toString())
+            val mode = calendarToMode(service)
+            val time = parseTime(cursor.getString(2))
+            val lowFloor = cursor.getInt(3) == 1
+            val stopSequence = cursor.getInt(4)
+            val tripId = createTripId(cursor.getString(5))
+            val headsign = cursor.getString(6)
+            val desc = cursor.getString(7)
 
-        parseStopTimesWithStopIndex(listOf(segment.stop.id)) {
-            tripsInStop[it[0]] = Pair(parseTime(it[2]), it[4].toInt())
-        }
+            val modifications = Route.createModifications(desc)
 
-        val file = File(filesDir, "gtfs_files/calendar.txt")
-        val settings = CsvParserSettings()
-        settings.format.setLineSeparator("\r\n")
-        settings.format.quote = '"'
-        settings.isHeaderExtractionEnabled = true
-        val parser = CsvParser(settings)
-        parser.parseAll(file).forEach {
-            departures[AgencyAndId(it[0])] = ArrayList()
+            val modification = explainModification(tripId, stopSequence, modifications)
+            val departure = Departure(line, mode, time, lowFloor, modification, headsign)
+            if (map[service] == null)
+                map[service] = ArrayList()
+            map[service]!!.add(departure)
         }
 
-        tripsInStop.forEach {
-            //fixme this part is long --- cache is the only option
-            departures[trips[it.key]!!.serviceId]!!.add(Departure(trips[it.key]!!.routeId, // fixme null?
-                    calendarToMode(trips[it.key]!!.serviceId),
-                    it.value.first, trips[it.key]!!.wheelchairAccessible,
-                    explainModification(trips[it.key]!!, it.value.second),
-                    trips[it.key]!!.headsign))
-        }
-        println("getStopDeparturesBySegment: ${JCalendar.getInstance().timeInMillis}")
-        val sortedDepartures = HashMap<AgencyAndId, List<Departure>>()
-        departures.keys.forEach {
-            sortedDepartures[it] = departures[it]!!.sortedBy { it.time }
-        }
-        println("</>: ${JCalendar.getInstance().timeInMillis}")
-        println("</>: ${JCalendar.getInstance().timeInMillis}")
-        return sortedDepartures*/
-        TODO("FIXME")
+        map.forEach { it.value.sortBy { it.time } }
+        return map
     }
+
 
     private fun parseTime(time: String): Int {
         val cal = JCalendar.getInstance()
@@ -367,16 +258,6 @@             }
         }
 
         return explanations
-    }
-
-    private fun getRouteForTrip(trip: Trip): Route {
-        val cursor = db.rawQuery("select * from routes natural join trips where trip_id = ?",
-                arrayOf(trip.id.rawId))
-
-        cursor.moveToNext()
-        val route = createRouteFromCursorRow(cursor)
-        cursor.close()
-        return route
     }
 
     private fun createRouteFromCursorRow(cursor: Cursor): Route {
@@ -392,31 +273,6 @@
         return Route.create(routeId, agencyId, shortName, longName, desc, type, colour, textColour)
     }
 
-    fun getTripsForStop(stopId: AgencyAndId): HashMap<String, Trip> {
-        val tripIds = HashSet<String>()
-
-        parseStopTimesWithStopIndex(listOf(stopId.id)) {
-            tripIds.add(it[0])
-        }
-
-        val filteredTrips = HashMap<String, Trip>()
-
-        tripIds.forEach {
-            filteredTrips[it] = tripFromCache(it)
-        }
-        return filteredTrips
-    }
-
-    private fun tripFromCache(id: String): Trip {
-        if (tripsCache.isEmpty())
-            createTripCache()
-        return Trip(AgencyAndId(tripsCache[id]!![0]),
-                AgencyAndId(tripsCache[id]!![1]), createTripId(tripsCache[id]!![2]),
-                tripsCache[id]!![3], Integer.parseInt(tripsCache[id]!![4]),
-                AgencyAndId(tripsCache[id]!![5]), tripsCache[id]!![6] == "1")
-
-    }
-
     private fun createTripId(rawId: String): Trip.ID {
         if (rawId.contains('^')) {
             var modification = rawId.split("^")[1]
@@ -439,14 +295,19 @@         } else
             return Trip.ID(rawId, AgencyAndId(rawId), HashSet(), false)
     }
 
+    @SuppressLint("Recycle")
     fun isEmpty(): Boolean {
-        return try {
-            File(filesDir, "timetable.db")
-            //todo check if not empty
-            false
+        var result: Boolean
+        var cursor: Cursor? = null
+        try {
+            cursor = db.rawQuery("select * from feed_info", null)
+            result = !cursor.moveToNext()
         } catch (e: Exception) {
-            true
+            result = true
+        } finally {
+            cursor!!.close()
         }
+        return result
     }
 
     fun getValidSince(): String {
@@ -496,23 +357,6 @@             throw IllegalArgumentException()
         }
     }
 
-    fun getLineForNumber(number: String): AgencyAndId {
-        val file = File(filesDir, "gtfs_files/routes.txt")
-        val mapReader = CsvMapReader(FileReader(file), CsvPreference.STANDARD_PREFERENCE)
-        val header = mapReader.getHeader(true)
-
-        var row: Map<String, Any>? = null
-        val processors = Array<CellProcessor?>(header.size, { null })
-        while ({ row = mapReader.read(header, processors); row }() != null) {
-            if ((row!!["route_short_name"] as String) == number) {
-                mapReader.close()
-                return AgencyAndId(row!!["route_id"] as String)
-            }
-        }
-        mapReader.close()
-        throw IllegalArgumentException("Route $number not in store")
-    }
-
     fun getPlatesForStop(stop: AgencyAndId): Set<Plate.ID> {
         val plates = HashSet<Plate.ID>()
         val cursor = db.rawQuery("select route_id, trip_headsign " +
@@ -530,28 +374,7 @@         return plates
     }
 
     fun getTripGraphs(id: AgencyAndId): List<Map<Int, List<Int>>> {
-        val tripsToDo = HashSet<String>()
-        if (tripsCache.isEmpty())
-            createTripCache()
-        tripsCache.forEach {
-            if (it.value[0] == id.id) {
-                tripsToDo.add(it.key) //todo and direction {0,1}
-            }
-        }
-        parseStopTimesWithTripIndex(tripsToDo.toList()) {
-            //todo create graph
-        }
-        val map = ArrayList<HashMap<Int, List<Int>>>()
-        val map0 = HashMap<Int, List<Int>>()
-        map0[0] = listOf(1, 2)
-        map0[1] = listOf(3, 4, 5)
-        map.add(map0)
-        val map1 = HashMap<Int, List<Int>>()
-        map1[0] = listOf(1)
-        map1[1] = listOf(2, 3, 4)
-        map1[2] = listOf(4, 5)
-        map.add(map1)
-        return map
+        TODO("create graph")
     }
 }