// Normalize app data
func normalizeApp(a *bspb.BatteryStats_App, totalTimeHour float64) *bspb.BatteryStats_App {
	if a == nil {
		return nil
	}
	res := proto.Clone(a).(*bspb.BatteryStats_App)

	if norm := normalizeMessage(a.GetForeground(), totalTimeHour); norm != nil {
		res.Foreground = norm.(*bspb.BatteryStats_App_Foreground)
	}
	if norm := normalizeAppApk(a.GetApk(), totalTimeHour); norm != nil {
		res.Apk = norm
	}
	normalizeAppChildren(res.GetChild(), totalTimeHour)
	if norm := normalizeMessage(a.GetNetwork(), totalTimeHour); norm != nil {
		res.Network = norm.(*bspb.BatteryStats_App_Network)
	}
	if norm := normalizeMessage(a.GetPowerUseItem(), totalTimeHour); norm != nil {
		res.PowerUseItem = norm.(*bspb.BatteryStats_App_PowerUseItem)
	}
	if norm := normalizeRepeatedMessage(a.GetProcess(), totalTimeHour).Interface(); norm != nil {
		res.Process = norm.([]*bspb.BatteryStats_App_Process)
	}
	if norm := normalizeRepeatedMessage(a.GetSensor(), totalTimeHour).Interface(); norm != nil {
		res.Sensor = norm.([]*bspb.BatteryStats_App_Sensor)
	}
	if norm := normalizeMessage(a.GetStateTime(), totalTimeHour); norm != nil {
		res.StateTime = norm.(*bspb.BatteryStats_App_StateTime)
	}
	if norm := normalizeMessage(a.GetVibrator(), totalTimeHour); norm != nil {
		res.Vibrator = norm.(*bspb.BatteryStats_App_Vibrator)
	}
	if norm := normalizeRepeatedMessage(a.GetWakelock(), totalTimeHour).Interface(); norm != nil {
		res.Wakelock = norm.([]*bspb.BatteryStats_App_Wakelock)
	}
	if norm := normalizeMessage(a.GetWifi(), totalTimeHour); norm != nil {
		res.Wifi = norm.(*bspb.BatteryStats_App_Wifi)
	}
	if norm := normalizeRepeatedMessage(a.GetUserActivity(), totalTimeHour).Interface(); norm != nil {
		res.UserActivity = norm.([]*bspb.BatteryStats_App_UserActivity)
	}
	if norm := normalizeRepeatedMessage(a.GetScheduledJob(), totalTimeHour).Interface(); norm != nil {
		res.ScheduledJob = norm.([]*bspb.BatteryStats_App_ScheduledJob)
	}
	return res
}
func subtractApp(a1, a2 *bspb.BatteryStats_App) *bspb.BatteryStats_App {
	// The app name may be empty for one of the inputs,
	// if that file does not contain any occurence for this particular app
	// Here we extract the valid name from the 2 protos
	appName := a1.GetName()
	if appName == "" {
		appName = a2.GetName()
	}

	a := &bspb.BatteryStats_App{
		Name:        proto.String(appName),
		Uid:         proto.Int32(a1.GetUid()),
		VersionName: combineProtoStrings(a1.GetVersionName(), a2.GetVersionName(), connector),
		VersionCode: a1.VersionCode,
	}
	c2map := make(map[string]*bspb.BatteryStats_App_Child)
	for _, c := range a2.GetChild() {
		c2map[c.GetName()] = c
	}

	changed := false
	if diff := subtractMessage(a1.GetCpu(), a2.GetCpu()); diff != nil {
		a.Cpu = diff.(*bspb.BatteryStats_App_Cpu)
		changed = true
	}
	if diff := subtractMessage(a1.GetForeground(), a2.GetForeground()); diff != nil {
		a.Foreground = diff.(*bspb.BatteryStats_App_Foreground)
		changed = true
	}
	if diff := subtractAppApk(a1.GetApk(), a2.GetApk()); diff != nil {
		a.Apk = diff
		changed = true
	}
	if diff := subtractController(a1.GetBluetoothController(), a2.GetBluetoothController()); diff != nil {
		a.BluetoothController = diff
		changed = true
	}
	if diff := subtractController(a1.GetModemController(), a2.GetModemController()); diff != nil {
		a.ModemController = diff
		changed = true
	}
	if diff := subtractMessage(a1.GetNetwork(), a2.GetNetwork()); diff != nil {
		a.Network = diff.(*bspb.BatteryStats_App_Network)
		changed = true
	}
	if diff := subtractMessage(a1.GetPowerUseItem(), a2.GetPowerUseItem()); diff != nil {
		a.PowerUseItem = diff.(*bspb.BatteryStats_App_PowerUseItem)
		changed = true
	}
	if diff := subtractRepeatedMessage(a1.GetProcess(), a2.GetProcess()); !diff.IsNil() {
		a.Process = diff.Interface().([]*bspb.BatteryStats_App_Process)
		changed = true
	}
	if diff := subtractRepeatedMessage(a1.GetSensor(), a2.GetSensor()); !diff.IsNil() {
		a.Sensor = diff.Interface().([]*bspb.BatteryStats_App_Sensor)
		changed = true
	}
	if diff := subtractMessage(a1.GetStateTime(), a2.GetStateTime()); diff != nil {
		a.StateTime = diff.(*bspb.BatteryStats_App_StateTime)
		changed = true
	}
	if diff := subtractMessage(a1.GetVibrator(), a2.GetVibrator()); diff != nil {
		a.Vibrator = diff.(*bspb.BatteryStats_App_Vibrator)
		changed = true
	}
	if diff := subtractRepeatedMessage(a1.GetWakelock(), a2.GetWakelock()); !diff.IsNil() {
		a.Wakelock = diff.Interface().([]*bspb.BatteryStats_App_Wakelock)
		changed = true
	}
	if diff := subtractMessage(a1.GetWifi(), a2.GetWifi()); diff != nil {
		a.Wifi = diff.(*bspb.BatteryStats_App_Wifi)
		changed = true
	}
	if diff := subtractController(a1.GetWifiController(), a2.GetWifiController()); diff != nil {
		a.WifiController = diff
		changed = true
	}
	if diff := subtractRepeatedMessage(a1.GetSync(), a2.GetSync()); !diff.IsNil() {
		a.Sync = diff.Interface().([]*bspb.BatteryStats_App_Sync)
		changed = true
	}
	if diff := subtractRepeatedMessage(a1.GetUserActivity(), a2.GetUserActivity()); !diff.IsNil() {
		a.UserActivity = diff.Interface().([]*bspb.BatteryStats_App_UserActivity)
		changed = true
	}
	if diff := subtractRepeatedMessage(a1.GetScheduledJob(), a2.GetScheduledJob()); !diff.IsNil() {
		a.ScheduledJob = diff.Interface().([]*bspb.BatteryStats_App_ScheduledJob)
		changed = true
	}
	for _, c := range a1.GetChild() {
		if c2, ok := c2map[c.GetName()]; ok {
			if diff := subtractAppChild(c, c2); diff != nil {
				a.Child = append(a.Child, diff)
				changed = true
			}
			delete(c2map, c.GetName())
		} else {
			// Child doesn't exist in a2
			a.Child = append(a.Child, c)
			changed = true
		}
	}
	for _, c2 := range c2map {
		// These children aren't in a1
		a.Child = append(a.Child, c2)
		changed = true
	}
	// Subtract the head child
	h1 := a1.GetHeadChild()
	h2 := a2.GetHeadChild()
	if h1 != nil || h2 != nil {
		if h1 == nil {
			a.HeadChild = h2
			changed = true
		} else if h2 == nil {
			a.HeadChild = h1
			changed = true
		} else {
			if diff := subtractAppChild(a1.GetHeadChild(), a2.GetHeadChild()); diff != nil {
				a.HeadChild = diff
				changed = true
			}
		}
	}
	if !changed {
		return nil
	}
	return a
}