// Path: src/main/java/com/pathfinder/api/GraphTraversalService.java
// public interface GraphTraversalService extends Remote {
// 
//   /**
//    * @param origin origin point
//    * @param destination destination point
//    * @param limitations restrictions on the path selection, as key-value according to some API specification
//    * @return A list of transit paths
//    * @throws java.rmi.RemoteException RMI problem
//    */
//   List<TransitPath> findShortestPath(String origin,
//                                      String destination,
//                                      Properties limitations);
// 
// }
// 
// Path: src/main/java/com/pathfinder/api/TransitEdge.java
// public final class TransitEdge implements Serializable {
// 
//   private final String edge;
//   private final String fromNode;
//   private final String toNode;
//   private final Date fromDate;
//   private final Date toDate;
// 
//   /**
//    * Constructor.
//    *
//    * @param edge
//    * @param fromNode
//    * @param toNode
//    * @param fromDate
//    * @param toDate
//    */
//   public TransitEdge(final String edge,
//                      final String fromNode,
//                      final String toNode,
//                      final Date fromDate,
//                      final Date toDate) {
//     this.edge = edge;
//     this.fromNode = fromNode;
//     this.toNode = toNode;
//     this.fromDate = fromDate;
//     this.toDate = toDate;
//   }
// 
//   public String getEdge() {
//     return edge;
//   }
// 
//   public String getFromNode() {
//     return fromNode;
//   }
// 
//   public String getToNode() {
//     return toNode;
//   }
// 
//   public Date getFromDate() {
//     return fromDate;
//   }
// 
//   public Date getToDate() {
//     return toDate;
//   }
// }
// 
// Path: src/main/java/se/citerus/dddsample/domain/model/cargo/RouteSpecification.java
// public class RouteSpecification extends AbstractSpecification<Itinerary> implements ValueObject<RouteSpecification> {
// 
//   private Location origin;
//   private Location destination;
//   private Date arrivalDeadline;
// 
//   /**
//    * @param origin origin location - can't be the same as the destination
//    * @param destination destination location - can't be the same as the origin
//    * @param arrivalDeadline arrival deadline
//    */
//   public RouteSpecification(final Location origin, final Location destination, final Date arrivalDeadline) {
//     Validate.notNull(origin, "Origin is required");
//     Validate.notNull(destination, "Destination is required");
//     Validate.notNull(arrivalDeadline, "Arrival deadline is required");
//     Validate.isTrue(!origin.sameIdentityAs(destination), "Origin and destination can't be the same: " + origin);
// 
//     this.origin = origin;
//     this.destination = destination;
//     this.arrivalDeadline = (Date) arrivalDeadline.clone();
//   }
// 
//   /**
//    * @return Specified origin location.
//    */
//   public Location origin() {
//     return origin;
//   }
// 
//   /**
//    * @return Specfied destination location.
//    */
//   public Location destination() {
//     return destination;
//   }
// 
//   /**
//    * @return Arrival deadline.
//    */
//   public Date arrivalDeadline() {
//     return new Date(arrivalDeadline.getTime());
//   }
// 
//   @Override
//   public boolean isSatisfiedBy(final Itinerary itinerary) {
//     return itinerary != null &&
//            origin().sameIdentityAs(itinerary.initialDepartureLocation()) &&
//            destination().sameIdentityAs(itinerary.finalArrivalLocation()) &&
//            arrivalDeadline().after(itinerary.finalArrivalDate());
//   }
// 
//   @Override
//   public boolean sameValueAs(final RouteSpecification other) {
//     return other != null && new EqualsBuilder().
//       append(this.origin, other.origin).
//       append(this.destination, other.destination).
//       append(this.arrivalDeadline, other.arrivalDeadline).
//       isEquals();
//   }
// 
//   @Override
//   public boolean equals(final Object o) {
//     if (this == o) return true;
//     if (o == null || getClass() != o.getClass()) return false;
// 
//     final RouteSpecification that = (RouteSpecification) o;
// 
//     return sameValueAs(that);
//   }
// 
//   @Override
//   public int hashCode() {
//     return new HashCodeBuilder().
//       append(this.origin).
//       append(this.destination).
//       append(this.arrivalDeadline).
//       toHashCode();
//   }
// 
//   RouteSpecification() {
//     // Needed by Hibernate
//   }
//   
// }


import com.pathfinder.api.GraphTraversalService;
import com.pathfinder.api.TransitEdge;
import com.pathfinder.api.TransitPath;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import se.citerus.dddsample.domain.model.cargo.Itinerary;
import se.citerus.dddsample.domain.model.cargo.Leg;
import se.citerus.dddsample.domain.model.cargo.RouteSpecification;
import se.citerus.dddsample.domain.model.location.Location;
import se.citerus.dddsample.domain.model.location.LocationRepository;
import se.citerus.dddsample.domain.model.location.UnLocode;
import se.citerus.dddsample.domain.model.voyage.VoyageNumber;
import se.citerus.dddsample.domain.model.voyage.VoyageRepository;
import se.citerus.dddsample.domain.service.RoutingService;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
package se.citerus.dddsample.infrastructure.routing;



/**
 * Our end of the routing service. This is basically a data model
 * translation layer between our domain model and the API put forward
 * by the routing team, which operates in a different context from us.
 *
 */
public class ExternalRoutingService implements RoutingService {

  private GraphTraversalService graphTraversalService;
  private LocationRepository locationRepository;
  private VoyageRepository voyageRepository;
  private static final Log log = LogFactory.getLog(ExternalRoutingService.class);

// Path: src/main/java/com/pathfinder/api/GraphTraversalService.java
// public interface GraphTraversalService extends Remote {
// 
//   /**
//    * @param origin origin point
//    * @param destination destination point
//    * @param limitations restrictions on the path selection, as key-value according to some API specification
//    * @return A list of transit paths
//    * @throws java.rmi.RemoteException RMI problem
//    */
//   List<TransitPath> findShortestPath(String origin,
//                                      String destination,
//                                      Properties limitations);
// 
// }
// 
// Path: src/main/java/com/pathfinder/api/TransitEdge.java
// public final class TransitEdge implements Serializable {
// 
//   private final String edge;
//   private final String fromNode;
//   private final String toNode;
//   private final Date fromDate;
//   private final Date toDate;
// 
//   /**
//    * Constructor.
//    *
//    * @param edge
//    * @param fromNode
//    * @param toNode
//    * @param fromDate
//    * @param toDate
//    */
//   public TransitEdge(final String edge,
//                      final String fromNode,
//                      final String toNode,
//                      final Date fromDate,
//                      final Date toDate) {
//     this.edge = edge;
//     this.fromNode = fromNode;
//     this.toNode = toNode;
//     this.fromDate = fromDate;
//     this.toDate = toDate;
//   }
// 
//   public String getEdge() {
//     return edge;
//   }
// 
//   public String getFromNode() {
//     return fromNode;
//   }
// 
//   public String getToNode() {
//     return toNode;
//   }
// 
//   public Date getFromDate() {
//     return fromDate;
//   }
// 
//   public Date getToDate() {
//     return toDate;
//   }
// }
// 
// Path: src/main/java/se/citerus/dddsample/domain/model/cargo/RouteSpecification.java
// public class RouteSpecification extends AbstractSpecification<Itinerary> implements ValueObject<RouteSpecification> {
// 
//   private Location origin;
//   private Location destination;
//   private Date arrivalDeadline;
// 
//   /**
//    * @param origin origin location - can't be the same as the destination
//    * @param destination destination location - can't be the same as the origin
//    * @param arrivalDeadline arrival deadline
//    */
//   public RouteSpecification(final Location origin, final Location destination, final Date arrivalDeadline) {
//     Validate.notNull(origin, "Origin is required");
//     Validate.notNull(destination, "Destination is required");
//     Validate.notNull(arrivalDeadline, "Arrival deadline is required");
//     Validate.isTrue(!origin.sameIdentityAs(destination), "Origin and destination can't be the same: " + origin);
// 
//     this.origin = origin;
//     this.destination = destination;
//     this.arrivalDeadline = (Date) arrivalDeadline.clone();
//   }
// 
//   /**
//    * @return Specified origin location.
//    */
//   public Location origin() {
//     return origin;
//   }
// 
//   /**
//    * @return Specfied destination location.
//    */
//   public Location destination() {
//     return destination;
//   }
// 
//   /**
//    * @return Arrival deadline.
//    */
//   public Date arrivalDeadline() {
//     return new Date(arrivalDeadline.getTime());
//   }
// 
//   @Override
//   public boolean isSatisfiedBy(final Itinerary itinerary) {
//     return itinerary != null &&
//            origin().sameIdentityAs(itinerary.initialDepartureLocation()) &&
//            destination().sameIdentityAs(itinerary.finalArrivalLocation()) &&
//            arrivalDeadline().after(itinerary.finalArrivalDate());
//   }
// 
//   @Override
//   public boolean sameValueAs(final RouteSpecification other) {
//     return other != null && new EqualsBuilder().
//       append(this.origin, other.origin).
//       append(this.destination, other.destination).
//       append(this.arrivalDeadline, other.arrivalDeadline).
//       isEquals();
//   }
// 
//   @Override
//   public boolean equals(final Object o) {
//     if (this == o) return true;
//     if (o == null || getClass() != o.getClass()) return false;
// 
//     final RouteSpecification that = (RouteSpecification) o;
// 
//     return sameValueAs(that);
//   }
// 
//   @Override
//   public int hashCode() {
//     return new HashCodeBuilder().
//       append(this.origin).
//       append(this.destination).
//       append(this.arrivalDeadline).
//       toHashCode();
//   }
// 
//   RouteSpecification() {
//     // Needed by Hibernate
//   }
//   
// }


// Path: src/main/java/se/citerus/dddsample/infrastructure/routing/ExternalRoutingService.java
import com.pathfinder.api.GraphTraversalService;
import com.pathfinder.api.TransitEdge;
import com.pathfinder.api.TransitPath;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import se.citerus.dddsample.domain.model.cargo.Itinerary;
import se.citerus.dddsample.domain.model.cargo.Leg;
import se.citerus.dddsample.domain.model.cargo.RouteSpecification;
import se.citerus.dddsample.domain.model.location.Location;
import se.citerus.dddsample.domain.model.location.LocationRepository;
import se.citerus.dddsample.domain.model.location.UnLocode;
import se.citerus.dddsample.domain.model.voyage.VoyageNumber;
import se.citerus.dddsample.domain.model.voyage.VoyageRepository;
import se.citerus.dddsample.domain.service.RoutingService;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

package se.citerus.dddsample.infrastructure.routing;



/**
 * Our end of the routing service. This is basically a data model
 * translation layer between our domain model and the API put forward
 * by the routing team, which operates in a different context from us.
 *
 */
public class ExternalRoutingService implements RoutingService {

  private GraphTraversalService graphTraversalService;
  private LocationRepository locationRepository;
  private VoyageRepository voyageRepository;
  private static final Log log = LogFactory.getLog(ExternalRoutingService.class);

  public List<Itinerary> fetchRoutesForSpecification(RouteSpecification routeSpecification) {