package com.tutpro.baresip.plus

import android.app.Activity
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.*
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.core.graphics.Insets
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.core.view.updatePadding
import com.tutpro.baresip.plus.databinding.ActivityAccountBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserFactory
import java.io.StringReader
import java.net.URL
import java.util.*

class AccountActivity : AppCompatActivity() {

    private lateinit var binding: ActivityAccountBinding
    private lateinit var acc: Account
    private lateinit var ua: UserAgent
    private lateinit var uri: TextView
    private lateinit var nickName: EditText
    private lateinit var displayName: EditText
    private lateinit var aor: String
    private lateinit var authUser: EditText
    private lateinit var authPass: EditText
    private lateinit var outbound: Array<EditText>
    private lateinit var mediaNat: String
    private lateinit var stun: LinearLayout
    private lateinit var stunServer: EditText
    private lateinit var stunUser: EditText
    private lateinit var stunPass: EditText
    private lateinit var regCheck: CheckBox
    private lateinit var regInt: EditText
    private lateinit var mediaNatSpinner: Spinner
    private lateinit var mediaEnc: String
    private lateinit var mediaEncSpinner: Spinner
    private lateinit var rtcpCheck: CheckBox
    private lateinit var rel100Check: CheckBox
    private var dtmfMode = Api.DTMFMODE_RTP_EVENT
    private lateinit var dtmfModeSpinner: Spinner
    private var answerMode = Api.ANSWERMODE_MANUAL
    private lateinit var answerModeSpinner: Spinner
    private var autoRedirect = false
    private lateinit var redirectModeSpinner: Spinner
    private lateinit var vmUri: EditText
    private lateinit var countryCode: EditText
    private lateinit var telProvider: EditText
    private lateinit var defaultCheck: CheckBox

    private val mediaEncKeys = arrayListOf("zrtp", "dtls_srtp", "srtp-mandf", "srtp-mand", "srtp", "")
    private val mediaEncVals = arrayListOf("ZRTP", "DTLS-SRTPF", "SRTP-MANDF", "SRTP-MAND", "SRTP", "-")
    private val mediaNatKeys = arrayListOf("stun", "turn", "ice", "")
    private val mediaNatVals = arrayListOf("STUN", "TURN", "ICE", "-")

    private var reRegister = false
    private var uaIndex= -1

    private val scope = CoroutineScope(Job() + Dispatchers.Main)

    private val onBackPressedCallback = object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            goBack()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)

        binding = ActivityAccountBinding.inflate(layoutInflater)
        setContentView(binding.root)

        ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { v: View, insets: WindowInsetsCompat ->
            val systemBars: Insets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            if (Build.VERSION.SDK_INT >= 35)
                binding.AccountView.updatePadding(top = 172)
            WindowInsetsCompat.CONSUMED
        }

        if (!Utils.isDarkTheme(this))
            WindowInsetsControllerCompat(window, binding.root).isAppearanceLightStatusBars = true

        supportActionBar?.setDisplayHomeAsUpEnabled(true)

        uri = binding.Uri
        nickName = binding.NickName
        displayName = binding.DisplayName
        authUser = binding.AuthUser
        authPass = binding.AuthPass
        outbound = arrayOf(binding.Outbound1, binding.Outbound2)
        regCheck = binding.Register
        regInt = binding.RegInt
        mediaNatSpinner = binding.mediaNatSpinner
        stun = binding.Stun
        stunServer = binding.StunServer
        stunUser = binding.StunUser
        stunPass = binding.StunPass
        mediaEncSpinner = binding.mediaEncSpinner
        rtcpCheck = binding.RtcpMux
        rel100Check = binding.Rel100
        dtmfModeSpinner = binding.dtmfModeSpinner
        answerModeSpinner = binding.answerModeSpinner
        redirectModeSpinner = binding.redirectModeSpinner
        vmUri = binding.voicemailUri
        countryCode = binding.countryCode
        telProvider = binding.telephonyProvider
        defaultCheck = binding.Default

        aor = intent.getStringExtra("aor")!!
        ua = UserAgent.ofAor(aor)!!
        acc = ua.account
        uaIndex = UserAgent.findAorIndex(aor)!!

        Utils.addActivity("account,$aor")

        if (intent.getBooleanExtra("new", false))
            initAccountFromConfig(this)

        title = if (acc.nickName != "")
            acc.nickName
        else
            aor.split(":")[1]

        initLayoutFromAccount(acc)

        bindTitles()

        onBackPressedDispatcher.addCallback(this, onBackPressedCallback)

        // Api.account_debug(acc.accp)

    }

    private fun initAccountFromConfig(ctx: AccountActivity) {
        scope.launch(Dispatchers.IO) {
            val url = "https://${Utils.uriHostPart(aor)}/baresip/account_config.xml"
            val config = try {
                URL(url).readText()
            } catch (e: java.lang.Exception) {
                Log.d(TAG, "Failed to get account configuration from network")
                null
            }
            if (config != null && !ctx.isFinishing) {
                Log.d(TAG, "Got account config '$config'")
                val acc = Account(acc.accp)
                val parserFactory: XmlPullParserFactory = XmlPullParserFactory.newInstance()
                val parser: XmlPullParser = parserFactory.newPullParser()
                parser.setInput(StringReader(config))
                var tag: String?
                var text = ""
                var event = parser.eventType
                val audioCodecs = ArrayList(Api.audio_codecs().split(","))
                val videoCodecs = ArrayList(Api.video_codecs().split(","))
                while (event != XmlPullParser.END_DOCUMENT) {
                    tag = parser.name
                    when (event) {
                        XmlPullParser.TEXT ->
                            text = parser.text
                        XmlPullParser.START_TAG -> {
                            if (tag == "audio-codecs")
                                acc.audioCodec.clear()
                            if (tag == "video-codecs")
                                acc.videoCodec.clear()
                        }
                        XmlPullParser.END_TAG ->
                            when (tag) {
                                "outbound-proxy-1" ->
                                    if (text.isNotEmpty())
                                        acc.outbound.add(text)
                                "outbound-proxy-2" ->
                                    if (text.isNotEmpty())
                                        acc.outbound.add(text)
                                "registration-interval" ->
                                    acc.configuredRegInt = text.toInt()
                                "register" ->
                                    acc.regint = if (text == "yes") acc.configuredRegInt else 0
                                "audio-codec" ->
                                    if (text in audioCodecs)
                                        acc.audioCodec.add(text)
                                "video-codec" ->
                                    if (text in videoCodecs)
                                        acc.videoCodec.add(text)
                                "media-encoding" -> {
                                    val enc = text.lowercase(Locale.ROOT)
                                    if (enc in mediaEncKeys && enc.isNotEmpty())
                                        acc.mediaEnc = enc
                                }
                                "media-nat" -> {
                                    val nat = text.lowercase(Locale.ROOT)
                                    if (nat in mediaNatKeys && nat.isNotEmpty())
                                        acc.mediaNat = nat
                                }
                                "stun-turn-server" ->
                                    if (text.isNotEmpty())
                                        acc.stunServer = text
                                "rtcp-mux" ->
                                    acc.rtcpMux = text == "yes"
                                "100rel-mode" ->
                                    acc.rel100Mode = if (text == "yes")
                                            Api.REL100_ENABLED
                                        else
                                            Api.REL100_DISABLED
                                "dtmf-mode" ->
                                    if (text in arrayOf("rtp-event", "sip-info", "auto"))
                                        acc.dtmfMode = when (text) {
                                            "rtp-event" -> Api.DTMFMODE_RTP_EVENT
                                            "sip-info" -> Api.DTMFMODE_SIP_INFO
                                            else -> Api.DTMFMODE_AUTO
                                        }
                                "answer-mode" ->
                                    if (text in arrayOf("manual", "auto"))
                                        acc.answerMode = if (text == "manual")
                                            Api.ANSWERMODE_MANUAL
                                        else
                                            Api.ANSWERMODE_AUTO
                                "redirect-mode" ->
                                    acc.autoRedirect = text == "yes"
                                "voicemail-uri" ->
                                    if (text.isNotEmpty())
                                        acc.vmUri = text
                                "country-code" ->
                                    acc.countryCode = text
                                "tel-provider" ->
                                    acc.telProvider = text
                            }
                    }
                    event = parser.next()
                }
                runOnUiThread {
                    initLayoutFromAccount(acc)
                }
            }
        }
    }

    private fun initLayoutFromAccount(acc: Account) {

        uri.text = acc.luri
        nickName.setText(acc.nickName)
        displayName.setText(acc.displayName)
        authUser.setText(acc.authUser)

        if (BaresipService.aorPasswords[aor] != null || acc.authPass == NO_AUTH_PASS)
            authPass.setText("")
        else
            authPass.setText(acc.authPass)

        if (acc.outbound.size > 0) {
            outbound[0].setText(acc.outbound[0])
            if (acc.outbound.size > 1)
                outbound[1].setText(acc.outbound[1])
        }

        regCheck.isChecked = acc.regint > 0
        regInt.setText(acc.configuredRegInt.toString())

        this.acc.audioCodec = acc.audioCodec
        this.acc.videoCodec = acc.videoCodec

        mediaNat = acc.mediaNat
        var keyIx = mediaNatKeys.indexOf(acc.mediaNat)
        var keyVal = mediaNatVals.elementAt(keyIx)
        mediaNatKeys.removeAt(keyIx)
        mediaNatVals.removeAt(keyIx)
        mediaNatKeys.add(0, acc.mediaNat)
        mediaNatVals.add(0, keyVal)
        val mediaNatAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item,
                mediaNatVals)
        mediaNatAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        mediaNatSpinner.adapter = mediaNatAdapter
        mediaNatSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
                mediaNat = mediaNatKeys[mediaNatVals.indexOf(parent.selectedItem.toString())]
                if ((mediaNat == "turn") && stunServer.text.startsWith("stun"))
                    stunServer.setText("")
                else if ((mediaNat == "stun") &&
                        (stunServer.text.startsWith("turn") || (stunServer.text.toString() == "")))
                    stunServer.setText(resources.getString(R.string.stun_server_default))
                else if ((mediaNat == "ice") && (stunServer.text.toString() == ""))
                    stunServer.setText(resources.getString(R.string.stun_server_default))
                if (mediaNat == "") {
                    stun.visibility = GONE
                    stunServer.setText("")
                    stunUser.setText("")
                    stunPass.setText("")
                } else
                    stun.visibility = VISIBLE
            }
            override fun onNothingSelected(parent: AdapterView<*>) {
            }
        }

        stunServer.setText(acc.stunServer)
        stunUser.setText(acc.stunUser)
        stunPass.setText(acc.stunPass)

        mediaEnc = acc.mediaEnc
        keyIx = mediaEncKeys.indexOf(mediaEnc)
        keyVal = mediaEncVals.elementAt(keyIx)
        mediaEncKeys.removeAt(keyIx)
        mediaEncVals.removeAt(keyIx)
        mediaEncKeys.add(0, mediaEnc)
        mediaEncVals.add(0, keyVal)
        val mediaEncAdapter = ArrayAdapter(this,android.R.layout.simple_spinner_item,
                mediaEncVals)
        mediaEncAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        mediaEncSpinner.adapter = mediaEncAdapter
        mediaEncSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
                mediaEnc = mediaEncKeys[mediaEncVals.indexOf(parent.selectedItem.toString())]
            }
            override fun onNothingSelected(parent: AdapterView<*>) {
            }
        }

        rtcpCheck.isChecked = acc.rtcpMux

        rel100Check.isChecked = acc.rel100Mode == Api.REL100_ENABLED

        dtmfMode = acc.dtmfMode
        val dtmfModeKeys = arrayListOf(Api.DTMFMODE_RTP_EVENT, Api.DTMFMODE_SIP_INFO, Api.DTMFMODE_AUTO)
        val dtmfModeVals = arrayListOf(getString(R.string.dtmf_inband), getString(R.string.dtmf_info), getString(R.string.dtmf_auto))
        keyIx = dtmfModeKeys.indexOf(acc.dtmfMode)
        keyVal = dtmfModeVals.elementAt(keyIx)
        dtmfModeKeys.removeAt(keyIx)
        dtmfModeVals.removeAt(keyIx)
        dtmfModeKeys.add(0, acc.dtmfMode)
        dtmfModeVals.add(0, keyVal)
        val dtmfModeAdapter = ArrayAdapter(this,android.R.layout.simple_spinner_item,
                dtmfModeVals)
        dtmfModeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        dtmfModeSpinner.adapter = dtmfModeAdapter
        dtmfModeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
                dtmfMode = dtmfModeKeys[dtmfModeVals.indexOf(parent.selectedItem.toString())]
            }
            override fun onNothingSelected(parent: AdapterView<*>) {
            }
        }

        answerMode = acc.answerMode
        val answerModeKeys = arrayListOf(Api.ANSWERMODE_MANUAL, Api.ANSWERMODE_AUTO)
        val answerModeVals = arrayListOf(getString(R.string.manual), getString(R.string.auto))
        keyIx = answerModeKeys.indexOf(acc.answerMode)
        keyVal = answerModeVals.elementAt(keyIx)
        answerModeKeys.removeAt(keyIx)
        answerModeVals.removeAt(keyIx)
        answerModeKeys.add(0, acc.answerMode)
        answerModeVals.add(0, keyVal)
        val answerModeAdapter = ArrayAdapter(this,android.R.layout.simple_spinner_item,
                answerModeVals)
        answerModeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        answerModeSpinner.adapter = answerModeAdapter
        answerModeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
                answerMode = answerModeKeys[answerModeVals.indexOf(parent.selectedItem.toString())]
            }
            override fun onNothingSelected(parent: AdapterView<*>) {
            }
        }

        autoRedirect = acc.autoRedirect
        val redirectModeKeys = arrayListOf(false, true)
        val redirectModeVals = arrayListOf(getString(R.string.manual), getString(R.string.auto))
        keyIx = redirectModeKeys.indexOf(acc.autoRedirect)
        keyVal = redirectModeVals.elementAt(keyIx)
        redirectModeKeys.removeAt(keyIx)
        redirectModeVals.removeAt(keyIx)
        redirectModeKeys.add(0, acc.autoRedirect)
        redirectModeVals.add(0, keyVal)
        val redirectModeAdapter = ArrayAdapter(this,android.R.layout.simple_spinner_item,
            redirectModeVals)
        redirectModeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        redirectModeSpinner.adapter = redirectModeAdapter
        redirectModeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
                autoRedirect = redirectModeKeys[redirectModeVals.indexOf(parent.selectedItem.toString())]
            }
            override fun onNothingSelected(parent: AdapterView<*>) {
            }
        }

        if (acc.countryCode != "")
            countryCode.setText(acc.countryCode)

        telProvider.setText(acc.telProvider)

        vmUri.setText(acc.vmUri)

        defaultCheck.isChecked = uaIndex == 0
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {

        super.onCreateOptionsMenu(menu)
        val inflater = menuInflater
        inflater.inflate(R.menu.check_icon, menu)
        return true

    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {

        if (BaresipService.activities.indexOf("account,$aor") == -1)
            return true

        when (item.itemId) {

            R.id.checkIcon -> {

                val nn = nickName.text.toString().trim()
                if (nn != acc.nickName) {
                    if (Account.checkDisplayName(nn)) {
                        if (nn == "" || Account.uniqueNickName(nn)) {
                            acc.nickName = nn
                            Log.d(TAG, "New nickname is ${acc.nickName}")
                        } else {
                            Utils.alertView(this, getString(R.string.notice),
                                    String.format(getString(R.string.non_unique_account_nickname), nn))
                            return false
                        }
                    } else {
                        Utils.alertView(this, getString(R.string.notice),
                                String.format(getString(R.string.invalid_account_nickname), nn))
                        return false
                    }
                }

                val dn = displayName.text.toString().trim()
                if (dn != acc.displayName) {
                    if (Account.checkDisplayName(dn)) {
                        if (Api.account_set_display_name(acc.accp, dn) == 0) {
                            acc.displayName = Api.account_display_name(acc.accp)
                            Log.d(TAG, "New display name is ${acc.displayName}")
                        } else {
                            Log.e(TAG, "Setting of display name failed")
                        }
                    } else {
                        Utils.alertView(this, getString(R.string.notice),
                                String.format(getString(R.string.invalid_display_name), dn))
                        return false
                    }
                }

                val au = authUser.text.toString().trim()
                val ap = authPass.text.toString().trim()

                if (au != acc.authUser) {
                    if (Account.checkAuthUser(au)) {
                        if (Api.account_set_auth_user(acc.accp, au) == 0) {
                            acc.authUser = Api.account_auth_user(acc.accp)
                            Log.d(TAG, "New auth user is ${acc.authUser}")
                            if (acc.regint > 0)
                                reRegister = true
                        } else {
                            Log.e(TAG, "Setting of auth user failed")
                        }
                    } else {
                        Utils.alertView(this, getString(R.string.notice),
                                String.format(getString(R.string.invalid_authentication_username), au))
                        return false
                    }
                }

                if (ap != "") {
                    if (ap != acc.authPass) {
                        if (Account.checkAuthPass(ap)) {
                            if (Api.account_set_auth_pass(acc.accp, ap) == 0) {
                                acc.authPass = Api.account_auth_pass(acc.accp)
                                if (acc.regint > 0)
                                    reRegister = true
                            } else {
                                Log.e(TAG, "Setting of auth pass failed")
                            }
                            BaresipService.aorPasswords.remove(acc.aor)
                        } else {
                            Utils.alertView(this, getString(R.string.notice),
                                    String.format(getString(R.string.invalid_authentication_password), ap))
                            return false
                        }
                    } else {
                        BaresipService.aorPasswords.remove(acc.aor)
                    }
                } else { // ap == ""
                    if (acc.authPass != NO_AUTH_PASS &&
                            acc.authPass != BaresipService.aorPasswords[acc.aor])
                        if (Api.account_set_auth_pass(acc.accp, "") == 0) {
                            acc.authPass = NO_AUTH_PASS
                            BaresipService.aorPasswords[aor] = NO_AUTH_PASS
                        }
                }

                val ob = ArrayList<String>()
                for (i in 0..1) {
                    var uri: String
                    if (outbound[i].text.toString().trim() != "") {
                        uri = outbound[i].text.toString().trim().replace(" ", "")
                        if (!uri.startsWith("sip:"))
                            uri = "sip:$uri"
                        if (checkOutboundUri(uri)) {
                            ob.add(uri)
                        } else {
                            Utils.alertView(this, getString(R.string.notice),
                                    String.format(getString(R.string.invalid_proxy_server_uri), uri))
                            return false
                        }
                    }
                }
                if (ob != acc.outbound) {
                    for (i in 0..1) {
                        val uri = if (ob.size > i)
                            ob[i]
                        else
                            ""
                        if (Api.account_set_outbound(acc.accp, uri, i) != 0)
                            Log.e(TAG, "Setting of outbound proxy $i uri '$uri' failed")
                    }
                    Log.d(TAG, "New outbound proxies are $ob")
                    acc.outbound = ob
                    if (ob.isEmpty())
                        Api.account_set_sipnat(acc.accp, "")
                    else
                        Api.account_set_sipnat(acc.accp, "outbound")
                    if (acc.regint > 0)
                        reRegister = true
                }

                val newConfiguredRegInt = regInt.text.toString().trim().toInt()
                if (newConfiguredRegInt < 60 || newConfiguredRegInt > 3600) {
                    Utils.alertView(
                        this, getString(R.string.notice),
                        String.format(getString(R.string.invalid_reg_int), "$newConfiguredRegInt")
                    )
                    return false
                }
                val reReg = (regCheck.isChecked != acc.regint > 0) ||
                        (regCheck.isChecked && newConfiguredRegInt != acc.configuredRegInt)
                if (reReg) {
                    if (Api.account_set_regint(acc.accp,
                            if (regCheck.isChecked) newConfiguredRegInt else 0) != 0) {
                        Log.e(TAG, "Setting of regint failed")
                    } else {
                        acc.regint = Api.account_regint(acc.accp)
                        acc.configuredRegInt = newConfiguredRegInt
                        Log.d(TAG, "New regint is ${acc.regint}")
                        reRegister = true
                    }
                } else {
                    if (newConfiguredRegInt != acc.configuredRegInt) {
                        acc.configuredRegInt = newConfiguredRegInt
                    }
                }

                if (mediaNat != acc.mediaNat) {
                    if (Api.account_set_medianat(acc.accp, mediaNat) == 0) {
                        acc.mediaNat = Api.account_medianat(acc.accp)
                        Log.d(TAG, "New medianat is ${acc.mediaNat}")
                    } else {
                        Log.e(TAG, "Setting of medianat failed")
                    }
                }

                var newStunServer = stunServer.text.toString().trim()
                if (mediaNat != "") {
                    if (((mediaNat == "stun") || (mediaNat == "ice")) && (newStunServer == ""))
                        newStunServer = resources.getString(R.string.stun_server_default)
                    if (!Utils.checkStunUri(newStunServer) ||
                            (mediaNat == "turn" &&
                                    newStunServer.substringBefore(":") !in setOf("turn", "turns"))) {
                        Utils.alertView(this, getString(R.string.notice),
                                String.format(getString(R.string.invalid_stun_server), newStunServer))
                        return false
                    }
                }

                if (acc.stunServer != newStunServer) {
                    if (Api.account_set_stun_uri(acc.accp, newStunServer) == 0) {
                        acc.stunServer = Api.account_stun_uri(acc.accp)
                        Log.d(TAG, "New STUN/TURN server URI is '${acc.stunServer}'")
                    } else {
                        Log.e(TAG, "Setting of STUN/TURN URI server failed")
                    }
                }

                val newStunUser = stunUser.text.toString().trim()
                if (acc.stunUser != newStunUser) {
                    if (Account.checkAuthUser(newStunUser)) {
                        if (Api.account_set_stun_user(acc.accp, newStunUser) == 0) {
                            acc.stunUser = Api.account_stun_user(acc.accp)
                            Log.d(TAG, "New STUN/TURN user is ${acc.stunUser}")
                        } else {
                            Log.e(TAG, "Setting of STUN/TURN user failed")
                        }
                    } else {
                        Utils.alertView(this, getString(R.string.notice), String.format(getString(R.string.invalid_stun_username),
                                newStunUser))
                        return false
                    }
                }

                val newStunPass = stunPass.text.toString().trim()
                if (acc.stunPass != newStunPass) {
                    if (newStunPass.isEmpty() || Account.checkAuthPass(newStunPass)) {
                        if (Api.account_set_stun_pass(acc.accp, newStunPass) == 0) {
                            acc.stunPass = Api.account_stun_pass(acc.accp)
                        } else {
                            Log.e(TAG, "Setting of stun pass failed")
                        }
                    } else {
                        Utils.alertView(this, getString(R.string.notice),
                                String.format(getString(R.string.invalid_stun_password), newStunPass))
                        return false
                    }
                }

                if (mediaEnc != acc.mediaEnc) {
                    if (Api.account_set_mediaenc(acc.accp, mediaEnc) == 0) {
                        acc.mediaEnc = Api.account_mediaenc(acc.accp)
                        Log.d(TAG, "New mediaenc is ${acc.mediaEnc}")
                    } else {
                        Log.e(TAG, "Setting of mediaenc $mediaEnc failed")
                    }
                }

                if (rtcpCheck.isChecked != acc.rtcpMux)
                    if (Api.account_set_rtcp_mux(acc.accp, rtcpCheck.isChecked) == 0) {
                        acc.rtcpMux = Api.account_rtcp_mux(acc.accp)
                        Log.d(TAG, "New rtcpMux is ${acc.rtcpMux}")
                    } else {
                        Log.e(TAG, "Setting of account_rtc_mux failed")
                    }

                if (rel100Check.isChecked != (acc.rel100Mode == Api.REL100_ENABLED)) {
                    val mode = if (rel100Check.isChecked) Api.REL100_ENABLED else Api.REL100_DISABLED
                    if (Api.account_set_rel100_mode(acc.accp, mode) == 0) {
                        acc.rel100Mode = Api.account_rel100_mode(acc.accp)
                        Api.ua_update_account(ua.uap)
                        Log.d(TAG, "New rel100Mode is ${acc.rel100Mode}")
                    } else {
                        Log.e(TAG, "Setting of account_rel100Mode failed")
                    }
                }

                if (dtmfMode != acc.dtmfMode) {
                    if (Api.account_set_dtmfmode(acc.accp, dtmfMode) == 0) {
                        acc.dtmfMode = Api.account_dtmfmode(acc.accp)
                        Log.d(TAG, "New dtmfmode is ${acc.dtmfMode}")
                    } else {
                        Log.e(TAG, "Setting of dtmfmode $dtmfMode failed")
                    }
                }

                if (answerMode != acc.answerMode) {
                    if (Api.account_set_answermode(acc.accp, answerMode) == 0) {
                        acc.answerMode = Api.account_answermode(acc.accp)
                        Log.d(TAG, "New answermode is ${acc.answerMode}")
                    } else {
                        Log.e(TAG, "Setting of answermode $answerMode failed")
                    }
                }

                if (autoRedirect != acc.autoRedirect) {
                    Api.account_set_sip_autoredirect(acc.accp, autoRedirect)
                    acc.autoRedirect = autoRedirect
                    Log.d(TAG, "New autoRedirect is ${acc.autoRedirect}")
                }

                var tVmUri = vmUri.text.toString().trim()
                if (tVmUri != acc.vmUri) {
                    if (tVmUri != "") {
                        if (!tVmUri.startsWith("sip:")) tVmUri = "sip:$tVmUri"
                        if (!tVmUri.contains("@")) tVmUri = "$tVmUri@${acc.host()}"
                        if (!Utils.checkUri(tVmUri)) {
                            Utils.alertView(this, getString(R.string.notice),
                                    String.format(getString(R.string.invalid_sip_or_tel_uri), tVmUri))
                            return false
                        }
                        Api.account_set_mwi(acc.accp, true)
                    } else {
                        Api.account_set_mwi(acc.accp, false)
                    }
                    acc.vmUri = tVmUri
                }

                val newCountryCode = countryCode.text.toString().trim()
                if (newCountryCode != acc.countryCode) {
                    if (newCountryCode != "" && !Utils.checkCountryCode(newCountryCode)) {
                        Utils.alertView(this, getString(R.string.notice),
                                String.format(getString(R.string.invalid_country_code), newCountryCode))
                        return false
                    }
                    acc.countryCode = newCountryCode
                }

                val hostPart = telProvider.text.toString().trim()
                if (hostPart != acc.telProvider) {
                    if (hostPart != "" && !Utils.checkHostPortParams(hostPart)) {
                        Utils.alertView(this, getString(R.string.notice),
                                String.format(getString(R.string.invalid_sip_uri_hostpart), hostPart))
                        return false
                    }
                    acc.telProvider = hostPart
                }

                if (defaultCheck.isChecked && (uaIndex > 0)) {
                    BaresipService.uas.add(0, BaresipService.uas[uaIndex])
                    BaresipService.uas.removeAt(uaIndex + 1)
                }

                AccountsActivity.saveAccounts()

                if (reRegister) {
                    ua.status = R.drawable.circle_yellow
                    if (acc.regint == 0)
                        Api.ua_unregister(ua.uap)
                    else
                        Api.ua_register(ua.uap)
                }

                BaresipService.activities.remove("account,$aor")
                returnResult(Activity.RESULT_OK)
                return true
            }

            android.R.id.home -> {
                goBack()
                return true
            }

        }

        return super.onOptionsItemSelected(item)

    }

    private fun goBack() {
        BaresipService.activities.remove("account,$aor")
        returnResult(Activity.RESULT_CANCELED)
    }

    override fun onPause() {
        MainActivity.activityAor = aor
        super.onPause()
    }

    private fun bindTitles() {
        binding.NickNameTitle.setOnClickListener{
            Utils.alertView(this, getString(R.string.nickname),
                    getString(R.string.account_nickname_help))
        }
        binding.DisplayNameTitle.setOnClickListener{
            Utils.alertView(this, getString(R.string.display_name),
                getString(R.string.display_name_help))
        }
        binding.AuthUserTitle.setOnClickListener {
            Utils.alertView(
                this, getString(R.string.authentication_username),
                getString(R.string.authentication_username_help)
            )
        }
        binding.AuthPassTitle.setOnClickListener {
            Utils.alertView(
                this, getString(R.string.authentication_password),
                getString(R.string.authentication_password_help)
            )
        }
        binding.OutboundProxyTitle.setOnClickListener {
            Utils.alertView(
                this, getString(R.string.outbound_proxies),
                getString(R.string.outbound_proxies_help)
            )
        }
        binding.RegTitle.setOnClickListener {
            Utils.alertView(
                this, getString(R.string.register),
                getString(R.string.register_help)
            )
        }
        binding.RegIntTitle.setOnClickListener {
            Utils.alertView(
                    this, getString(R.string.reg_int),
                    getString(R.string.reg_int_help)
            )
        }
        binding.AudioCodecsTitle.setOnClickListener {
            val i = Intent(this, CodecsActivity::class.java)
            val b = Bundle()
            b.putString("aor", aor)
            b.putString("media", "audio")
            i.putExtras(b)
            startActivity(i)
        }
        binding.VideoCodecsTitle.setOnClickListener {
            val i = Intent(this, CodecsActivity::class.java)
            val b = Bundle()
            b.putString("aor", aor)
            b.putString("media", "video")
            i.putExtras(b)
            startActivity(i)
        }
        binding.MediaNatTitle.setOnClickListener {
            Utils.alertView(
                this, getString(R.string.media_nat),
                getString(R.string.media_nat_help)
            )
        }
        binding.StunServerTitle.setOnClickListener {
            Utils.alertView(
                this, getString(R.string.stun_server),
                getString(R.string.stun_server_help)
            )
        }
        binding.StunUserTitle.setOnClickListener {
            Utils.alertView(
                this, getString(R.string.stun_username),
                getString(R.string.stun_username_help)
            )
        }
        binding.StunPassTitle.setOnClickListener {
            Utils.alertView(
                this, getString(R.string.stun_password),
                getString(R.string.stun_password_help)
            )
        }
        binding.MediaEncTitle.setOnClickListener {
            Utils.alertView(
                this, getString(R.string.media_encryption),
                getString(R.string.media_encryption_help)
            )
        }
        binding.Rel100Title.setOnClickListener {
            Utils.alertView(
                this, getString(R.string.rel_100),
                getString(R.string.rel_100_help)
            )
        }
        binding.DtmfModeTitle.setOnClickListener {
            Utils.alertView(
                this, getString(R.string.dtmf_mode),
                getString(R.string.dtmf_mode_help)
            )
        }
        binding.AnswerModeTitle.setOnClickListener {
            Utils.alertView(
                this, getString(R.string.answer_mode),
                getString(R.string.answer_mode_help)
            )
        }
        binding.RedirectModeTitle.setOnClickListener {
            Utils.alertView(
                this, getString(R.string.redirect_mode),
                getString(R.string.redirect_mode_help)
            )
        }
        binding.VoicemailUriTitle.setOnClickListener {
            Utils.alertView(
                this, getString(R.string.voicemail_uri),
                getString(R.string.voicemain_uri_help)
            )
        }
        binding.CountryCodeTitle.setOnClickListener {
            Utils.alertView(
                    this, getString(R.string.country_code),
                    getString(R.string.country_code_help)
            )
        }
        binding.TelephonyProviderTitle.setOnClickListener {
            Utils.alertView(
                    this, getString(R.string.telephony_provider),
                    getString(R.string.telephony_provider_help)
            )
        }
        binding.DefaultTitle.setOnClickListener {
            Utils.alertView(
                this, getString(R.string.default_account),
                getString(R.string.default_account_help)
            )
        }
    }

    private fun returnResult(code: Int) {
        val i = Intent()
        if (code == Activity.RESULT_OK)
            i.putExtra("aor", aor)
        setResult(code, i)
        finish()
    }

    private fun checkOutboundUri(uri: String): Boolean {
        if (!uri.startsWith("sip:")) return false
        return Utils.checkHostPortParams(uri.substring(4))
    }

}
