// appendCSVs appends any parsed kernel or powermonitor CSVs to the Historian V2 CSV.
func (pd *ParsedData) appendCSVs() error {
	// Need to append the kernel and powermonitor CSV entries to the end of the existing CSV.
	if pd.kd != nil {
		if len(pd.data) == 0 {
			return errors.New("no bug report found for the provided kernel trace file")
		}
		if len(pd.data) > 1 {
			return errors.New("kernel trace file uploaded with more than one bug report")
		}
		pd.responseArr[0].HistorianV2CSV = appendCSVs(pd.responseArr[0].HistorianV2CSV, pd.kd.csv)
		pd.data[0].Error += historianutils.ErrorsToString(pd.kd.errs)
	}

	if pd.md != nil {
		if len(pd.data) == 0 {
			return errors.New("no bug report found for the provided powermonitor file")
		}
		if len(pd.data) > 1 {
			return errors.New("powermonitor file uploaded with more than one bug report")
		}
		pd.responseArr[0].DisplayPowermonitor = true
		// Need to append the powermonitor CSV entries to the end of the existing CSV.
		pd.responseArr[0].HistorianV2CSV = appendCSVs(pd.responseArr[0].HistorianV2CSV, pd.md.csv)
		pd.data[0].Error += historianutils.ErrorsToString(pd.md.errs)
	}
	return nil
}
// Data returns a single structure (HTMLData) containing aggregated battery stats in html format.
func Data(meta *bugreportutils.MetaInfo, fname string, summaries []parseutils.ActivitySummary, checkinOutput *bspb.BatteryStats, historianOutput string, warnings []string, errs []error, overflow bool) HTMLData {
	var output []UnplugSummary
	ch := aggregated.ParseCheckinData(checkinOutput)

	for _, s := range summaries {
		duration := time.Duration(s.EndTimeMs-s.StartTimeMs) * time.Millisecond
		if duration == 0 {
			errs = append(errs, fmt.Errorf("history duration is 0"))
			continue
		}

		t := UnplugSummary{
			Date:             s.Date,
			Reason:           s.Reason,
			SummaryStart:     time.Unix(0, s.StartTimeMs*int64(time.Millisecond)).String(),
			SummaryEnd:       time.Unix(0, s.EndTimeMs*int64(time.Millisecond)).String(),
			Duration:         (time.Duration(s.EndTimeMs-s.StartTimeMs) * time.Millisecond).String(),
			LevelDrop:        int32(s.InitialBatteryLevel - s.FinalBatteryLevel),
			LevelDropPerHour: float64(s.InitialBatteryLevel-s.FinalBatteryLevel) / duration.Hours(),
			SystemStats: []DurationStats{
				internalDist{s.ScreenOnSummary}.print(hScreenOn, duration),
				internalDist{s.CPURunningSummary}.print(hCPURunning, duration),
				internalDist{s.TotalSyncSummary}.print(hTotalSync, duration),
				internalDist{s.MobileRadioOnSummary}.print(hRadioOn, duration),
				internalDist{s.PhoneCallSummary}.print(hPhoneCall, duration),
				internalDist{s.GpsOnSummary}.print(hGpsOn, duration),
				internalDist{s.WifiFullLockSummary}.print(hWifiFullLock, duration),
				internalDist{s.WifiScanSummary}.print(hWifiScan, duration),
				internalDist{s.WifiMulticastOnSummary}.print(hWifiMulticastOn, duration),
				internalDist{s.WifiOnSummary}.print(hWifiOn, duration),
				internalDist{s.WifiRunningSummary}.print(hWifiRunning, duration),
				internalDist{s.WifiRadioSummary}.print(hWifiRadio, duration),
				internalDist{s.PhoneScanSummary}.print(hPhoneScan, duration),
				internalDist{s.SensorOnSummary}.print(hSensorOn, duration),
				internalDist{s.PluggedInSummary}.print(hPluggedIn, duration),
				internalDist{s.FlashlightOnSummary}.print(hFlashlightOn, duration),
				internalDist{s.LowPowerModeOnSummary}.print(hLowPowerModeOn, duration),
				internalDist{s.AudioOnSummary}.print(hAudioOn, duration),
				internalDist{s.VideoOnSummary}.print(hVideoOn, duration),
			},
			BreakdownStats: []MultiDurationStats{
				mapPrint(hDataConnectionSummary, s.DataConnectionSummary, duration),
				mapPrint(hConnectivitySummary, s.ConnectivitySummary, duration),
				mapPrint(hPerAppSyncSummary, s.PerAppSyncSummary, duration),
				mapPrint(hWakeupReasonSummary, s.WakeupReasonSummary, duration),
				mapPrint(hFirstWakelockAfterSuspend, s.WakeLockSummary, duration),
				mapPrint(hDetailedWakelockSummary, s.WakeLockDetailedSummary, duration),
				mapPrint(hForegroundProcessSummary, s.ForegroundProcessSummary, duration),
				mapPrint(hPhoneStateSummary, s.PhoneStateSummary, duration),
				mapPrint(hScheduledJobSummary, s.ScheduledJobSummary, duration),
				mapPrint(hWifiSupplSummary, s.WifiSupplSummary, duration),
				mapPrint(hPhoneSignalStrengthSummary, s.PhoneSignalStrengthSummary, duration),
				mapPrint(hWifiSignalStrengthSummary, s.WifiSignalStrengthSummary, duration),
				mapPrint(hTopApplicationSummary, s.TopApplicationSummary, duration),
				mapPrint(hIdleModeSummary, s.IdleModeSummary, duration),
				// Disabled as they were not found to be very useful.
				/*
				   mapPrint("HealthSummary", s.HealthSummary, duration),
				   mapPrint("PlugTypeSummary", s.PlugTypeSummary, duration),
				   mapPrint("ChargingStatusSummary", s.ChargingStatusSummary, duration),
				*/
			},
		}
		output = append(output, t)
	}
	return HTMLData{
		DeviceID:        meta.DeviceID,
		SDKVersion:      meta.SdkVersion,
		DeviceModel:     meta.ModelName,
		Historian:       template.HTML(historianOutput),
		Filename:        fname,
		Count:           len(output),
		UnplugSummaries: output,
		CheckinSummary:  ch,
		Error:           historianutils.ErrorsToString(errs),
		Warning:         strings.Join(warnings, "\n"),
		AppStats:        parseAppStats(checkinOutput, meta.Sensors),
		Overflow:        overflow,
	}
}