package com.casic.detector.view

import android.annotation.SuppressLint
import android.app.DatePickerDialog
import android.app.Dialog
import android.content.Context
import android.content.DialogInterface
import android.graphics.BitmapFactory
import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.media.AudioAttributes
import android.media.SoundPool
import android.os.Bundle
import android.os.CountDownTimer
import android.util.Log
import android.view.KeyEvent
import android.view.View
import android.view.animation.Animation
import android.view.animation.RotateAnimation
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.amap.api.location.AMapLocation
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.CoordinateConverter
import com.amap.api.maps.model.BitmapDescriptorFactory
import com.amap.api.maps.model.LatLng
import com.amap.api.maps.model.LatLngBounds
import com.amap.api.maps.model.MarkerOptions
import com.amap.api.maps.model.MyLocationStyle
import com.casic.detector.R
import com.casic.detector.adapter.EditableImageAdapter
import com.casic.detector.base.SerialPortActivity
import com.casic.detector.bean.LabelBean
import com.casic.detector.bean.TaskBean
import com.casic.detector.callback.ILocationListener
import com.casic.detector.callback.OnImageCompressListener
import com.casic.detector.cluster.ClusterItem
import com.casic.detector.cluster.ClusterOverlay
import com.casic.detector.cluster.RegionItem
import com.casic.detector.databinding.ActivityMainBinding
import com.casic.detector.databinding.DialogInstallMarkerBinding
import com.casic.detector.databinding.DialogSearchMarkerBinding
import com.casic.detector.databinding.DialogSearchMarkerNewBinding
import com.casic.detector.extensions.appendDownloadUrl
import com.casic.detector.extensions.compressImage
import com.casic.detector.extensions.drawCircle
import com.casic.detector.extensions.getDefaultValue
import com.casic.detector.extensions.hexToString
import com.casic.detector.extensions.initImmersionBar
import com.casic.detector.extensions.isNumber
import com.casic.detector.extensions.setDefaultValue
import com.casic.detector.extensions.show
import com.casic.detector.extensions.toColor
import com.casic.detector.extensions.toHex
import com.casic.detector.extensions.toObjectType
import com.casic.detector.model.TaskModel
import com.casic.detector.utils.DataBaseManager
import com.casic.detector.utils.ExcelHub
import com.casic.detector.utils.FileType
import com.casic.detector.utils.GpioManager
import com.casic.detector.utils.LocaleConstant
import com.casic.detector.utils.LocationHub
import com.casic.detector.utils.RouteOnMap
import com.casic.detector.vm.TaskViewModel
import com.casic.detector.widgets.QueryMarkerDialog
import com.casic.detector.widgets.SamplePopupWindow
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.luck.picture.lib.basic.PictureSelector
import com.luck.picture.lib.config.SelectMimeType
import com.luck.picture.lib.entity.LocalMedia
import com.luck.picture.lib.interfaces.OnResultCallbackListener
import com.pengxh.kt.lite.extensions.appendZero
import com.pengxh.kt.lite.extensions.binding
import com.pengxh.kt.lite.extensions.convertColor
import com.pengxh.kt.lite.extensions.convertDrawable
import com.pengxh.kt.lite.extensions.createDownloadFileDir
import com.pengxh.kt.lite.extensions.dateToTimestamp
import com.pengxh.kt.lite.extensions.dp2px
import com.pengxh.kt.lite.extensions.initDialogLayoutParams
import com.pengxh.kt.lite.extensions.isNetworkConnected
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.extensions.timestampToCompleteDate
import com.pengxh.kt.lite.extensions.timestampToTime
import com.pengxh.kt.lite.extensions.toJson
import com.pengxh.kt.lite.utils.FileDownloadManager
import com.pengxh.kt.lite.utils.LoadState
import com.pengxh.kt.lite.utils.LoadingDialogHub
import com.pengxh.kt.lite.utils.SaveKeyValues
import com.pengxh.kt.lite.widget.dialog.AlertControlDialog
import com.pengxh.kt.lite.widget.dialog.AlertInputDialog
import com.pengxh.kt.lite.widget.dialog.AlertMessageDialog
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.text.DecimalFormat
import java.util.Calendar
import java.util.Date
import java.util.Timer
import java.util.TimerTask

@SuppressLint("all")
class MainActivity : SerialPortActivity<ActivityMainBinding>() {

    private val kTag = "MainActivity"
    private val context = this@MainActivity
    private val samplePopupWindow by lazy { SamplePopupWindow(this) }
    private val gson by lazy { Gson() }
    private val regionRadius by lazy { LocaleConstant.RADIUS_SIZE.dp2px(this) }
    private val backDrawables by lazy { HashMap<Int, Drawable>() }
    private val installDialog by lazy { InstallMarkerDialog(this) }
    private val searchDialog by lazy { SearchMarkerDialog(this) }
    private val searchNewDialog by lazy { SearchMarkerNewDialog(this) }
    private var clickTime: Long = 0
    private var labelBeans = ArrayList<LabelBean>()
    private var clusterOverlay: ClusterOverlay? = null
    private var latitude: Double = 0.0
    private var longitude: Double = 0.0
    private var isFreeTask = false
    private var ids = ArrayList<String>()
    private var signalTask: TimerTask? = null
    private var searchMarkerTimer: Timer? = null
    private var taskId: String? = null
    private lateinit var aMap: AMap
    private lateinit var task: TaskBean

    /***inner class 需要用到*****start*/
    private val gpioManager by lazy { GpioManager() }
    private val locationHub by lazy { LocationHub(this) }
    private val taskViewModel by lazy { ViewModelProvider(this)[TaskViewModel::class.java] }
    private val attr = AudioAttributes.Builder()
        .setUsage(AudioAttributes.USAGE_ALARM)
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .build()
    private val soundPool = SoundPool.Builder().setMaxStreams(16).setAudioAttributes(attr).build()
    private var soundResourceId = 0
    private var slowSoundResourceId = 0
    private var fastSoundResourceId = 0
    private var isExecuteTask = false

    /***inner class 需要用到*****end*/

    override fun initViewBinding(): ActivityMainBinding {
        return ActivityMainBinding.inflate(layoutInflater)
    }

    override fun setupTopBarLayout() {
        binding.rootView.initImmersionBar(this, false, R.color.themeColor)
    }

    override fun initOnCreate(savedInstanceState: Bundle?) {
        soundResourceId = soundPool.load(this, R.raw.ring3, 1)
        slowSoundResourceId = soundPool.load(this, R.raw.ring4, 1)
        fastSoundResourceId = soundPool.load(this, R.raw.ring2, 1)

        //地图初始化
        initMapConfig(savedInstanceState)

        //右上角菜单
        samplePopupWindow.setPopupMenuItem(LocaleConstant.POPUP_TITLES)
        samplePopupWindow.setBackgroundDrawable(null)

        //task网络请求监听
        taskViewModel.markerFileResult.observe(this) {
            if (it.isSuccess) {
                //清空之前的数据
                DataBaseManager.get.clearTaskLabels()
                //下载最新的数据
                val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "")
                val downloadUrl = companyId.toString().appendDownloadUrl(FileType.EXCEL)
                Log.d(kTag, "downloadUrl => $downloadUrl")
                FileDownloadManager.Builder().setDownloadFileSource(downloadUrl)
                    .setFileSuffix("xls").setFileSaveDirectory(createDownloadFileDir())
                    .setOnFileDownloadListener(object : FileDownloadManager.OnFileDownloadListener {
                        override fun onDownloadEnd(file: File) {
                            lifecycleScope.launch(Dispatchers.Main) {
                                labelBeans = ExcelHub.read(file.absolutePath)
                                withContext(Dispatchers.IO) {
                                    labelBeans.forEach { label ->
                                        DataBaseManager.get.insertTaskLabel(label)
                                    }
                                }
                                LoadingDialogHub.dismiss()
                                showLabelsOnMap()
                            }
                        }

                        override fun onFailure(throwable: Throwable) {

                        }

                        override fun onProgressChanged(progress: Int) {

                        }
                    }).build().start()
            }
        }
        taskViewModel.taskResult.observe(this) {
            if (it.success == "true") {
                //清空之前的数据
                DataBaseManager.get.clearTasks()
                AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示")
                    .setMessage("您有${it.message.size}个新任务！").setPositiveButton("知道了")
                    .setOnDialogButtonClickListener(object :
                        AlertMessageDialog.OnDialogButtonClickListener {
                        override fun onConfirmClick() {
                            saveTaskInformation(it)
                        }
                    }).build().show()
            }
        }
        taskViewModel.freeTaskResult.observe(this) { taskId = it }
        taskViewModel.uploadTaskMarkerResult.observe(this) {
            "自由巡检任务已完成".show(this)
            ids.clear()
        }
    }

    override fun initEvent() {
        binding.rightImageView.setOnClickListener {
            lifecycleScope.launch(Dispatchers.Main) {
                val labels = withContext(Dispatchers.IO) {
                    DataBaseManager.get.queryLabelById("0")
                }
                if (labels.isNotEmpty()) {
                    samplePopupWindow.setShowPosition(4)
                }
                val x = binding.rightImageView.width - samplePopupWindow.width - 1.dp2px(context)
                samplePopupWindow.showAsDropDown(binding.rightImageView, x, 1.dp2px(context))
            }
        }

        samplePopupWindow.setOnPopupWindowClickListener(object :
            SamplePopupWindow.OnPopupWindowClickListener {
            override fun onPopupItemClicked(position: Int) {
                when (position) {
                    0 -> updateLabels()
                    1 -> downloadTask()
                    2 -> navigatePageTo<VersionControlActivity>()
                    3 -> uploadEvent()
                    4 -> uploadLabel()
                }
            }
        })

        //安装。上传，然后存入本地库
        binding.installButton.setOnClickListener {
            /**
             * 改为Dialog方式，避免频繁打开/关闭串口
             * */
            installDialog.show()
        }

        //查看
        binding.viewButton.setOnClickListener {
            QueryMarkerDialog.Builder().setContext(context).setTitle("查看标识器")
                .setSpinnerArray(LocaleConstant.SPINNER_ARRAY).setNegativeButton("取消")
                .setPositiveButton("确定").setOnDialogButtonClickListener(object :
                    QueryMarkerDialog.OnDialogButtonClickListener {
                    override fun onConfirmClick(selectedItem: String, value: String) {
                        //查询数据库
                        lifecycleScope.launch(Dispatchers.Main) {
                            labelBeans = withContext(Dispatchers.IO) {
                                DataBaseManager.get.loadLabelByCondition(
                                    selectedItem, value
                                ) as ArrayList<LabelBean>
                            }

                            if (labelBeans.isEmpty()) {
                                "无法查到相关数据信息，请检查您的查询条件".show(context)
                            } else {
                                val latitudeList = ArrayList<Double>()
                                val longitudeList = ArrayList<Double>()

                                labelBeans.forEach {
                                    val latitude = it.lat
                                    val longitude = it.lng
                                    if (latitude.isNotBlank() && longitude.isNotBlank()) {
                                        if (CoordinateConverter.isAMapDataAvailable(
                                                latitude.toDouble(), longitude.toDouble()
                                            )
                                        ) {
                                            //分别缓存经、纬度
                                            latitudeList.add(latitude.toDouble())
                                            longitudeList.add(longitude.toDouble())
                                        }
                                    }
                                }

                                if (latitudeList.isNotEmpty() && longitudeList.isNotEmpty()) {
                                    //移动地图到所有labelBeans的第一个点
                                    val center = LatLng(latitudeList.first(), longitudeList.first())
                                    //移动到指定经纬度
                                    aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(center, 16f))
                                }

                                showLabelsOnMap()
                            }
                        }
                    }

                    override fun onCancelClick() {

                    }
                }).build().show()
        }

        //巡检
        binding.inspectionButton.setOnClickListener {
            val tasks = DataBaseManager.get.queryDistinctTask()
            if (tasks.isNotEmpty()) {
                val arrayList = ArrayList<String>()
                tasks.forEachIndexed { index, bean ->
                    arrayList.add("任务${index + 1}：${bean.taskId}，${bean.desc}")
                }

                BottomActionSheet.Builder().setContext(this).setItemTextColor(Color.BLUE)
                    .setActionItemTitle(arrayList)
                    .setOnActionSheetListener(object : BottomActionSheet.OnActionSheetListener {
                        override fun onActionItemClick(position: Int) {
                            task = tasks[position]
                            SaveKeyValues.putValue(LocaleConstant.TASK_ID, task.taskId)
                            AlertControlDialog.Builder()
                                .setContext(context)
                                .setTitle("提示")
                                .setMessage("请选择操作方式")
                                .setPositiveButton("执行工单")
                                .setNegativeButton("提交工单")
                                .setOnDialogButtonClickListener(object :
                                    AlertControlDialog.OnDialogButtonClickListener {
                                    override fun onConfirmClick() {
                                        val latLng = LatLng(
                                            task.lat.toDouble(), task.lng.toDouble()
                                        )
                                        aMap.moveCamera(
                                            CameraUpdateFactory.newLatLngZoom(latLng, 16f)
                                        )
                                        //执行工单
                                        uploadTask(task.taskId, "1")
                                        detectRedrawGraphic(task.taskId)
                                        isExecuteTask = true
                                    }

                                    override fun onCancelClick() {
                                        //提交工单
                                        uploadTask(task.taskId, "2")
                                        isExecuteTask = false
                                    }
                                }).build().show()
                        }
                    }).build().show()
            } else {
                AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示")
                    .setMessage("现有任务已完成，请点击右上角菜单下载新工单或者开始自由巡检")
                    .setPositiveButton("开始自由巡检").setOnDialogButtonClickListener(object :
                        AlertMessageDialog.OnDialogButtonClickListener {
                        override fun onConfirmClick() {
                            startFreeTask()
                        }
                    }).build().show()
            }
        }

        //探测
        binding.detectionButton.setOnClickListener {
            /**
             * 改为Dialog方式，避免频繁打开/关闭串口
             *
             * 如果开启自由巡检就不让探测
             * */
            if (isFreeTask) {
                AlertMessageDialog.Builder()
                    .setContext(this)
                    .setTitle("温馨提示")
                    .setMessage("正在自由巡检任务中，请完成此次任务之后再使用探测功能")
                    .setPositiveButton("好的")
                    .setOnDialogButtonClickListener(object :
                        AlertMessageDialog.OnDialogButtonClickListener {
                        override fun onConfirmClick() {

                        }
                    }).build().show()
            } else {
                searchDialog.show()
//            searchNewDialog.show()
            }
        }

        //自由巡检
        binding.stopFreeTaskButton.setOnLongClickListener {
            AlertMessageDialog.Builder().setContext(this).setTitle("温馨提示")
                .setMessage("是否确定结束此次自由巡检任务？").setPositiveButton("是")
                .setOnDialogButtonClickListener(object :
                    AlertMessageDialog.OnDialogButtonClickListener {
                    override fun onConfirmClick() {
                        isFreeTask = false
                        soundPool.autoPause()

                        //降低串口电位
                        gpioManager.setGpioLow("18")

                        binding.stopFreeTaskButton.visibility = View.GONE
                        if (taskId.isNullOrBlank()) {
                            "任务ID异常，无法提交任务，请联系服务器管理员".show(context)
                            return
                        }
                        taskViewModel.uploadTaskMarker(taskId, ids)
                    }
                }).build().show()
            true
        }
    }

    private fun startFreeTask() {
        AlertInputDialog.Builder().setContext(this).setTitle("新建自由巡检任务")
            .setHintMessage("请输入自由巡检任务简要描述").setNegativeButton("取消")
            .setPositiveButton("确定")
            .setOnDialogButtonClickListener(object : AlertInputDialog.OnDialogButtonClickListener {
                override fun onConfirmClick(value: String) {
                    val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String
                    taskViewModel.createFreeTask(userId, value)

                    //调高串口电位
                    gpioManager.setGpioHigh("18")

                    soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)
                    isFreeTask = true
                    //自由巡检
                    signalTask = object : TimerTask() {
                        override fun run() {
                            out.write('2'.code)
                            out.flush()
                        }
                    }
                    searchMarkerTimer = Timer()
                    searchMarkerTimer?.apply {
                        schedule(signalTask, 0, 100)
                    }

                    binding.stopFreeTaskButton.visibility = View.VISIBLE
                }

                override fun onCancelClick() {}
            }).build().show()
    }

    override fun onDataReceived(buffer: ByteArray) {
        val hex = buffer.toHex()
        Log.d(kTag, "$kTag => $hex")
        if (searchDialog.isDetectMarker) {
            searchDialog.bindingValue(hex)
        } else if (searchNewDialog.isDetectMarker) {
            searchNewDialog.bindingValue(hex)
        } else if (installDialog.isReadMarker) {
            val markerId = hex.take(20).hexToString()
            if (markerId.isNumber()) {
                installDialog.bindingValue(markerId)
            }
        } else if (isFreeTask) {
            val markerId = hex.take(20).hexToString()
            if (markerId.isNumber()) {
                "标识器${markerId}已探测".show(this)
                ids.add(markerId)
            }
        }
    }

    override fun observeRequestState() {
        taskViewModel.loadState.observe(this) {
            when (it) {
                LoadState.Loading -> {
                    if (installDialog.isInstallMarker) {
                        LoadingDialogHub.show(this, "标识器安装中，请稍后...")
                    } else if (searchDialog.isDetectMarker) {
                        searchDialog.taskBean?.apply {
                            "标识器${this.markerRealId}已探测！".show(context)
                            DataBaseManager.get.updateTaskLabel(this)
                        }
                    } else {
                        LoadingDialogHub.show(this, "提交工单中，请稍后")
                    }
                }

                else -> {
                    if (installDialog.isInstallMarker) {
                        installDialog.dismiss()
                    }

                    if (searchDialog.isDetectMarker) {
                        searchDialog.taskBean?.apply {
                            detectRedrawGraphic(taskId)
                        }
                    }

                    LoadingDialogHub.dismiss()
                }
            }
        }
    }

    private fun initMapConfig(savedInstanceState: Bundle?) {
        binding.mapView.onCreate(savedInstanceState)
        aMap = binding.mapView.map

        val uiSettings = aMap.uiSettings
        uiSettings.isCompassEnabled = true
        uiSettings.isMyLocationButtonEnabled = false//不显示默认定位按钮
        uiSettings.isScaleControlsEnabled = true
        uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
        uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
        uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜
        //显示定位小蓝点
        val locationStyle = MyLocationStyle()
        locationStyle.interval(2000)
        locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0))
        locationStyle.strokeColor(Color.argb(0, 0, 0, 0))
        locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER)//定位、但不会移动到地图中心点，定位点依照设备方向旋转，并且会跟随设备移动。
        aMap.myLocationStyle = locationStyle//设置定位蓝点的Style
        aMap.isMyLocationEnabled = true//设置是否显示定位小蓝点
        aMap.setOnMyLocationChangeListener {
            longitude = it.longitude
            latitude = it.latitude
            //经纬度逆编码
            locationHub.antiCodingLocation(it) { address ->
                binding.currentLocationView.text = address
            }
        }

        //首次移动到定位点
        moveToCurrentLocation()

        aMap.setOnMapLongClickListener {
            //协程异步显示默认数据
            lifecycleScope.launch(Dispatchers.Main) {
                labelBeans = withContext(Dispatchers.IO) {
                    DataBaseManager.get.loadTaskLabels() as ArrayList<LabelBean>
                }
                showLabelsOnMap()
            }
        }

        //自定义定位按钮
        binding.aimButton.setOnClickListener { moveToCurrentLocation() }
    }

    private fun moveToCurrentLocation() {
        locationHub.getCurrentLocation(true, object : ILocationListener {
            override fun onAMapLocationGet(location: AMapLocation?) {
                if (location != null) {
                    aMap.moveCamera(
                        CameraUpdateFactory.newLatLngZoom(
                            LatLng(location.latitude, location.longitude), 16f
                        )
                    )
                } else {
                    "当前位置信号差，无法移动地图到定位点".show(context)
                }
            }
        })
    }

    private fun saveTaskInformation(it: TaskModel) {
        val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "") as String
        if (it.message.size > 0) {
            it.message.forEach { messageModel ->
                val count = DataBaseManager.get.countTaskById(messageModel.id.toString())
                if (count == 0) {
                    messageModel.taskDetailInfos.forEach { info ->
                        DataBaseManager.get.insertTaskInformation(
                            userName,
                            messageModel.description,
                            info.taskId.toString(),
                            info.id.toString(),
                            info.markerId.toString(),
                            info.markerIdReal.toString(),
                            info.longitude.toString(),
                            info.latitude.toString(),
                            messageModel.status
                        )
                    }
                }
            }
            "工单下载成功！".show(context)
        }
    }

    private fun showLabelsOnMap() {
        clusterOverlay?.onDestroy()
        val clusterItems = ArrayList<ClusterItem>()

        labelBeans.forEach {
            if (it.lat.isNotEmpty() && it.lng.isNotEmpty()) {
                val latitude = it.lat.toDouble()
                val longitude = it.lng.toDouble()

                val latLng = LatLng(latitude, longitude, false)
                val regionItem = RegionItem(latLng, it.id.toString())
                clusterItems.add(regionItem)
            }
        }

        clusterOverlay = ClusterOverlay(context, aMap, clusterItems, regionRadius)
        clusterOverlay?.setClusterRender { clusterNum ->
            val radius = 80.dp2px(context)
            if (clusterNum == 0) {
                var bitmapDrawable = backDrawables[0]
                if (bitmapDrawable == null) {
                    bitmapDrawable = BitmapDrawable(
                        null, radius.drawCircle(Color.argb(159, 100, 149, 237))
                    )
                    backDrawables[0] = bitmapDrawable
                }
                bitmapDrawable
            }
            if (clusterNum == 1) {
                var bitmapDrawable = backDrawables[1]
                if (bitmapDrawable == null) {
                    bitmapDrawable = R.mipmap.label.convertDrawable(this)!!
                    backDrawables[1] = bitmapDrawable
                }
                bitmapDrawable
            } else if (clusterNum < 5) {
                var bitmapDrawable = backDrawables[2]
                if (bitmapDrawable == null) {
                    bitmapDrawable = BitmapDrawable(
                        null, radius.drawCircle(Color.argb(159, 100, 149, 237))
                    )
                    backDrawables[2] = bitmapDrawable
                }
                bitmapDrawable
            } else if (clusterNum < 10) {
                var bitmapDrawable = backDrawables[3]
                if (bitmapDrawable == null) {
                    bitmapDrawable = BitmapDrawable(
                        null, radius.drawCircle(Color.argb(199, 30, 144, 255))
                    )
                    backDrawables[3] = bitmapDrawable
                }
                bitmapDrawable
            } else {
                var bitmapDrawable = backDrawables[4]
                if (bitmapDrawable == null) {
                    bitmapDrawable = BitmapDrawable(
                        null, radius.drawCircle(Color.argb(235, 65, 105, 225))
                    )
                    backDrawables[4] = bitmapDrawable
                }
                bitmapDrawable
            }
        }
        clusterOverlay?.setOnClusterClickListener { _, items ->
            var item: RegionItem? = null
            val builder = LatLngBounds.Builder()
            for (clusterItem in items) {
                builder.include(clusterItem.position)
                item = clusterItem as RegionItem
            }

            if (item == null) {
                "标识器经纬度异常".show(context)
                return@setOnClusterClickListener
            }

            val latLng = LatLng(item.position.latitude, item.position.longitude)

            //移动视图
            val latLngBounds = builder.build()
            aMap.animateCamera(CameraUpdateFactory.newLatLngBounds(latLngBounds, 0))

            AlertControlDialog.Builder().setContext(this).setTitle("提示")
                .setMessage("请选择操作方式").setNegativeButton("标识器信息")
                .setPositiveButton("到这里去").setOnDialogButtonClickListener(object :
                    AlertControlDialog.OnDialogButtonClickListener {
                    override fun onConfirmClick() {
                        RouteOnMap.startNavigation(context, item.title, latLng)
                    }

                    override fun onCancelClick() {
                        labelBeans.forEach {
                            if (it.id.toString() == item.title) {
                                navigatePageTo<ObjectDetailActivity>(it.toJson())
                            }
                        }
                    }
                }).build().show()
        }
    }

    private fun detectRedrawGraphic(taskId: String) {
        val tasks = DataBaseManager.get.queryTaskById(taskId)
        if (tasks.isNotEmpty()) {
            tasks.forEach {
                val latLng = LatLng(it.lat.toDouble(), it.lng.toDouble())
                val otMarkerOptions = MarkerOptions()
                otMarkerOptions.position(latLng)
                otMarkerOptions.visible(true) // 设置可见
                if (it.state == "未开始") {
                    otMarkerOptions.icon(
                        BitmapDescriptorFactory.fromBitmap(
                            BitmapFactory.decodeResource(resources, R.mipmap.label_red1)
                        )
                    ).period(99).title("工单标识器").snippet(it.markerId)
                } else {
                    otMarkerOptions.icon(
                        BitmapDescriptorFactory.fromBitmap(
                            BitmapFactory.decodeResource(resources, R.mipmap.label_blue1)
                        )
                    ).period(99).title("工单标识器").snippet(it.markerId)
                }
                aMap.addMarker(otMarkerOptions)
            }
        }
        showLabelsOnMap()
    }

    private fun uploadTask(taskId: String?, state: String) {
        if (isNetworkConnected()) {
            val userId = SaveKeyValues.getValue(LocaleConstant.USER_ID, "") as String
            taskViewModel.uploadTask(userId, taskId, state)
        } else {
            "网络连接已断开，请检查".show(this)
        }
    }

    //更新数据
    private fun updateLabels() {
        AlertControlDialog.Builder().setContext(this).setTitle("提示").setMessage("是否更新数据？")
            .setNegativeButton("取消").setPositiveButton("确定")
            .setOnDialogButtonClickListener(object :
                AlertControlDialog.OnDialogButtonClickListener {
                override fun onConfirmClick() {
                    if (isNetworkConnected()) {
                        val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "")

                        LoadingDialogHub.show(this@MainActivity, "获取标识器信息中，请稍后")
                        /**
                         * 后台设计如此，都传companyId
                         * */
                        taskViewModel.getMarkerFile(companyId.toString(), companyId.toString())
                    } else {
                        "网络连接已断开，请检查".show(context)
                    }
                }

                override fun onCancelClick() {

                }
            }).build().show()
    }

    //下载工单
    private fun downloadTask() {
        if (isNetworkConnected()) {
            val userName = SaveKeyValues.getValue(LocaleConstant.USER_NAME, "")
            taskViewModel.getTask(userName.toString())
        } else {
            "网络连接已断开，请检查".show(this)
        }
    }

    private fun uploadEvent() {
        val taskId = SaveKeyValues.getValue(LocaleConstant.TASK_ID, "") as String
        if (taskId.isBlank()) {
            "已完成全部巡检".show(this)
            return
        }
        if (latitude != 0.0 && longitude != 0.0) {
            navigatePageTo<UploadEventActivity>()
        } else {
            "定位中，请稍后再试...".show(this)
        }
    }

    //标识器补全
    private fun uploadLabel() {
        val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
        val labelBeans = DataBaseManager.get.queryLabelById("0")
        if (labelBeans.isNotEmpty()) {
            LoadingDialogHub.show(this, "标识器补全中，请稍后...")
            labelBeans.forEach { labelBean ->
                val imagePaths = gson.fromJson<ArrayList<String>>(
                    labelBean.imagePath, object : TypeToken<ArrayList<String>>() {}.type
                )

                taskViewModel.installLabel(
                    companyId,
                    labelBean.objectType,
                    labelBean.pipelineType,
                    labelBean.pipelineMaterial,
                    labelBean.pipelineDiameter,
                    labelBean.buryDeep,
                    labelBean.lowerType,
                    labelBean.lowerMaterial,
                    labelBean.lowerDiameter,
                    labelBean.lowerDeep,
                    labelBean.buryMethod,
                    labelBean.area,
                    labelBean.line,
                    labelBean.road,
                    labelBean.constructTime,
                    labelBean.owner,
                    labelBean.objectId,
                    labelBean.identifierId,
                    labelBean.identifierType,
                    labelBean.identifierDeep,
                    labelBean.person,
                    labelBean.installTime,
                    labelBean.lng,
                    labelBean.lat,
                    labelBean.color,
                    labelBean.remark,
                    imagePaths
                )
            }
            LoadingDialogHub.dismiss()
        } else {
            "没有需要补传的标识器！".show(this)
        }
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        return if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (System.currentTimeMillis() - clickTime > 2000) {
                "再按一次退出程序".show(this)
                clickTime = System.currentTimeMillis()
                true
            } else {
                super.onKeyDown(keyCode, event)
            }
        } else super.onKeyDown(keyCode, event)
    }

    /***以下是地图生命周期管理************************************************************************/

    override fun onResume() {
        super.onResume()
        binding.mapView.onResume()
        //协程异步显示默认数据
        lifecycleScope.launch(Dispatchers.Main) {
            labelBeans = withContext(Dispatchers.IO) {
                DataBaseManager.get.loadTaskLabels() as ArrayList<LabelBean>
            }
            showLabelsOnMap()
        }
    }

    override fun onPause() {
        super.onPause()
        binding.mapView.onPause()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        binding.mapView.onSaveInstanceState(outState)
    }

    override fun onDestroy() {
        super.onDestroy()
        binding.mapView.onDestroy()
        signalTask?.cancel()
        searchMarkerTimer?.cancel()
        soundPool.release()
        locationHub.stopLocation()
        //降低串口电位
        gpioManager.setGpioLow("18")
    }

    /**安装标识器对话框******************************************************************************/
    inner class InstallMarkerDialog(context: Context) : Dialog(context) {

        private val binding: DialogInstallMarkerBinding by binding()
        private val calendar by lazy { Calendar.getInstance() }
        private val realPaths = ArrayList<String>() //真实图片路径
        private lateinit var imageAdapter: EditableImageAdapter
        private lateinit var countDownTimer: CountDownTimer

        var isReadMarker = false
        var isInstallMarker = false

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            this.initDialogLayoutParams(1f)

            //初始化数据
            initDefaultData()

            //返回
            binding.titleInclude.leftBackView.setOnClickListener {
                soundPool.autoPause()
                dismiss()
            }

            //安装
            binding.installButton.setOnClickListener {
                val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String
                val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String
                if (binding.objectInclude.markerObjectTypeView.text.isNullOrBlank()) {
                    when (binding.objectInclude.objectTypeSpinner.selectedItem.toString()) {
                        "管线" -> "请输入管线种类！".show(context)
                        "管线附属物" -> "请输入附属物名称！".show(context)
                        "管线特征管点" -> "请输入特征管点！".show(context)
                        "交叉穿越点" -> "请输入上层管种类！".show(context)
                    }
                    return@setOnClickListener
                }

                if (binding.objectInclude.pipelineDiameterView.text.isNullOrBlank()) {
                    "请输入管径".show(context)
                    return@setOnClickListener
                }

                if (binding.objectInclude.buryDeepView.text.isNullOrBlank()) {
                    "请输入埋深".show(context)
                    return@setOnClickListener
                }

                if (binding.objectInclude.downPipeDiameterView.text.isNullOrBlank()) {
                    "请输入下层管管径".show(context)
                    return@setOnClickListener
                }

                if (binding.objectInclude.areaView.text.isNullOrBlank()) {
                    "请输入所属区域".show(context)
                    return@setOnClickListener
                }

                if (binding.objectInclude.lineView.text.isNullOrBlank()) {
                    "请输入所属线路".show(context)
                    return@setOnClickListener
                }

                if (binding.objectInclude.roadView.text.isNullOrBlank()) {
                    "请输入所属道路".show(context)
                    return@setOnClickListener
                }

                if (binding.objectInclude.constructDateView.text.isNullOrBlank()) {
                    "请选择建设年代".show(context)
                    return@setOnClickListener
                }

                if (binding.objectInclude.ownerView.text.isNullOrBlank()) {
                    "请输入权属单位".show(context)
                    return@setOnClickListener
                }

                if (binding.identifierInclude.identifierIdView.text.isNullOrBlank()) {
                    "请先读取标识器获取ID".show(context)
                    return@setOnClickListener
                }

                if (binding.identifierInclude.identifierDeepView.text.isNullOrBlank()) {
                    "请输入标识器埋深".show(context)
                    return@setOnClickListener
                }

                if (binding.identifierInclude.personDeptView.text.isNullOrBlank()) {
                    "请输入标识器安装部门".show(context)
                    return@setOnClickListener
                }

                //先存本地再上传服务器
                saveLabelInLocal()

                isInstallMarker = true
                taskViewModel.installLabel(
                    companyId,
                    binding.objectInclude.objectTypeSpinner.selectedItem.toString().toObjectType(),
                    binding.objectInclude.markerObjectTypeView.text.toString(),
                    binding.objectInclude.materialSpinner.selectedItem.toString(),
                    "${binding.objectInclude.pipelineDiameterView.text}mm",
                    "${binding.objectInclude.buryDeepView.text}mm",
                    binding.objectInclude.downPipeTypeSpinner.selectedItem.toString(),
                    binding.objectInclude.downPipeMaterialSpinner.selectedItem.toString(),
                    "${binding.objectInclude.downPipeDiameterView.text}mm",
                    "${binding.objectInclude.downPointDeepView.text}mm",
                    binding.objectInclude.buryMethodSpinner.selectedItem.toString(),
                    binding.objectInclude.areaView.text.toString(),
                    binding.objectInclude.lineView.text.toString(),
                    binding.objectInclude.roadView.text.toString(),
                    binding.objectInclude.constructDateView.text.toString(),
                    binding.objectInclude.ownerView.text.toString(),
                    objectId,
                    binding.identifierInclude.identifierIdView.text.toString(),
                    binding.identifierInclude.identifierTypeSpinner.selectedItem.toString(),
                    "${binding.identifierInclude.identifierDeepView.text}mm",
                    binding.identifierInclude.personDeptView.text.toString(),
                    binding.identifierInclude.installTimeView.text.toString(),
                    binding.identifierInclude.lngView.text.toString(),
                    binding.identifierInclude.latView.text.toString(),
                    binding.identifierInclude.colorSpinner.selectedItem.toString().toColor(),
                    binding.remarkView.text.toString(),
                    realPaths
                )

                //保存默认值
                "markerObjectTypeView".setDefaultValue(binding.objectInclude.markerObjectTypeView.text.toString())
                "pipelineDiameterView".setDefaultValue(binding.objectInclude.pipelineDiameterView.text.toString())
                "buryDeepView".setDefaultValue(binding.objectInclude.buryDeepView.text.toString())
                "downPipeDiameterView".setDefaultValue(binding.objectInclude.downPipeDiameterView.text.toString())
                "downPointDeepView".setDefaultValue(binding.objectInclude.downPointDeepView.text.toString())
                "areaView".setDefaultValue(binding.objectInclude.areaView.text.toString())
                "lineView".setDefaultValue(binding.objectInclude.lineView.text.toString())
                "roadView".setDefaultValue(binding.objectInclude.roadView.text.toString())
                "ownerView".setDefaultValue(binding.objectInclude.ownerView.text.toString())
                "identifierDeepView".setDefaultValue(binding.identifierInclude.identifierDeepView.text.toString())
                "personDeptView".setDefaultValue(binding.identifierInclude.personDeptView.text.toString())
            }

            //读标识器
            binding.readMarkerButton.setOnClickListener {
                LoadingDialogHub.show(this@MainActivity, "标识器读取中，请稍后...")
                binding.readMarkerButton.isEnabled = false

                isReadMarker = true

                //调高串口电位
                gpioManager.setGpioHigh("18")

                soundPool.play(soundResourceId, 1f, 1f, 0, -1, 1f)

                out.write('2'.code)
                out.flush()

                countDownTimer = object : CountDownTimer(5 * 1000, 1000) {
                    override fun onTick(millisUntilFinished: Long) {

                    }

                    override fun onFinish() {
                        LoadingDialogHub.dismiss()
                        soundPool.autoPause()
                        binding.readMarkerButton.isEnabled = true

                        //降低串口电位
                        gpioManager.setGpioLow("18")

                        isReadMarker = false
                        "读取此标识器ID超时，请重试".show(context)
                    }
                }
                countDownTimer.start()
            }
        }

        fun bindingValue(markerId: String) {
            LoadingDialogHub.dismiss()
            soundPool.autoPause()
            countDownTimer.cancel()
            binding.readMarkerButton.isEnabled = true

            //降低串口电位
            gpioManager.setGpioLow("18")

            isReadMarker = false
            binding.identifierInclude.identifierIdView.text = markerId
        }

        override fun dismiss() {
            //降低串口电位
            gpioManager.setGpioLow("18")
            soundPool.autoPause()
            isInstallMarker = false
            super.dismiss()
        }

        private fun initDefaultData() {
            binding.titleInclude.titleView.text = "安装新标识器"
            binding.titleInclude.titleView.setTextColor(R.color.themeColor.convertColor(context))

            imageAdapter = EditableImageAdapter(context, 3, 3)
            binding.cameraInclude.addImageRecyclerView.adapter = imageAdapter

            //设置默认值
            binding.objectInclude.markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue())
            binding.objectInclude.pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue())
            binding.objectInclude.buryDeepView.setText("buryDeepView".getDefaultValue())
            binding.objectInclude.downPipeDiameterView.setText("downPipeDiameterView".getDefaultValue())
            binding.objectInclude.downPointDeepView.setText("downPointDeepView".getDefaultValue())
            binding.objectInclude.areaView.setText("areaView".getDefaultValue())
            binding.objectInclude.lineView.setText("lineView".getDefaultValue())
            binding.objectInclude.roadView.setText("roadView".getDefaultValue())
            binding.objectInclude.ownerView.setText("ownerView".getDefaultValue())
            binding.identifierInclude.identifierDeepView.setText("identifierDeepView".getDefaultValue())
            binding.identifierInclude.personDeptView.setText("personDeptView".getDefaultValue())

            /**************************************************************************************/
            binding.objectInclude.objectTypeSpinner.show(
                this@MainActivity, LocaleConstant.POINT_TYPE_ARRAY, 0
            )
            binding.objectInclude.materialSpinner.show(
                this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
            )
            binding.objectInclude.downPipeTypeSpinner.show(
                this@MainActivity, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 0
            )
            binding.objectInclude.downPipeMaterialSpinner.show(
                this@MainActivity, LocaleConstant.PIPE_MATERIAL_ARRAY, 0
            )
            binding.objectInclude.buryMethodSpinner.show(
                this@MainActivity, LocaleConstant.BURY_METHOD_ARRAY, 0
            )

            binding.objectInclude.constructDateView.setOnClickListener {
                val datePicker = DatePickerDialog(
                    context,
                    null,
                    calendar.get(Calendar.YEAR),
                    calendar.get(Calendar.MONTH),
                    calendar.get(Calendar.DAY_OF_MONTH)
                )
                datePicker.show()

                datePicker.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
                    val year = datePicker.datePicker.year
                    val month = datePicker.datePicker.month + 1
                    val day = datePicker.datePicker.dayOfMonth
                    val selectedDate = String.format(
                        "%s-%s-%s", year, month.appendZero(), day.appendZero()
                    )

                    //当前时间
                    val current = System.currentTimeMillis().timestampToTime()
                    val today = "$selectedDate $current".dateToTimestamp()
                    if (Date(today).after(Date())) {
                        "建设年代不能早于当前日期".show(context)
                    } else {
                        datePicker.dismiss()
                        binding.objectInclude.constructDateView.text = selectedDate
                    }
                }
            }

            binding.identifierInclude.identifierTypeSpinner.show(
                this@MainActivity, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0
            )

            binding.identifierInclude.installTimeView.text =
                System.currentTimeMillis().timestampToCompleteDate()
            locationHub.getCurrentLocation(true, object : ILocationListener {
                override fun onAMapLocationGet(location: AMapLocation?) {
                    if (location != null) {
                        binding.identifierInclude.lngView.text = location.longitude.toString()
                        binding.identifierInclude.latView.text = location.latitude.toString()
                    } else {
                        "当前位置信号差，无法获取定位".show(context)
                    }
                }
            })

            binding.identifierInclude.colorSpinner.show(
                this@MainActivity, LocaleConstant.COLOR_ARRAY, 0
            )

            imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener {
                override fun onAddImageClick() {
                    takePicture()
                }

                override fun onItemClick(position: Int) {
                    if (realPaths[position].isEmpty()) {
                        "图片加载失败，无法查看大图".show(context)
                    } else {
                        context.navigatePageTo<BigImageActivity>(position, realPaths)
                    }
                }

                override fun onItemLongClick(view: View?, position: Int) {
                    imageAdapter.deleteImage(position)
                }
            })
            /**************************************************************************************/
        }

        private fun saveLabelInLocal() {
            val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String

            val labelBean = LabelBean()
            labelBean.objectType = binding.objectInclude.objectTypeSpinner.selectedItem.toString()
            labelBean.pipelineType = binding.objectInclude.markerObjectTypeView.text.toString()
            labelBean.pipelineMaterial =
                binding.objectInclude.materialSpinner.selectedItem.toString()
            labelBean.pipelineDiameter = "${binding.objectInclude.pipelineDiameterView.text}mm"
            labelBean.buryDeep = "${binding.objectInclude.buryDeepView.text}mm"
            labelBean.lowerType = binding.objectInclude.downPipeTypeSpinner.selectedItem.toString()
            labelBean.lowerMaterial =
                binding.objectInclude.downPipeMaterialSpinner.selectedItem.toString()
            labelBean.lowerDiameter = "${binding.objectInclude.downPipeDiameterView.text}mm"
            labelBean.lowerDeep = "${binding.objectInclude.downPointDeepView.text}mm"
            labelBean.buryMethod = binding.objectInclude.buryMethodSpinner.selectedItem.toString()
            labelBean.area = binding.objectInclude.areaView.text.toString()
            labelBean.line = binding.objectInclude.lineView.text.toString()
            labelBean.road = binding.objectInclude.roadView.text.toString()
            labelBean.constructTime = binding.objectInclude.constructDateView.text.toString()
            labelBean.owner = binding.objectInclude.ownerView.text.toString()
            labelBean.objectId = objectId
            labelBean.identifierId = binding.identifierInclude.identifierIdView.text.toString()
            labelBean.identifierType =
                binding.identifierInclude.identifierTypeSpinner.selectedItem.toString()
            labelBean.identifierDeep = "${binding.identifierInclude.identifierDeepView.text}mm"
            labelBean.person = binding.identifierInclude.personDeptView.text.toString()
            labelBean.installTime = binding.identifierInclude.installTimeView.text.toString()
            labelBean.lng = binding.identifierInclude.lngView.text.toString()
            labelBean.lat = binding.identifierInclude.latView.text.toString()
            labelBean.color =
                binding.identifierInclude.colorSpinner.selectedItem.toString().toColor()
            labelBean.remark = binding.remarkView.text.toString()
            labelBean.imagePath = realPaths.toJson()

            DataBaseManager.get.insertTaskLabel(labelBean)
        }

        private fun takePicture() {
            PictureSelector.create(this@MainActivity).openCamera(SelectMimeType.ofImage())
                .forResult(object : OnResultCallbackListener<LocalMedia> {
                    override fun onResult(result: java.util.ArrayList<LocalMedia>?) {
                        if (result == null) {
                            "拍照失败，请重试".show(context)
                            return
                        }
                        analyticalSelectResults(result[0])
                    }

                    override fun onCancel() {

                    }
                })
        }

        private fun analyticalSelectResults(result: LocalMedia) {
            //压缩图片
            result.realPath.compressImage(context, object : OnImageCompressListener {
                override fun onSuccess(file: File) {
                    realPaths.add(file.absolutePath)
                    imageAdapter.setupImage(realPaths)
                }

                override fun onError(e: Throwable) {
                    e.printStackTrace()
                }
            })
        }
    }

    /**探测标识器对话框******************************************************************************/
    inner class SearchMarkerDialog(context: Context) : Dialog(context) {

        private val binding: DialogSearchMarkerBinding by binding()
        private val decimal by lazy { DecimalFormat("0.0") }
        private val degreeCache by lazy { HashMap<String, Float>() }
        private var isPlaying = false
        private var markerId = ""
        private lateinit var searchMarkerTimer: Timer
        private lateinit var signalTask: TimerTask
        private lateinit var energyTask: TimerTask
        private lateinit var countDownTimer: CountDownTimer

        var isDetectMarker = false
        var taskBean: TaskBean? = null

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            this.initDialogLayoutParams(1f)
            binding.depthButton.setOnClickListener {
                signalTask.cancel()
                energyTask.cancel()
                searchMarkerTimer.cancel()

                out.write('3'.code)
                val result = DataBaseManager.get.queryLabelById(markerId)
                if (result.isNotEmpty()) {
                    val tag = when (result.first().identifierType) {
                        "EM30" -> '7'
                        "EM50" -> '8'
                        "EM14" -> '9'
                        else -> '1'
                    }
                    if (tag == '1') {
                        "此标识器无法读取埋深！".show(context)
                    } else {
                        // 发送读取标识器埋设深度指令
                        LoadingDialogHub.show(this@MainActivity, "正在测距，请稍后...")
                        out.write(tag.code)
                        out.flush()
                        countDownTimer = object : CountDownTimer(15 * 1000, 1000) {
                            override fun onTick(millisUntilFinished: Long) {

                            }

                            override fun onFinish() {
                                LoadingDialogHub.dismiss()
                                "探测此标识器深度超时，请重试".show(context)
                                initTimer()
                            }
                        }
                        countDownTimer.start()
                    }
                } else {
                    "标识器未安装，安装成功后才可读取埋深！".show(context)
                }
            }

            binding.markerInfoButton.setOnClickListener {
                //查库
                val result = DataBaseManager.get.queryLabelById(markerId)
                if (result.isNotEmpty()) {
                    context.navigatePageTo<ObjectDetailActivity>(result.first().toJson())
                } else {
                    context.navigatePageTo<NewObjectDetailActivity>(markerId)
                }
            }
        }

        override fun onStart() {
            super.onStart()
            //调高串口电位
            gpioManager.setGpioHigh("18")

            initTimer()

            isDetectMarker = true

            //角度
            degreeCache["lastDegree"] = 0f

            if (isExecuteTask) {
                binding.taskStateView.visibility = View.GONE
                binding.taskStateView.isSelected = false
            } else {
                binding.taskStateView.visibility = View.VISIBLE
                binding.taskStateView.isSelected = true
            }
        }

        fun bindingValue(hex: String) {
            if (hex.startsWith("4E")) {
                try {
                    //4E转为String为N，代表能量值
                    //用能量值转动表盘
                    val energyResponse = hex.take(10).hexToString()
                    val energy = energyResponse.substring(1).toInt()
                    if (energy >= 4000) {
                        isPlaying = if (!isPlaying) {
                            soundPool.play(fastSoundResourceId, 1f, 1f, 0, 0, 1f)
                            true
                        } else {
                            soundPool.pause(fastSoundResourceId)
                            false
                        }
                    } else {
                        isPlaying = if (!isPlaying) {
                            soundPool.play(slowSoundResourceId, 1f, 1f, 0, 0, 1f)
                            true
                        } else {
                            soundPool.pause(slowSoundResourceId)
                            false
                        }
                    }

                    binding.resultTextView.text = "信号能量值：${energyResponse}"

                    //转换为转动的角度
                    val degree = (energy.toFloat() / (50 * 100)) * 180
                    binding.energyValueView.text = decimal.format(degree)

                    degreeCache["lastDegree"]?.apply {
                        val animation = RotateAnimation(
                            this,
                            degree,
                            Animation.RELATIVE_TO_SELF,
                            0.5f,
                            Animation.RELATIVE_TO_SELF,
                            0.5f
                        )
                        animation.duration = 0
                        animation.fillAfter = true
                        binding.needleView.startAnimation(animation)
                    }

                    //保存旋转后的角度
                    degreeCache["lastDegree"] = degree

                    if (energy <= 700) {//18°
                        binding.energyTipsView.text = "标识器信号较弱，可能距离较远"
                        binding.energyTipsView.setTextColor(Color.parseColor("#8D1717"))
                        binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_red)

                        binding.depthButton.isEnabled = false
                        binding.depthButton.setTextColor(Color.parseColor("#CCCCCC"))
                        binding.depthButton.setBackgroundResource(R.mipmap.left_button_disable)
                        binding.markerInfoButton.isEnabled = false
                        binding.markerInfoButton.setTextColor(Color.parseColor("#CCCCCC"))
                        binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_disable)

                        binding.searchResultView.text = "未检测到标识器"
                        binding.searchResultView.setTextColor(Color.parseColor("#8D1717"))
                        binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_red)
                    } else if (energy >= 4100) {//148°
                        binding.energyTipsView.text = "标识器信号极强，可能在正下方"
                        binding.energyTipsView.setTextColor(Color.parseColor("#428d00"))
                        binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green)
                    } else {//[18°,148°]
                        binding.energyTipsView.text = "已靠近标识器，请继续移动位置"
                        binding.energyTipsView.setTextColor(Color.parseColor("#8C5700"))
                        binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_yellow)
                    }
                } catch (e: NumberFormatException) {
                    e.printStackTrace()
                }
            } else if (hex.startsWith("53")) {
                LoadingDialogHub.dismiss()
                countDownTimer.cancel()
                try {
                    val depthResponse = hex.take(10).hexToString()
                    val depth = depthResponse.drop(2).toInt()
                    AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示")
                        .setMessage("标识器埋深：${depth}厘米").setPositiveButton("知道了")
                        .setOnDialogButtonClickListener(object :
                            AlertMessageDialog.OnDialogButtonClickListener {
                            override fun onConfirmClick() {
                                initTimer()
                            }
                        }).build().show()
                } catch (e: NumberFormatException) {
                    e.printStackTrace()
                }
            } else {
                val id = hex.take(20).hexToString()
                if (id.isNumber()) {
                    markerId = id

                    binding.depthButton.isEnabled = true
                    binding.depthButton.setTextColor(Color.WHITE)
                    binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable)
                    binding.markerInfoButton.isEnabled = true
                    binding.markerInfoButton.setTextColor(Color.WHITE)
                    binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_enable)

                    binding.searchResultView.text = "已检测到标识器"
                    binding.searchResultView.setTextColor(Color.parseColor("#428d00"))
                    binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green)

                    //工单开始后才自动上传标识器
                    if (isExecuteTask) {
                        taskBean = DataBaseManager.get.queryTaskMarkerById(markerId, "未开始")
                        taskBean?.apply {
                            /**
                             * 此taskCode是 [com.casic.detector.model.TaskModel.MessageModel.TaskDetailInfosModel] 里面的主键，也就是这个标签在数据库里面的主键
                             * */
                            taskViewModel.uploadMarker(taskCode)
                        }
                    }
                }
            }
        }

        private fun initTimer() {
            searchMarkerTimer = Timer()

            signalTask = object : TimerTask() {
                override fun run() {
                    out.write('2'.code)
                    out.flush()
                }
            }

            energyTask = object : TimerTask() {
                override fun run() {
                    out.write('6'.code)
                    out.flush()
                }
            }

            //错开信号和能量定时器
            searchMarkerTimer.schedule(signalTask, 0, 201)
            searchMarkerTimer.schedule(energyTask, 0, 251)
        }

        override fun dismiss() {
            signalTask.cancel()
            energyTask.cancel()
            searchMarkerTimer.cancel()
            //降低串口电位
            gpioManager.setGpioLow("18")
            isDetectMarker = false
            soundPool.autoPause()
            super.dismiss()
        }
    }

    /**探测标识器新对话框****************************************************************************/
    inner class SearchMarkerNewDialog(context: Context) : Dialog(context) {

        private val binding: DialogSearchMarkerNewBinding by binding()
        private var isPlaying = false
        private var markerId = ""
        private lateinit var searchMarkerTimer: Timer
        private lateinit var signalTask: TimerTask
        private lateinit var energyTask: TimerTask
        private lateinit var countDownTimer: CountDownTimer

        var isDetectMarker = false

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            this.initDialogLayoutParams(1f)
            binding.depthButton.setOnClickListener {
                signalTask.cancel()
                energyTask.cancel()
                searchMarkerTimer.cancel()

                out.write('3'.code)
                val result = DataBaseManager.get.queryLabelById(markerId)
                if (result.isNotEmpty()) {
                    val tag = when (result.first().identifierType) {
                        "EM30" -> '7'
                        "EM50" -> '8'
                        "EM14" -> '9'
                        else -> '1'
                    }
                    if (tag == '1') {
                        "此标识器无法读取埋深！".show(context)
                    } else {
                        // 发送读取标识器埋设深度指令
                        LoadingDialogHub.show(this@MainActivity, "正在测距，请稍后...")
                        out.write(tag.code)
                        out.flush()
                        countDownTimer = object : CountDownTimer(15 * 1000, 1000) {
                            override fun onTick(millisUntilFinished: Long) {

                            }

                            override fun onFinish() {
                                LoadingDialogHub.dismiss()
                                "探测此标识器深度超时，请重试".show(context)
                                initTimer()
                            }
                        }
                        countDownTimer.start()
                    }
                } else {
                    "标识器未安装，安装成功后才可读取埋深！".show(context)
                }
            }

            binding.markerInfoButton.setOnClickListener {
                //查库
                val result = DataBaseManager.get.queryLabelById(markerId)
                if (result.isNotEmpty()) {
                    context.navigatePageTo<ObjectDetailActivity>(result.first().toJson())
                } else {
                    context.navigatePageTo<NewObjectDetailActivity>(markerId)
                }
            }
        }

        override fun onStart() {
            super.onStart()
            //调高串口电位
            gpioManager.setGpioHigh("18")

            initTimer()

            isDetectMarker = true
        }

        fun bindingValue(hex: String) {
            if (hex.startsWith("4E")) {
                try {
                    //4E转为String为N，代表能量值
                    //用能量值转动表盘
                    val energyResponse = hex.take(10).hexToString()
                    val energy = energyResponse.substring(1).toInt()
                    if (energy >= 4000) {
                        isPlaying = if (!isPlaying) {
                            soundPool.play(fastSoundResourceId, 1f, 1f, 0, 0, 1f)
                            true
                        } else {
                            soundPool.pause(fastSoundResourceId)
                            false
                        }
                    } else {
                        isPlaying = if (!isPlaying) {
                            soundPool.play(slowSoundResourceId, 1f, 1f, 0, 0, 1f)
                            true
                        } else {
                            soundPool.pause(slowSoundResourceId)
                            false
                        }
                    }

                    //通过设置进度条表示能量值
                    binding.energyPgBar.progress = energy
                    binding.energyValueView.text = "${energy}dB"

                    if (energy <= 700) {//18°
                        binding.energyTipsView.text = "标识器信号较弱，可能距离较远"
                        binding.energyTipsView.setTextColor(Color.parseColor("#8D1717"))
                        binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_red)

                        binding.depthButton.isEnabled = false
                        binding.depthButton.setTextColor(Color.parseColor("#CCCCCC"))
                        binding.depthButton.setBackgroundResource(R.mipmap.left_button_disable)
                        binding.markerInfoButton.isEnabled = false
                        binding.markerInfoButton.setTextColor(Color.parseColor("#CCCCCC"))
                        binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_disable)

                        binding.searchResultView.text = "未检测到标识器"
                        binding.searchResultView.setTextColor(Color.parseColor("#8D1717"))
                        binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_red)
                    } else if (energy >= 4100) {
                        binding.energyTipsView.text = "标识器信号极强，可能在正下方"
                        binding.energyTipsView.setTextColor(Color.parseColor("#428d00"))
                        binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_green)
                    } else {
                        binding.energyTipsView.text = "已靠近标识器，请继续移动位置"
                        binding.energyTipsView.setTextColor(Color.parseColor("#8C5700"))
                        binding.energyTipsView.setBackgroundResource(R.mipmap.bg_large_text_yellow)
                    }
                } catch (e: NumberFormatException) {
                    e.printStackTrace()
                }
            } else if (hex.startsWith("53")) {
                LoadingDialogHub.dismiss()
                countDownTimer.cancel()
                try {
                    val depthResponse = hex.take(10).hexToString()
                    val depth = depthResponse.drop(2).toInt()
                    AlertMessageDialog.Builder().setContext(context).setTitle("温馨提示")
                        .setMessage("标识器埋深：${depth}厘米").setPositiveButton("知道了")
                        .setOnDialogButtonClickListener(object :
                            AlertMessageDialog.OnDialogButtonClickListener {
                            override fun onConfirmClick() {
                                initTimer()
                            }
                        }).build().show()
                } catch (e: NumberFormatException) {
                    e.printStackTrace()
                }
            } else {
                val id = hex.take(20).hexToString()
                if (id.isNumber()) {
                    markerId = id

                    binding.depthButton.isEnabled = true
                    binding.depthButton.setTextColor(Color.WHITE)
                    binding.depthButton.setBackgroundResource(R.mipmap.left_button_enable)
                    binding.markerInfoButton.isEnabled = true
                    binding.markerInfoButton.setTextColor(Color.WHITE)
                    binding.markerInfoButton.setBackgroundResource(R.mipmap.right_button_enable)

                    binding.searchResultView.text = "已检测到标识器"
                    binding.searchResultView.setTextColor(Color.parseColor("#428d00"))
                    binding.searchResultView.setBackgroundResource(R.mipmap.bg_small_text_green)

                    //自动上传标识器
                    if (isExecuteTask) {
                        val taskBean = DataBaseManager.get.queryTaskMarkerById(markerId, "未开始")
                        taskBean?.apply {
                            /**
                             * 此taskCode是 [com.casic.detector.model.TaskModel.MessageModel.TaskDetailInfosModel] 里面的主键，也就是这个标签在数据库里面的主键
                             * */
                            taskViewModel.uploadMarker(taskCode)
                        }
                    }
                }
            }
        }

        private fun initTimer() {
            searchMarkerTimer = Timer()

            signalTask = object : TimerTask() {
                override fun run() {
                    out.write('2'.code)
                    out.flush()
                }
            }

            energyTask = object : TimerTask() {
                override fun run() {
                    out.write('6'.code)
                    out.flush()
                }
            }

            //错开信号和能量定时器
            searchMarkerTimer.schedule(signalTask, 0, 201)
            searchMarkerTimer.schedule(energyTask, 0, 251)
        }

        override fun dismiss() {
            signalTask.cancel()
            energyTask.cancel()
            searchMarkerTimer.cancel()
            //降低串口电位
            gpioManager.setGpioLow("18")
            isDetectMarker = false
            soundPool.autoPause()
            super.dismiss()
        }
    }
}