Newer
Older
ValidState / ShipmentAggregateRoot.cs
@Derek Comartin Derek Comartin on 24 Aug 2021 3 KB Init
using System;
using System.Collections.Generic;
using System.Linq;

namespace AggregateConsistencyBoundary
{
    public class ShipmentAggregateRoot
    {
        private SortedList<int, Stop> Stops { get; } = new();

        private ShipmentAggregateRoot(IReadOnlyList<Stop> stops)
        {
            for(var x = 0; x < stops.Count; x++)
            {
                Stops.Add(x, stops[x]);
            }
        }

        public static ShipmentAggregateRoot Factory(PickupStop pickup, DeliveryStop delivery)
        {
            return new ShipmentAggregateRoot(new Stop[] { pickup, delivery });
        }

        public static ShipmentAggregateRoot Factory(Stop[] stops)
        {
            if (stops.Length < 2)
            {
                throw new InvalidOperationException("Shipment requires at least 2 stops.");
            }

            if (stops.First() is not PickupStop)
            {
                throw new InvalidOperationException("First stop must be a Pickup");
            }

            if (stops.Last() is not DeliveryStop)
            {
                throw new InvalidOperationException("first stop must be a Pickup");
            }

            return new ShipmentAggregateRoot(stops);
        }

        public void Arrive(int stopId)
        {
            var currentStop = Stops.SingleOrDefault(x => x.Value.StopId == stopId);
            if (currentStop.Value == null)
            {
                throw new InvalidOperationException("Stop does not exist.");
            }

            var previousStopsAreNotDeparted = Stops.Any(x => x.Key < currentStop.Key && x.Value.Status != StopStatus.Departed);
            if (previousStopsAreNotDeparted)
            {
                throw new InvalidOperationException("Previous stops have not departed.");
            }

            currentStop.Value.Arrive();
        }

        public void Pickup(int stopId)
        {
            var currentStop = Stops.SingleOrDefault(x => x.Value.StopId == stopId);
            if (currentStop.Value == null)
            {
                throw new InvalidOperationException("Stop does not exist.");
            }

            if (currentStop.Value is not PickupStop)
            {
                throw new InvalidOperationException("Stop is not a pickup.");
            }

            currentStop.Value.Depart();
        }

        public void Deliver(int stopId)
        {
            var currentStop = Stops.SingleOrDefault(x => x.Value.StopId == stopId);
            if (currentStop.Value == null)
            {
                throw new InvalidOperationException("Stop does not exist.");
            }

            if (currentStop.Value is not DeliveryStop)
            {
                throw new InvalidOperationException("Stop is not a delivery.");
            }

            currentStop.Value.Depart();
        }

        public bool IsComplete()
        {
            return Stops.All(x => x.Value.Status == StopStatus.Departed);
        }
    }

    public record Address(string Street, string City, string Postal, string Country);
}