// newParser creates a parser for the given bugreport.
func newParser(br string) (*parser, []string, error) {
	loc, err := bugreportutils.TimeZone(br)
	if err != nil {
		return nil, []string{}, err
	}
	pm, warnings := bugreportutils.ExtractPIDMappings(br)
	// Extract the year and month from the bugreport dumpstate line.
	d, err := bugreportutils.DumpState(br)
	if err != nil {
		return nil, warnings, fmt.Errorf("could not find dumpstate information in the bugreport: %v", err)
	}
	buf := new(bytes.Buffer)
	return &parser{
		referenceYear:  d.Year(),
		referenceMonth: d.Month(),
		loc:            loc,
		activeProcMap:  make(map[string]*procEntry),
		buf:            buf,
		csvState:       csv.NewState(buf, false),
		pidMappings:    pm,
	}, warnings, nil
}
// parseBugReport analyzes the given bug report contents, and updates the ParsedData object.
func (pd *ParsedData) parseBugReport(fname, contents string) error {
	meta, err := bugreportutils.ParseMetaInfo(contents)
	if err != nil {
		// If there are issues getting the meta info, then the file is most likely not a bug report.
		return errors.New("error parsing the bug report. Please provide a well formed bug report")
	}

	log.Printf("Trace started analyzing file.")
	// Generate the Historian plot and parse batterystats and activity manager simultaneously.
	historianCh := make(chan historianData)
	summariesCh := make(chan summariesData)
	checkinCh := make(chan checkinData)
	activityManagerCh := make(chan activityManagerData)

	// Create a temporary file to save the bug report, for the Historian script.
	brFile, err := writeTempFile(contents)

	historianOutput := historianData{"", err}
	if err == nil {
		// Don't run the Historian script if could not create temporary file.
		defer os.Remove(brFile)
		go func() {
			html, err := generateHistorianPlot(fname, brFile)
			historianCh <- historianData{html, err}
			log.Printf("Trace finished generating Historian plot.")
		}()
	}

	var errs []error
	ce := ""
	if meta.SdkVersion < minSupportedSDK {
		ce = "Unsupported bug report version."
		errs = append(errs, errors.New("unsupported bug report version"))
	} else {
		// No point running these if we don't support the sdk version since we won't get any data from them.
		bs := bugreportutils.ExtractBatterystatsCheckin(contents)

		if strings.Contains(bs, "Exception occurred while dumping") {
			// TODO: Display activity manager events even if battery data is invalid. Currently they will not be displayed.
			ce = "Exception found in battery dump."
			errs = append(errs, errors.New("exception found in battery dump"))
			close(summariesCh)
			close(checkinCh)
		} else {
			pkgs, pkgErrs := packageutils.ExtractAppsFromBugReport(contents)
			errs = append(errs, pkgErrs...)

			// Activity manager events are only parsed for supported sdk versions, even though they are still present in unsupported sdk version reports.
			// This is as the events are rendered with Historian v2, which is not generated for unsupported sdk versions.
			go func() {
				amCSV, warnings, errs := activity.Parse(pkgs, contents)
				activityManagerCh <- activityManagerData{amCSV, warnings, errs}
			}()

			go func() {
				var ctr checkinutil.IntCounter

				s := &sessionpb.Checkin{
					Checkin:          proto.String(bs),
					BuildFingerprint: proto.String(meta.BuildFingerprint),
				}
				stats, warnings, pbsErrs := checkinparse.ParseBatteryStats(&ctr, checkinparse.CreateCheckinReport(s), pkgs)
				checkinCh <- checkinData{stats, warnings, pbsErrs}
				log.Printf("Trace finished processing checkin.")
				if stats == nil {
					ce = "Could not parse aggregated battery stats."
					errs = append(errs, errors.New("could not parse aggregated battery stats"))
					// Only returning from this goroutine.
					return
				}
				pd.deviceType = stats.GetBuild().GetDevice()
			}()

			go func() {
				summariesCh <- analyze(bs, pkgs)
				log.Printf("Trace finished processing summary data.")
			}()
		}
	}

	if historianOutput.err == nil {
		historianOutput = <-historianCh
	}
	if historianOutput.err != nil {
		historianOutput.html = fmt.Sprintf("Error generating historian plot: %v", historianOutput.err)
	}

	var summariesOutput summariesData
	var checkinOutput checkinData
	var activityManagerOutput activityManagerData
	if meta.SdkVersion >= minSupportedSDK {
		summariesOutput = <-summariesCh
		checkinOutput = <-checkinCh
		activityManagerOutput = <-activityManagerCh
		errs = append(errs, append(summariesOutput.errs, append(activityManagerOutput.errs, checkinOutput.err...)...)...)
	}

	log.Printf("Trace finished generating Historian plot and summaries.")
	var loc string
	if d, err := bugreportutils.DumpState(contents); err != nil {
		log.Printf("Failed to extract time information from bugreport dumpstate: %v", err)
	} else {
		loc = d.Location().String()
	}

	warnings := append(checkinOutput.warnings, activityManagerOutput.warnings...)
	data := presenter.Data(meta,
		fname, summariesOutput.summaries,
		checkinOutput.batterystats, historianOutput.html,
		warnings,
		errs, summariesOutput.overflow)

	pd.responseArr = append(pd.responseArr, uploadResponse{
		SDKVersion:      data.SDKVersion,
		HistorianV2CSV:  appendCSVs(summariesOutput.historianV2CSV, activityManagerOutput.csv),
		LevelSummaryCSV: summariesOutput.levelSummaryCSV,
		ReportVersion:   data.CheckinSummary.ReportVersion,
		AppStats:        data.AppStats,
		DeviceCapacity:  checkinOutput.batterystats.GetSystem().GetPowerUseSummary().GetBatteryCapacityMah(),
		HistogramStats:  extractHistogramStats(data),
		TimeToDelta:     summariesOutput.timeToDelta,
		CriticalError:   ce,
		FileName:        data.Filename,
		Location:        loc,
	})
	pd.data = append(pd.data, data)
	return nil
}