public Task When_road_nodes_were_imported()
        {
            var imported_nodes = Enumerable
                                 .Range(0, new Random().Next(10))
                                 .Select(index => new ImportedRoadNode
            {
                Id       = _fixture.Create <int>(),
                Type     = _fixture.Create <RoadNodeType>(),
                Geometry = BackOffice.Core.GeometryTranslator.Translate(_fixture.Create <NetTopologySuite.Geometries.Point>()),
                Origin   = _fixture.Create <ImportedOriginProperties>()
            })
                                 .ToArray();
            var givens = Array.ConvertAll(imported_nodes, imported => (object)imported);

            return(new RoadNetworkInfoProjection()
                   .Scenario()
                   .Given(
                       new BeganRoadNetworkImport()
                       )
                   .Given(givens)
                   .Expect(
                       new RoadNetworkInfo
            {
                Id = 0,
                CompletedImport = false,
                OrganizationCount = 0,
                RoadNodeCount = imported_nodes.Length,
                TotalRoadNodeShapeLength = imported_nodes.Aggregate(
                    new WordLength(0),
                    (current, imported) =>
                    current
                    .Plus(
                        new PointShapeContent(GeometryTranslator.FromGeometryPoint(BackOffice.Core.GeometryTranslator.Translate(imported.Geometry)))
                        .ContentLength
                        .Plus(ShapeRecord.HeaderLength))
                    ).ToInt32(),
                RoadSegmentCount = 0,
                RoadSegmentSurfaceAttributeCount = 0,
                RoadSegmentLaneAttributeCount = 0,
                RoadSegmentWidthAttributeCount = 0,
                RoadSegmentEuropeanRoadAttributeCount = 0,
                RoadSegmentNationalRoadAttributeCount = 0,
                RoadSegmentNumberedRoadAttributeCount = 0,
                TotalRoadSegmentShapeLength = 0,
                GradeSeparatedJunctionCount = 0
            }
                       ));
        }
        public void ValidateWithEmptyPointRecordsReturnsExpectedResult()
        {
            var records = Enumerable.Range(0, 2)
                          .Select(index =>
                                  new PointShapeContent(GeometryTranslator.FromGeometryPoint(NetTopologySuite.Geometries.Point.Empty))
                                  .RecordAs(new RecordNumber(index + 1)))
                          .GetEnumerator();

            var result = _sut.Validate(_entry, records);

            Assert.Equal(
                ZipArchiveProblems.Many(
                    _entry.AtShapeRecord(new RecordNumber(1)).ShapeRecordGeometryMismatch(),
                    _entry.AtShapeRecord(new RecordNumber(2)).ShapeRecordGeometryMismatch()
                    ),
                result);
        }
        public RoadNodeChangeShapeRecordsTranslatorTests()
        {
            _fixture = new Fixture();
            _fixture.CustomizeRoadNodeId();
            _fixture.CustomizeRoadNodeType();

            _fixture.Customize <NetTopologySuite.Geometries.Point>(customization =>
                                                                   customization.FromFactory(generator =>
                                                                                             new NetTopologySuite.Geometries.Point(
                                                                                                 _fixture.Create <double>(),
                                                                                                 _fixture.Create <double>()
                                                                                                 )
                                                                                             ).OmitAutoProperties()
                                                                   );
            _fixture.Customize <RecordNumber>(customizer =>
                                              customizer.FromFactory(random => new RecordNumber(random.Next(1, int.MaxValue))));
            _fixture.Customize <ShapeRecord>(customization =>
                                             customization.FromFactory(random =>
                                                                       new PointShapeContent(GeometryTranslator.FromGeometryPoint(_fixture.Create <NetTopologySuite.Geometries.Point>())).RecordAs(_fixture.Create <RecordNumber>())
                                                                       ).OmitAutoProperties()
                                             );

            _sut        = new RoadNodeChangeShapeRecordsTranslator();
            _enumerator = new List <ShapeRecord>().GetEnumerator();
            _stream     = new MemoryStream();
            _archive    = new ZipArchive(_stream, ZipArchiveMode.Create);
            _entry      = _archive.CreateEntry("wegknoop_all.shp");
        }
        public RoadNodeRecordProjection(RecyclableMemoryStreamManager manager, Encoding encoding)
        {
            if (manager == null)
            {
                throw new ArgumentNullException(nameof(manager));
            }
            if (encoding == null)
            {
                throw new ArgumentNullException(nameof(encoding));
            }

            When <Envelope <ImportedRoadNode> >(async(context, envelope, token) =>
            {
                var typeTranslation = RoadNodeType.Parse(envelope.Message.Type).Translation;
                var dbaseRecord     = new RoadNodeDbaseRecord
                {
                    WK_OIDN   = { Value = envelope.Message.Id },
                    WK_UIDN   = { Value = envelope.Message.Id + "_" + envelope.Message.Version },
                    TYPE      = { Value = typeTranslation.Identifier },
                    LBLTYPE   = { Value = typeTranslation.Name },
                    BEGINTIJD = { Value = envelope.Message.Origin.Since },
                    BEGINORG  = { Value = envelope.Message.Origin.OrganizationId },
                    LBLBGNORG = { Value = envelope.Message.Origin.Organization }
                };

                var point             = GeometryTranslator.FromGeometryPoint(BackOffice.Core.GeometryTranslator.Translate(envelope.Message.Geometry));
                var pointShapeContent = new PointShapeContent(point);

                await context.RoadNodes.AddAsync(new RoadNodeRecord
                {
                    Id = envelope.Message.Id,
                    ShapeRecordContent       = pointShapeContent.ToBytes(manager, encoding),
                    ShapeRecordContentLength = pointShapeContent.ContentLength.ToInt32(),
                    DbaseRecord = dbaseRecord.ToBytes(manager, encoding),
                    BoundingBox = RoadNodeBoundingBox.From(pointShapeContent.Shape)
                }, token);
            });

            When <Envelope <RoadNetworkChangesBasedOnArchiveAccepted> >(async(context, envelope, token) =>
            {
                foreach (var message in envelope.Message.Changes.Flatten())
                {
                    switch (message)
                    {
                    case RoadNodeAdded node:
                        var typeTranslation = RoadNodeType.Parse(node.Type).Translation;
                        var dbaseRecord     = new RoadNodeDbaseRecord
                        {
                            WK_OIDN   = { Value = node.Id },
                            WK_UIDN   = { Value = node.Id + "_0" },  // 1?
                            TYPE      = { Value = typeTranslation.Identifier },
                            LBLTYPE   = { Value = typeTranslation.Name },
                            BEGINTIJD = { Value = LocalDateTimeTranslator.TranslateFromWhen(envelope.Message.When) },
                            BEGINORG  = { Value = envelope.Message.OrganizationId },
                            LBLBGNORG = { Value = envelope.Message.Organization }
                        };

                        var point             = GeometryTranslator.FromGeometryPoint(BackOffice.Core.GeometryTranslator.Translate(node.Geometry));
                        var pointShapeContent = new PointShapeContent(point);

                        await context.RoadNodes.AddAsync(new RoadNodeRecord
                        {
                            Id = node.Id,
                            ShapeRecordContent       = pointShapeContent.ToBytes(manager, encoding),
                            ShapeRecordContentLength = pointShapeContent.ContentLength.ToInt32(),
                            DbaseRecord = dbaseRecord.ToBytes(manager, encoding),
                            BoundingBox = RoadNodeBoundingBox.From(pointShapeContent.Shape)
                        }, token);
                        break;
                    }
                }
            });
        }
        public RoadNetworkInfoProjection()
        {
            When <Envelope <BeganRoadNetworkImport> >(async(context, envelope, token) =>
                                                      await context.RoadNetworkInfo.AddAsync(new RoadNetworkInfo(), token)
                                                      );
            When <Envelope <CompletedRoadNetworkImport> >(async(context, envelope, token) =>
            {
                var info = context.RoadNetworkInfo.Local.SingleOrDefault() ??
                           await context.RoadNetworkInfo.SingleAsync(candidate => candidate.Id == 0, token);
                info.CompletedImport = true;
            });
            When <Envelope <ImportedRoadNode> >(async(context, envelope, token) =>
            {
                var info = context.RoadNetworkInfo.Local.SingleOrDefault() ??
                           await context.RoadNetworkInfo.SingleAsync(candidate => candidate.Id == 0, token);
                info.RoadNodeCount            += 1;
                info.TotalRoadNodeShapeLength +=
                    new PointShapeContent(
                        GeometryTranslator.FromGeometryPoint(Core.GeometryTranslator.Translate(envelope.Message.Geometry))
                        )
                    .ContentLength.Plus(ShapeRecord.HeaderLength)
                    .ToInt32();
            });
            When <Envelope <ImportedRoadSegment> >(async(context, envelope, token) =>
            {
                var info = context.RoadNetworkInfo.Local.SingleOrDefault() ??
                           await context.RoadNetworkInfo.SingleAsync(candidate => candidate.Id == 0, token);
                info.RoadSegmentCount            += 1;
                info.TotalRoadSegmentShapeLength +=
                    new PolyLineMShapeContent(
                        GeometryTranslator.FromGeometryMultiLineString(Core.GeometryTranslator.Translate(envelope.Message.Geometry))
                        )
                    .ContentLength.Plus(ShapeRecord.HeaderLength)
                    .ToInt32();
                info.RoadSegmentSurfaceAttributeCount      += envelope.Message.Surfaces.Length;
                info.RoadSegmentLaneAttributeCount         += envelope.Message.Lanes.Length;
                info.RoadSegmentWidthAttributeCount        += envelope.Message.Widths.Length;
                info.RoadSegmentEuropeanRoadAttributeCount += envelope.Message.PartOfEuropeanRoads.Length;
                info.RoadSegmentNationalRoadAttributeCount += envelope.Message.PartOfNationalRoads.Length;
                info.RoadSegmentNumberedRoadAttributeCount += envelope.Message.PartOfNumberedRoads.Length;
            });
            When <Envelope <ImportedGradeSeparatedJunction> >(async(context, envelope, token) =>
            {
                var info = context.RoadNetworkInfo.Local.SingleOrDefault() ??
                           await context.RoadNetworkInfo.SingleAsync(candidate => candidate.Id == 0, token);
                info.GradeSeparatedJunctionCount += 1;
            });
            When <Envelope <ImportedOrganization> >(async(context, envelope, token) =>
            {
                var info = context.RoadNetworkInfo.Local.SingleOrDefault() ??
                           await context.RoadNetworkInfo.SingleAsync(candidate => candidate.Id == 0, token);
                info.OrganizationCount += 1;
            });

            When <Envelope <RoadNetworkChangesBasedOnArchiveAccepted> >(async(context, envelope, token) =>
            {
                var info = context.RoadNetworkInfo.Local.SingleOrDefault() ??
                           await context.RoadNetworkInfo.SingleAsync(candidate => candidate.Id == 0, token);
                foreach (var change in envelope.Message.Changes.Flatten())
                {
                    switch (change)
                    {
                    case RoadNodeAdded m:
                        info.RoadNodeCount++;
                        info.TotalRoadNodeShapeLength +=
                            new PointShapeContent(
                                GeometryTranslator.FromGeometryPoint(Core.GeometryTranslator.Translate(m.Geometry))
                                )
                            .ContentLength.Plus(ShapeRecord.HeaderLength)
                            .ToInt32();
                        break;

                    case RoadSegmentAdded m:
                        info.RoadSegmentCount            += 1;
                        info.TotalRoadSegmentShapeLength +=
                            new PolyLineMShapeContent(
                                GeometryTranslator.FromGeometryMultiLineString(Core.GeometryTranslator.Translate(m.Geometry))
                                )
                            .ContentLength.Plus(ShapeRecord.HeaderLength)
                            .ToInt32();
                        //Note that in order to support deletion and modification we'll need to track it per segment
                        info.RoadSegmentSurfaceAttributeCount += m.Surfaces.Length;
                        info.RoadSegmentLaneAttributeCount    += m.Lanes.Length;
                        info.RoadSegmentWidthAttributeCount   += m.Widths.Length;
                        break;

                    case RoadSegmentAddedToEuropeanRoad _:
                        info.RoadSegmentEuropeanRoadAttributeCount += 1;
                        break;

                    case RoadSegmentAddedToNationalRoad _:
                        info.RoadSegmentNationalRoadAttributeCount += 1;
                        break;

                    case RoadSegmentAddedToNumberedRoad _:
                        info.RoadSegmentNumberedRoadAttributeCount += 1;
                        break;

                    case GradeSeparatedJunctionAdded _:
                        info.GradeSeparatedJunctionCount += 1;
                        break;
                    }
                }


                info.OrganizationCount += 1;
            });
        }