package me.bvn13.sdk.android.gpx import me.bvn13.sdk.android.gpx.GpxWriter.Companion.DTF import me.bvn13.sdk.android.gpx.GpxWriter.Companion.HEADER import me.bvn13.sdk.android.gpx.GpxWriter.Companion.SCHEMA_LOCATION import me.bvn13.sdk.android.gpx.GpxWriter.Companion.XMLNS import me.bvn13.sdk.android.gpx.GpxWriter.Companion.XMLNS_XSI import java.time.Clock import java.time.OffsetDateTime import java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME import java.time.format.DateTimeFormatterBuilder fun GpxType.toXmlString(): String = this.toXmlString(null) fun GpxType.toXmlString(clock: Clock?): String = """ $HEADER ${this.metadata.toXmlString()} ${this.wpt?.toXmlString()} ${this.rte?.toXmlString()} ${this.trk?.toXmlString()} """.trim() fun MetadataType.toXmlString(): String = """ ${this.name} ${this.description} ${this.authorName} """.trim() private fun now(clock: Clock?) = OffsetDateTime.now(clock ?: Clock.systemDefaultZone()).format(DTF) fun WptType.toXmlString(nodeName: String? = null) = if (nodeName != null) { this.toXmlString(nodeName) } else { this.toXmlString("wpt") } @JvmName("toXmlStringNamed") fun WptType.toXmlString(nodeName: String) = """ <${nodeName} lat="${this.lat}" lon="${this.lon}"> ${toXmlString(ele, "ele")} ${toXmlString(time, "time")} ${toXmlString(magvar, "magvar")} ${toXmlString(geoidheight, "geoidheight")} ${toXmlString(name, "name")} ${toXmlString(cmt, "cmt")} ${toXmlString(desc, "desc")} ${toXmlString(src, "src")} ${link?.toXmlString()} ${toXmlString(sym, "sym")} ${toXmlString(type, "type")} ${fix?.toXmlString()} ${toXmlString(sat, "sat")} ${toXmlString(hdop, "hdop")} ${toXmlString(vdop, "vdop")} ${toXmlString(pdop, "pdop")} ${toXmlString(ageofgpsdata, "ageofgpsdata")} ${toXmlString(dgpsid, "dgpsid")} ${extensions?.toXmlString()} """.trim() fun RteType.toXmlString() = """ ${toXmlString(this.name, "name")} ${toXmlString(this.cmt, "cmt")} ${toXmlString(this.desc, "desc")} ${toXmlString(this.src, "src")} ${this.link?.toXmlString()} ${toXmlString(this.number, "number")} ${toXmlString(this.type, "type")} ${this.extensions?.toXmlString()} ${this.rtept?.toXmlString()} """.trim() fun TrkType.toXmlString() = """ ${toXmlString(this.name, "name")} ${toXmlString(this.cmt, "cmt")} ${toXmlString(this.desc, "desc")} ${toXmlString(this.src, "src")} ${this.link?.toXmlString()} ${toXmlString(this.number, "number")} ${toXmlString(this.type, "type")} ${this.extensions?.toXmlString()} ${this.trkseg?.toXmlString()} """.trim() fun List.toXmlString(nodeName: String?) = this.joinToString(prefix = "", postfix = "", separator = "") { it.toXmlString(nodeName) } @JvmName("toXmlStringWptType") fun List.toXmlString() = this.joinToString(prefix = "", postfix = "", separator = "") { it.toXmlString() } @JvmName("toXmlStringLinkType") fun List.toXmlString() = this.joinToString(prefix = "", postfix = "", separator = "\n", transform = LinkType::toXmlString) @JvmName("toXmlStringRteType") fun List.toXmlString() = this.joinToString(prefix = "", postfix = "", separator = "", transform = RteType::toXmlString) @JvmName("toXmlStringTrkType") fun List.toXmlString() = this.joinToString(prefix = "", postfix = "", separator = "", transform = TrkType::toXmlString) @JvmName("toXmlStringTrksegType") fun List.toXmlString() = this.joinToString(prefix = "", postfix = "", separator = "", transform = TrksegType::toXmlString) fun List.toXmlString() = this.joinToString( prefix = "\n", postfix = "\n", separator = "\n", transform = ExtensionType::toXmlString ) fun LinkType.toXmlString() = """ ${this.text} ${this.type} """.trim() fun FixType.toXmlString() = """ ${this.value} """.trim() fun ExtensionType.toXmlString() = """ <${this.nodeName}${toXmlString(this.parameters)}>${this.value ?: ""} """.trim() fun TrksegType.toXmlString() = """ ${this.trkpt?.toXmlString("trkpt")} """.trim() fun toXmlString(value: String?, nodeName: String) = if (value != null) { """ <${nodeName}>${value} """.trim() } else { "" } fun toXmlString(value: Int?, nodeName: String) = if (value != null) { """ <${nodeName}>${value} """.trim() } else { "" } fun toXmlString(value: Double?, nodeName: String) = if (value != null) { """ <${nodeName}>${value} """.trim() } else { "" } fun toXmlString(value: OffsetDateTime?, nodeName: String) = if (value != null) { """ <${nodeName}>${value.format(DTF)} """.trim() } else { "" } fun toXmlString(value: Map?) = value?.entries?.joinToString(separator = "") { " ${it.key}=\"${it.value}\"" } ?: "" class GpxWriter { companion object { const val HEADER = "" const val XMLNS = "http://www.topografix.com/GPX/1/1" const val XMLNS_XSI = "http://www.w3.org/2001/XMLSchema-instance" const val SCHEMA_LOCATION = "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd" internal val DTF = DateTimeFormatterBuilder() .append(ISO_LOCAL_DATE_TIME) // use the existing formatter for date time .appendOffset("+HH:MM", "+00:00") // set 'noOffsetText' to desired '+00:00' .toFormatter() } }