Bimba.git

commit ceac20ebc86e1a052a31118b0af5b687680485d7

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

splitting stop_times on download

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


diff --git a/.idea/dictionaries/adam.xml b/.idea/dictionaries/adam.xml
index 97ec6acaf972c3064bc9ec97c5fbf5d9c8dcb7c3..9d09bd12aa6a772411430c5662305f5dda08a2df 100644
--- a/.idea/dictionaries/adam.xml
+++ b/.idea/dictionaries/adam.xml
@@ -2,6 +2,7 @@ 
   <dictionary name="adam">
     <words>
       <w>headsign</w>
+      <w>headsigns</w>
     </words>
   </dictionary>
 </component>
\ No newline at end of file




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 ef52f870857a4c47430fcaefaddf004188946012..2632da43868d731ed9015939e0b71f027cea0408 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/DashActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/DashActivity.kt
@@ -40,14 +40,11 @@     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_dash)
 
-        println("view set")
         AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO)
         setSupportActionBar(toolbar)
         supportActionBar?.title = getString(R.string.merge_favourites)
-        println("getting stops")
 
         getStops()
-        println("stops got")
 
         prepareFavourites()
 
@@ -129,7 +126,6 @@                 "B" -> context.getString(R.string.zone_b_colour)
                 "C" -> context.getString(R.string.zone_c_colour)
                 else -> "#000000"
             }
-            println("${text[0]} $colour")
             val t = "<small><font color=\"$colour\">" + text[1] + "</font></small>"
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                 textView.text = Html.fromHtml("${text[0]} $t", Html.FROM_HTML_MODE_LEGACY)




diff --git a/app/src/main/java/ml/adamsprogs/bimba/activities/StopSpecifyActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/activities/StopSpecifyActivity.kt
index 01bae71d5ba1be49469bb1f76fc5f96afbc30d7f..14b2eb1488f25760892592baef1aa81f563ccc5b 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/activities/StopSpecifyActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/activities/StopSpecifyActivity.kt
@@ -20,13 +20,17 @@
         val ids = intent.getStringExtra(EXTRA_STOP_IDS).split(",").map {AgencyAndId(it)}.toSet()
         val headlines = Timetable.getTimetable().getHeadlinesForStop(ids)
 
+        headlines.forEach {
+            println(it)
+        }
+
         //todo select shed
 
         val shed = AgencyAndId("1")
 
-        intent = Intent(this, StopActivity::class.java)
+        /*intent = Intent(this, StopActivity::class.java)
         intent.putExtra(StopActivity.SOURCE_TYPE, StopActivity.SOURCE_TYPE_STOP)
         intent.putExtra(StopActivity.EXTRA_STOP_ID, shed)
-        startActivity(intent)
+        startActivity(intent)*/
     }
 }




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 06fc8fed24f7c6f5e687e5611c8619882a3b683e..c198ae033db3d6db29b58e64950787c232debe42 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/datasources/TimetableDownloader.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/datasources/TimetableDownloader.kt
@@ -6,17 +6,19 @@ import android.app.Notification
 import android.content.Context
 import android.content.Intent
 import android.support.v4.app.NotificationCompat
-import java.net.HttpURLConnection
-import java.net.URL
 import java.io.*
-import java.security.MessageDigest
 import android.app.NotificationManager
 import android.os.Build
+import com.univocity.parsers.csv.CsvWriter
+import com.univocity.parsers.csv.CsvWriterSettings
 import ir.mahdi.mzip.zip.ZipArchive
 import ml.adamsprogs.bimba.NetworkStateReceiver
 import ml.adamsprogs.bimba.NotificationChannels
 import ml.adamsprogs.bimba.R
 import ml.adamsprogs.bimba.models.Timetable
+import org.supercsv.io.CsvListReader
+import org.supercsv.prefs.CsvPreference
+import java.net.*
 import java.util.*
 
 class TimetableDownloader : IntentService("TimetableDownloader") {
@@ -58,7 +60,7 @@                 sendResult(RESULT_UP_TO_DATE)
                 return
             }
 
-            notifyDownloading(0)
+            notify(0, getString(R.string.timetable_downloading), size)
 
             val gtfs = File(this.filesDir, "timetable.zip")
             copyInputStreamToFile(httpCon.inputStream, gtfs)
@@ -67,15 +69,50 @@             prefsEditor.putString("timetableLastModified", lastModified)
             prefsEditor.apply()
             sendResult(RESULT_DOWNLOADED)
 
-            //notifyConverting() //fixme
+            notify(getString(R.string.timetable_converting))
 
             val target = File(this.filesDir, "gtfs_files")
             target.deleteRecursively()
             target.mkdir()
             ZipArchive.unzip(gtfs.path, target.path, "")
-            //todo divide stop_times by stop_id
+
+            val stopTimesFile = File(filesDir, "gtfs_files/stop_times.txt")
+
+            val reader = CsvListReader(FileReader(stopTimesFile), CsvPreference.STANDARD_PREFERENCE)
+            val header = reader.getHeader(true)
+
+            val headers = HashMap<String, Boolean>()
+            val mapReader = CsvListReader(FileReader(stopTimesFile), CsvPreference.STANDARD_PREFERENCE)
+
+            val string = getString(R.string.timetable_converting)
+
+            notify(0, string, 1_030_000)
+
+            println(Calendar.getInstance().timeInMillis)
+
+            var row: List<Any>? = null
+            while ({ row = mapReader.read(); row }() != null) {
+                val stopId = row!![3] as String
+                val outFile = File(filesDir, "gtfs_files/stop_times_$stopId.txt")
+                val writer = CsvWriter(CsvWriterSettings())
+                if (headers[stopId] == null) {
+                    val h = writer.writeHeadersToString(header.asList())
+                    outFile.appendText("$h\r\n")
+                    headers[stopId] = true
+                }
+                if (mapReader.rowNumber % 10_300 == 0)
+                    notify(mapReader.rowNumber, string, 1_030_000)
+                val line = writer.writeRowToString(row!!)
+                outFile.appendText("$line\r\n")
+            }
+            mapReader.close()
+
             gtfs.delete()
-            Timetable.getTimetable().refresh()
+
+            stopTimesFile.delete()
+            Timetable.getTimetable(this).refresh()
+
+            println(Calendar.getInstance().timeInMillis)
 
             cancelNotification()
 
@@ -100,51 +137,51 @@         broadcastIntent.putExtra(EXTRA_RESULT, result)
         sendBroadcast(broadcastIntent)
     }
 
-    private fun notifyDownloading(progress: Int) {
+    private fun notify(progress: Int, message: String, max: Int) {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
-            notifyCompat(progress)
+            notifyCompat(progress, message, max)
         else
-            notifyStandard(progress)
+            notifyStandard(progress, message, max)
     }
 
     @Suppress("DEPRECATION")
-    private fun notifyCompat(progress: Int) {
+    private fun notifyCompat(progress: Int, message: String, max: Int) {
         val builder = NotificationCompat.Builder(this)
                 .setSmallIcon(R.drawable.ic_download)
-                .setContentTitle(getString(R.string.timetable_downloading))
-                .setContentText("$progress KiB/$size KiB")
+                .setContentTitle(message)
+                .setContentText("${(progress.toDouble() / max.toDouble() * 100).toInt()} %")
                 .setCategory(NotificationCompat.CATEGORY_PROGRESS)
                 .setOngoing(true)
-                .setProgress(size, progress, false)
+                .setProgress(max, progress, false)
         notificationManager.notify(42, builder.build())
     }
 
     @TargetApi(Build.VERSION_CODES.O)
-    private fun notifyStandard(progress: Int) {
+    private fun notifyStandard(progress: Int, message: String, max: Int) {
         NotificationChannels.makeChannel(NotificationChannels.CHANNEL_UPDATES, "Updates", notificationManager)
         val builder = Notification.Builder(this, NotificationChannels.CHANNEL_UPDATES)
                 .setSmallIcon(R.drawable.ic_download)
-                .setContentTitle(getString(R.string.timetable_downloading))
-                .setContentText("$progress KiB/$size KiB")
+                .setContentTitle(message)
+                .setContentText("${(progress.toDouble() / max.toDouble() * 100).toInt()} %")
                 .setCategory(Notification.CATEGORY_PROGRESS)
                 .setOngoing(true)
-                .setProgress(size, progress, false)
+                .setProgress(max, progress, false)
         notificationManager.notify(42, builder.build())
     }
 
-    private fun notifyConverting() {
+    private fun notify(message: String) {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
-            notifyCompatConverting()
+            notifyCompat(message)
         else
-            notifyStandardConverting()
+            notifyStandard(message)
 
     }
 
     @Suppress("DEPRECATION")
-    private fun notifyCompatConverting() {
+    private fun notifyCompat(message: String) {
         val builder = NotificationCompat.Builder(this)
                 .setSmallIcon(R.drawable.ic_download)
-                .setContentTitle(getString(R.string.timetable_converting))
+                .setContentTitle(message)
                 .setContentText("")
                 .setCategory(NotificationCompat.CATEGORY_PROGRESS)
                 .setOngoing(true)
@@ -153,11 +190,11 @@         notificationManager.notify(42, builder.build())
     }
 
     @TargetApi(Build.VERSION_CODES.O)
-    private fun notifyStandardConverting() {
+    private fun notifyStandard(message: String) {
         NotificationChannels.makeChannel(NotificationChannels.CHANNEL_UPDATES, "Updates", notificationManager)
         val builder = Notification.Builder(this, NotificationChannels.CHANNEL_UPDATES)
                 .setSmallIcon(R.drawable.ic_download)
-                .setContentTitle(getString(R.string.timetable_converting))
+                .setContentTitle(message)
                 .setContentText("")
                 .setCategory(Notification.CATEGORY_PROGRESS)
                 .setOngoing(true)
@@ -170,7 +207,6 @@         notificationManager.cancel(42)
     }
 
     private fun copyInputStreamToFile(ins: InputStream, file: File) {
-        val md = MessageDigest.getInstance("SHA-512")
         try {
             val out = FileOutputStream(file)
             val buf = ByteArray(5 * 1024)
@@ -180,10 +216,9 @@             while (len > 0) {
                 len = ins.read(buf)
                 if (len <= 0)
                     break
-                md.update(buf, 0, len)
                 out.write(buf, 0, len)
                 lenSum += len.toFloat() / 1024.0f
-                notifyDownloading(lenSum.toInt())
+                notify(lenSum.toInt(), getString(R.string.timetable_downloading), size)
             }
             out.close()
         } catch (e: Exception) {




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 fe52772baa69c84eb089af806c8ceff6019823ae..bfa0eade27e6f02a16ba5814a10059df59919063 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/models/Timetable.kt
@@ -73,7 +73,43 @@         return _stops!!
     }
 
     fun getHeadlinesForStop(stops: Set<AgencyAndId>): Map<AgencyAndId, Pair<String, Set<String>>> {
-        TODO("Not Implemented")
+        val trips = HashMap<String, HashSet<String>>()
+        val routes = HashMap<String, Pair<String, String>>()
+        val headsigns = HashMap<AgencyAndId, Pair<String, HashSet<String>>>()
+        val settings = CsvParserSettings()
+        settings.format.setLineSeparator("\r\n")
+        settings.format.quote='"'
+        val parser = CsvParser(settings)
+        stops.forEach {
+            trips[it.id] = HashSet()
+            val stop = it.id
+            val stopsFile = File(filesDir, "gtfs_files/stop_times_${it.id}.txt")
+            parser.parseAll(stopsFile).forEach {
+                if (it[6] in arrayOf("0", "3")) {
+                    trips[stop]!!.add(it[0])
+                }
+            }
+        }
+
+        val allTrips = trips.flatMap { it.value }
+
+        val stopsFile = File(filesDir, "gtfs_files/trips.txt")
+        parser.parseAll(stopsFile).forEach {
+            if (it[2] in allTrips)
+                routes[it[2]] = Pair(it[0], it[3])
+        }
+
+
+        trips.forEach {
+            val headsign = HashSet<String>()
+            it.value.forEach {
+                println("adding: ${routes[it]}")
+                headsign.add("${routes[it]!!.first} → ${routes[it]!!.second}")
+            }
+            headsigns[AgencyAndId(it.key)] = Pair(getStopCode(AgencyAndId(it.key)), headsign)
+        }
+
+        return headsigns
         /*
         1435 -> (AWF03, {232 → Os. Rusa})
         1436 -> (AWF04, {232 → Rondo Kaponiera})