package com.fascilityconnex.voicemobile.ui.kpi.view import android.content.Context import android.graphics.Color import android.graphics.Typeface import android.os.Build import android.os.Bundle import android.text.Spannable import android.text.SpannableString import android.text.SpannableStringBuilder import android.text.Spanned import android.text.style.* import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.annotation.RequiresApi import androidx.core.content.res.ResourcesCompat import androidx.fragment.app.viewModels import com.fascilityconnex.voicemobile.R import com.fascilityconnex.voicemobile.appstate.AppState import com.fascilityconnex.voicemobile.database.entity.HistorianDataSample import com.fascilityconnex.voicemobile.database.entity.HistorianDataSourceModel import com.fascilityconnex.voicemobile.databinding.FragmentDetailedChartBinding import com.fascilityconnex.voicemobile.network.State import com.fascilityconnex.voicemobile.network.WebServiceRequest import com.fascilityconnex.voicemobile.network.constants.DomainHelper import com.fascilityconnex.voicemobile.network.constants.WebConstant import com.fascilityconnex.voicemobile.ui.base.BaseFragment import com.fascilityconnex.voicemobile.ui.custom.CustomToast import com.fascilityconnex.voicemobile.ui.home.model.Sample import com.fascilityconnex.voicemobile.ui.home.view.MainActivity import com.fascilityconnex.voicemobile.ui.home.viewmodel.HomeViewModel import com.fascilityconnex.voicemobile.util.AppConstants import com.fascilityconnex.voicemobile.util.CommonUtil import com.fascilityconnex.voicemobile.util.DateUtil import com.scichart.charting.ClipMode import com.scichart.charting.Direction2D import com.scichart.charting.model.dataSeries.IXyDataSeries import com.scichart.charting.modifiers.* import com.scichart.charting.visuals.SciChartSurface import com.scichart.charting.visuals.axes.* import com.scichart.charting.visuals.renderableSeries.hitTest.DefaultXySeriesInfoProvider import com.scichart.charting.visuals.renderableSeries.hitTest.XySeriesInfo import com.scichart.charting.visuals.renderableSeries.tooltips.ISeriesTooltip import com.scichart.charting.visuals.renderableSeries.tooltips.XySeriesTooltip import com.scichart.core.framework.UpdateSuspender import com.scichart.core.utility.StringUtil import com.scichart.data.numerics.ResamplingMode import com.scichart.drawing.common.FontStyle import com.scichart.drawing.utility.ColorUtil import com.scichart.extensions.builders.SciChartBuilder import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.ExperimentalCoroutinesApi import java.lang.NumberFormatException import java.util.* import kotlin.collections.ArrayList @AndroidEntryPoint @ExperimentalCoroutinesApi class DetailedChartFragment : BaseFragment(), View.OnClickListener { var dataModel: HistorianDataSourceModel? = null var samplelist: ArrayList? = null private lateinit var binding: FragmentDetailedChartBinding private var startTime: String? = null private var endTime: String? = null private lateinit var dataSeries: IXyDataSeries private val oHomeViewModel: HomeViewModel by viewModels() lateinit var baseActivity: MainActivity private lateinit var mContext: Context override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) arguments?.let { dataModel = DetailedChartFragmentArgs.fromBundle(it).historianDataSourceModel } baseActivity = activity as MainActivity } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { binding = FragmentDetailedChartBinding.inflate(inflater, container, false) return binding.root } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setObserver() initializeViews() } private fun setObserver() { oHomeViewModel.reSampleLiveData.observe(viewLifecycleOwner, { state -> when (state) { is State.Loading -> { CommonUtil.changeProgressDialogMsg( baseActivity, getString(R.string.resampling) ) } is State.Success -> { CommonUtil.dismissProgressDialog() if(state.data.data.isNotEmpty()) { state.data.data[0].samples?.let { reDrawGraphWithNewData(it) } } } is State.Error -> { if (state.errorCode == WebConstant.Status.NO_INTERNET_CONNECTIVITY.status) { CommonUtil.showSimpleAlertWithDismissAction(baseActivity, state.message) CommonUtil.dismissProgressDialog() } else { CommonUtil.showSimpleAlertWithDismissAction(baseActivity, state.message) CommonUtil.dismissProgressDialog() } } } }) } private fun reDrawGraphWithNewData(samples: List) { val historianDataSample = ArrayList() if (samples.isNotEmpty()) { samples.forEachIndexed { index, sample -> val quality = sample.quality val timeStamp = sample.timeStamp val value = sample.value //some fields are missing so random values are added val historianDataSampleObj = HistorianDataSample( null, 16, 1, quality!!, null, index, timeStamp, value ) historianDataSample.add(historianDataSampleObj) } dataSeries.clear() binding.resample.visibility = View.INVISIBLE binding.imageGrid.visibility = View.INVISIBLE historianDataSample.forEachIndexed { index, data -> dataSeries.append( DateUtil.generateDateObjectFromDateTimeString(data.timeStamp), data.value.toDouble() ) } } } private fun rePositionGraph() { dataSeries.clear() binding.surfaceChart.xAxes.clear() binding.surfaceChart.yAxes.clear() binding.imageGrid.visibility = View.INVISIBLE binding.resample.visibility = View.INVISIBLE dataModel!!.historianDataId?.let { oHomeViewModel.getHistorianDataSamples(it).observe( viewLifecycleOwner, { historianDataSample -> setGraph(historianDataSample) } ) } } override fun onResume() { super.onResume() getDataSamples() } private fun getDataSamples() { dataModel!!.historianDataId?.let { oHomeViewModel.getHistorianDataSamples(it).observe( viewLifecycleOwner, { historianDataSample -> samplelist = historianDataSample as ArrayList setGraph(historianDataSample) } ) } } private fun initializeViews() { baseActivity.showInsideToolBarSingleKPIList(getString(R.string.kpi_list), false) binding.imageGrid.setOnClickListener(this) binding.resample.setOnClickListener(this) } private fun setGraph(historianDataSample: List) { val customFont: Typeface? = ResourcesCompat.getFont(baseActivity, R.font.work_sans) val dragTextFont: Typeface? = ResourcesCompat.getFont(baseActivity, R.font.abeezee_italic) val fontStyle = FontStyle(customFont, 24f, Color.WHITE, false) SciChartBuilder.init(context) val sciChartBuilder = SciChartBuilder.instance() val xAxis = DateAxis(context).apply { drawLabels = true autoFitMarginalLabels = true axisTitle = "<--drag to scroll-->" titleStyle = FontStyle( dragTextFont, 30f, Color.parseColor(getString(R.string.graph_color)), false ) tickLabelStyle = fontStyle axisAlignment = AxisAlignment.Bottom drawMajorBands = true drawMinorGridLines = false drawMajorGridLines = true textFormatting = AppConstants.GRAPH_FORMAT cursorTextFormatting = " "+AppConstants.TOOLTIP_FORMAT subDayTextFormatting = AppConstants.GRAPH_FORMAT ResamplingMode.None AutoRange.Always //minorsPerMajor = 1 //labelProvider = SciChartXAxisLabelProvider() } xAxis.setAxisTitleMargins(0, 6, 0, 0) val yAxis = NumericAxis(context).apply { drawLabels = true axisAlignment = AxisAlignment.Left drawMajorBands = false tickLabelStyle = fontStyle drawMinorGridLines = false drawMajorGridLines = true cursorTextFormatting = dataModel?.propertyName + " " ResamplingMode.None AutoRange.Always } var rolloverModifier = RolloverModifier() rolloverModifier.drawVerticalLine = false rolloverModifier.showTooltip = true rolloverModifier.showAxisLabels = false val xAxisDragModifier = XAxisDragModifier() xAxisDragModifier.dragMode = AxisDragModifierBase.AxisDragMode.Pan xAxisDragModifier.clipModeX = ClipMode.ClipAtMax xAxisDragModifier.minTouchArea=1500f xAxisDragModifier.receiveHandledEvents=true val extendZoomModifier = ZoomExtentsModifier() extendZoomModifier.direction=Direction2D.XDirection val pinchZoomModifier = PinchZoomModifier() pinchZoomModifier.direction=Direction2D.XDirection val yAxisDragModifier = YAxisDragModifier() yAxisDragModifier.dragMode = AxisDragModifierBase.AxisDragMode.Pan val dragModifiers = sciChartBuilder.newModifierGroup() .withModifier(xAxisDragModifier) .withModifier(yAxisDragModifier) .build() xAxis.setVisibleRangeChangeListener { iAxisCore, oldRange, newRange, b -> binding.imageGrid.visibility = View.VISIBLE binding.resample.visibility = View.VISIBLE setDataOnVisibleRangeChange(newRange.min.toString(), newRange.max.toString()) } dataSeries = sciChartBuilder.newXyDataSeries( Date::class.javaObjectType, Double::class.javaObjectType ).build() dataSeries.acceptsUnsortedData = true historianDataSample.forEachIndexed { index, data -> dataSeries.append( DateUtil.generateDateObjectFromDateTimeString(data.timeStamp), data.value.toDouble() ) } val rSeries = sciChartBuilder.newLineSeries().withDataSeries(dataSeries) .withSeriesInfoProvider(ToolTipInfoProvider()) .withStrokeStyle(Color.parseColor(getString(R.string.graph_color)), 1f, false).build() rSeries.resamplingMode = ResamplingMode.None UpdateSuspender.using(binding.surfaceChart) { Collections.addAll(binding.surfaceChart.xAxes, xAxis) Collections.addAll(binding.surfaceChart.yAxes, yAxis) Collections.addAll(binding.surfaceChart.renderableSeries, rSeries) Collections.addAll( binding.surfaceChart.chartModifiers, rolloverModifier, dragModifiers,pinchZoomModifier,extendZoomModifier ) } } private fun setDataOnVisibleRangeChange(fromRange: String, toRange: String) { startTime = DateUtil.getDateTimeDouble(fromRange) endTime = DateUtil.getDateTimeDouble(toRange) } override fun onClick(view: View?) { when (view?.id) { R.id.imageGrid -> { rePositionGraph() } R.id.resample -> { reSampleGraph() } } } private fun reSampleGraph() { oHomeViewModel.getKpiTagsName(dataModel?.propertyName).observe( viewLifecycleOwner, { kpiTags -> val url = DomainHelper.customerDomainDetails[DomainHelper.fcxApiKey]!! + WebConstant.GET_HISTORIAN_DATA val request = WebServiceRequest.HistorianDataRequest( rootId = AppState.userData.rootEquipmentId, lastValueQualityPeriod = 168, getLastValue = true, tagNames = kpiTags, startTime = startTime, endTime = endTime ) oHomeViewModel.getReSampleHistorianData(url, request) } ) } private class ToolTipInfoProvider : DefaultXySeriesInfoProvider() { override fun getSeriesTooltipInternal( context: Context, seriesInfo: XySeriesInfo<*>?, modifierType: Class<*> ): ISeriesTooltip { return if (modifierType == RolloverModifier::class.java) { CustomXySeriesTooltip(context, seriesInfo) } else { super.getSeriesTooltipInternal(context, seriesInfo, modifierType) } } private class CustomXySeriesTooltip(context: Context?, seriesInfo: XySeriesInfo<*>?) : XySeriesTooltip(context, seriesInfo) { override fun internalUpdate(seriesInfo: XySeriesInfo<*>) { val sb = SpannableStringBuilder() val imageSpan = ImageSpan(context, R.drawable.blue_dot) val yValue = SpannableString(" "+seriesInfo.formattedYValue) val xValue = SpannableString(seriesInfo.formattedXValue) val typeface:Typeface= Typeface.create(ResourcesCompat.getFont(context, R.font.work_sans_semibold),Typeface.NORMAL) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { xValue.setSpan(TypefaceSpan(typeface),0,xValue.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) } yValue.setSpan(imageSpan,0,1,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) // yValue.setSpan(UnderlineSpan(),0,yValue.length,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) sb.append(xValue).append(StringUtil.NEW_LINE) sb.append(yValue) text = sb //setBackgroundResource(R.color.pure_white) setTooltipBackgroundColor(ColorUtil.White) setTooltipTextColor(ColorUtil.Black) } } } }