// BundleToEventStream takes a bundle of resources and converts them to an EventStream.  Currently only a
// limited set of resource types are supported, with unsupported resource types resulting in an error.  If
// the bundle contains more than one patient, this is also considered an error.
func BundleToEventStream(bundle *models.Bundle) (es *plugin.EventStream, err error) {
	var patient *models.Patient
	events := make([]plugin.Event, 0, len(bundle.Entry))
	for _, entry := range bundle.Entry {
		switch r := entry.Resource.(type) {
		default:
			err = fmt.Errorf("Unsupported: Converting %s to Event", reflect.TypeOf(r).Elem().Name())
			return
		case *models.Patient:
			if patient != nil {
				err = errors.New("Found more than one patient in resources")
				return
			}
			patient = r
		case *models.Condition:
			if r.VerificationStatus != "confirmed" {
				continue
			}
			if onset, err := findDate(false, r.OnsetDateTime, r.OnsetPeriod, r.DateRecorded); err == nil {
				events = append(events, plugin.Event{Date: onset, Type: "Condition", End: false, Value: r})
			}
			if abatement, err := findDate(true, r.AbatementDateTime, r.AbatementPeriod); err == nil {
				events = append(events, plugin.Event{Date: abatement, Type: "Condition", End: true, Value: r})
			}
			// TODO: What happens if there is no date at all?
		case *models.MedicationStatement:
			if r.Status == "" || r.Status == "entered-in-error" {
				continue
			}
			if active, err := findDate(false, r.EffectiveDateTime, r.EffectivePeriod, r.DateAsserted); err == nil {
				events = append(events, plugin.Event{Date: active, Type: "MedicationStatement", End: false, Value: r})
			}
			if inactive, err := findDate(true, r.EffectivePeriod); err == nil {
				events = append(events, plugin.Event{Date: inactive, Type: "MedicationStatement", End: true, Value: r})
			}
			// TODO: What happens if there is no date at all?
		case *models.Observation:
			if r.Status != "final" && r.Status != "amended" && r.Status != "preliminary" && r.Status != "registered" {
				continue
			}
			if effective, err := findDate(false, r.EffectiveDateTime, r.EffectivePeriod, r.Issued); err == nil {
				events = append(events, plugin.Event{Date: effective, Type: "Observation", End: false, Value: r})
			}
			if ineffective, err := findDate(true, r.EffectivePeriod); err == nil {
				events = append(events, plugin.Event{Date: ineffective, Type: "Observation", End: true, Value: r})
			}
			// TODO: What happens if there is no date at all?
		}
	}
	es = plugin.NewEventStream(patient)
	plugin.SortEventsByDate(events)
	es.Events = events
	return es, nil
}
func addSignificantBirthdayEvents(es *plugin.EventStream, birthdays []int) {
	if len(birthdays) == 0 || es.Patient == nil || es.Patient.BirthDate == nil {
		return
	}

	for _, age := range birthdays {
		bd := es.Patient.BirthDate.Time.AddDate(age, 0, 0)
		if bd.Before(time.Now()) {
			es.Events = append(es.Events, plugin.Event{Date: bd, Type: "Age", End: false, Value: age})
		}
	}

	plugin.SortEventsByDate(es.Events)
}