public override Attrition Build(ChunkData data, KeyMasterOffsetManager o)
        {
            Offset    = o;
            ChunkData = data;
            //"If the claim is associated with a diagnosis, " +
            //"and (1) that [Diagnosis].[Month and year of start of medical care] date falls within the [Month and year of medical care] and (2) " +
            //"there is no other diagnoses with the same level 4 ICD-10 code from the same institution for the same member with the same [Month and year of start of medical care] date, " +
            //"then the [Month and year of start of medical care] date is used as the visit_start_date."
            foreach (var sameSource in ConditionOccurrencesRaw
                     .Where(c => !string.IsNullOrEmpty(c.AdditionalFields["start_m_and_y_date"]))
                     .GroupBy(c => c.SourceValue))
            {
                foreach (var sameInstitution in sameSource.GroupBy(c => c.ProviderId))
                {
                    foreach (var sameStartOfMedicalCare in sameInstitution.GroupBy(c =>
                                                                                   c.AdditionalFields["month_and_year_of_start"]))
                    {
                        var diagnosis = sameStartOfMedicalCare.ToList();
                        if (diagnosis.Count == 1)
                        {
                            if (!_visitsDateDiagnosis.ContainsKey(diagnosis[0].VisitOccurrenceId.Value))
                            {
                                _visitsDateDiagnosis.Add(diagnosis[0].VisitOccurrenceId.Value,
                                                         DateTime.Parse(diagnosis[0].AdditionalFields["start_m_and_y_date"]));
                            }
                            else
                            {
                                var newValue = DateTime.Parse(diagnosis[0].AdditionalFields["start_m_and_y_date"]);

                                if (_visitsDateDiagnosis[diagnosis[0].VisitOccurrenceId.Value] < newValue)
                                {
                                    _visitsDateDiagnosis[diagnosis[0].VisitOccurrenceId.Value] = newValue;
                                }
                            }
                        }
                    }
                }
            }


            //If the claim is associated with a Drug.[Prescription date] or  Procedure.[Procedure date], use the minimum of those dates as the visit_start_date.
            foreach (var p in ProcedureOccurrencesRaw.GroupBy(p => p.VisitOccurrenceId))
            {
                var procedure = p.First();
                if (!procedure.VisitOccurrenceId.HasValue)
                {
                    continue;
                }

                var procedures = p.Where(pp => pp.StartDate > DateTime.MinValue).ToArray();

                if (procedures.Length > 0)
                {
                    var minProcedureDate = procedures.Min(pp => pp.StartDate);

                    if (_visitsDate.ContainsKey(procedure.VisitOccurrenceId.Value))
                    {
                        _visitsDate[procedure.VisitOccurrenceId.Value] = minProcedureDate;
                        continue;
                    }

                    _visitsDate.Add(procedure.VisitOccurrenceId.Value, minProcedureDate);
                }
            }

            foreach (var d in DrugExposuresRaw.GroupBy(d => d.VisitOccurrenceId))
            {
                var drug = d.First();
                if (!drug.VisitOccurrenceId.HasValue)
                {
                    continue;
                }

                var drugs = d.Where(dd => dd.StartDate > DateTime.MinValue).ToArray();

                if (drugs.Length > 0)
                {
                    var minDrugDate = drugs.Min(dd => dd.StartDate);

                    if (!_visitsDate.ContainsKey(drug.VisitOccurrenceId.Value))
                    {
                        _visitsDate.Add(drug.VisitOccurrenceId.Value, minDrugDate);
                        continue;
                    }

                    // [Date of prescription] < [Date of procedure]
                    // minDrugDate < visitsDate[drug.VisitOccurrenceId.Value]
                    if (minDrugDate < _visitsDate[drug.VisitOccurrenceId.Value])
                    {
                        _visitsDate[drug.VisitOccurrenceId.Value] = minDrugDate;
                    }
                }
            }

            return(base.Build(data, o));
        }
        /// <summary>
        /// Build person entity and all person related entities like: DrugExposures, ConditionOccurrences, ProcedureOccurrences... from raw data sets
        /// </summary>
        public override Attrition Build(ChunkData data, KeyMasterOffsetManager om)
        {
            this.Offset    = om;
            this.ChunkData = data;
            var result = BuildPerson(PersonRecords.ToList());
            var person = result.Key;

            if (person == null)
            {
                return(result.Value);
            }

            if (!ObservationPeriodsRaw.Any(op => op.StartDate < op.EndDate))
            {
                return(Attrition.InvalidObservationTime);
            }

            var observationPeriods =
                BuildObservationPeriods(person.ObservationPeriodGap,
                                        ObservationPeriodsRaw.Where(op => op.StartDate < op.EndDate).ToArray()).ToArray();

            var payerPlanPeriods = BuildPayerPlanPeriods(PayerPlanPeriodsRaw.ToArray(), null).ToArray();
            var cohort           = BuildCohort(CohortRecords.ToArray(), observationPeriods).ToArray();


            var visitOccurrences = new Dictionary <long, VisitOccurrence>();
            var visitIds         = new List <long>();

            // Build and clenaup visit occurrences entities
            foreach (var visitOccurrence in CleanupVisits(
                         BuildVisitOccurrences(VisitOccurrencesRaw.ToArray(), observationPeriods), cohort,
                         observationPeriods))
            {
                visitOccurrences.Add(visitOccurrence.Id, visitOccurrence);
                visitIds.Add(visitOccurrence.Id);
            }

            long?prevVisitId = null;

            foreach (var visitId in visitIds.OrderBy(v => v))
            {
                if (prevVisitId.HasValue)
                {
                    visitOccurrences[visitId].PrecedingVisitOccurrenceId = prevVisitId;
                }

                prevVisitId = visitId;
            }

            var drugExposures = BuildDrugExposures(DrugExposuresRaw.Where(de => de.StartDate < DateTime.Now).ToArray(),
                                                   visitOccurrences, observationPeriods)
                                .ToArray();
            var deviceExposure = BuildDeviceExposure(DeviceExposureRaw.ToArray(), visitOccurrences, observationPeriods)
                                 .ToArray();
            var conditionOccurrences =
                Cleanup(
                    BuildConditionOccurrences(
                        ConditionOccurrencesRaw.Where(co => co.StartDate < DateTime.Now).ToArray(), visitOccurrences,
                        observationPeriods),
                    cohort).ToArray();
            var procedureOccurrences =
                Cleanup(
                    BuildProcedureOccurrences(ProcedureOccurrencesRaw.ToArray(), visitOccurrences, observationPeriods),
                    cohort).ToArray();

            var observations =
                Cleanup(BuildObservations(ObservationsRaw.ToArray(), visitOccurrences, observationPeriods), cohort)
                .ToArray();
            var measurements =
                Cleanup(BuildMeasurement(MeasurementsRaw.ToArray(), visitOccurrences, observationPeriods), cohort)
                .ToArray();

            // set corresponding PlanPeriodIds to drug exposure entities and procedure occurrence entities
            SetPayerPlanPeriodId(payerPlanPeriods, drugExposures, procedureOccurrences,
                                 visitOccurrences.Values.ToArray(), new DeviceExposure[] { });

            // set corresponding ProviderIds
            SetProviderIds(drugExposures);
            SetProviderIds(conditionOccurrences);
            SetProviderIds(procedureOccurrences);
            SetProviderIds(observations);

            var death          = BuildDeath(DeathRecords.ToArray(), visitOccurrences, observationPeriods);
            var drugCosts      = BuildDrugCosts(drugExposures).ToArray();
            var procedureCosts = BuildProcedureCosts(procedureOccurrences).ToArray();

            // push built entities to ChunkBuilder for further save to CDM database
            AddToChunk(person, death,
                       observationPeriods,
                       payerPlanPeriods,
                       drugExposures,
                       CleanupCondition(conditionOccurrences).ToArray(),
                       procedureOccurrences,
                       CleanupObservations(observations, measurements, conditionOccurrences, procedureOccurrences).ToArray(),
                       measurements,
                       visitOccurrences.Values.ToArray(), null, cohort, deviceExposure, new Note[0]);

            var pg = new PregnancyAlgorithm.PregnancyAlgorithm();

            foreach (var r in pg.GetPregnancyEpisodes(Vocabulary, person, observationPeriods,
                                                      ChunkData.ConditionOccurrences.Where(e => e.PersonId == person.PersonId).ToArray(),
                                                      ChunkData.ProcedureOccurrences.Where(e => e.PersonId == person.PersonId).ToArray(),
                                                      ChunkData.Observations.Where(e => e.PersonId == person.PersonId).ToArray(),
                                                      ChunkData.Measurements.Where(e => e.PersonId == person.PersonId).ToArray(),
                                                      ChunkData.DrugExposures.Where(e => e.PersonId == person.PersonId).ToArray()))
            {
                r.Id = KeyMasterOffsetManager.GetKeyOffset(r.PersonId).ConditionEraId;
                ChunkData.ConditionEra.Add(r);
            }

            return(Attrition.None);
        }