LocationRange.java

package org.sterling.source;

import static java.util.Arrays.asList;
import static java.util.Collections.max;
import static java.util.Collections.min;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

public class LocationRange implements LocationAware {

    public static final LocationRange NULL = new LocationRange(Location.NULL, Location.NULL);

    public static LocationRange between(Location start, Location end) {
        return new LocationRange(start, end);
    }

    public static LocationRange extent(Collection<? extends LocationAware> locations) {
        List<Location> startLocations = new ArrayList<>();
        List<Location> endLocations = new ArrayList<>();
        for (LocationAware location : locations) {
            LocationRange range = location.getRange();
            if (!range.isNull()) {
                if (!range.getStart().isNull()) {
                    startLocations.add(range.getStart());
                }
                if (!range.getEnd().isNull()) {
                    endLocations.add(range.getEnd());
                }
            }
        }
        return between(min(startLocations), max(endLocations));
    }

    public static LocationRange extent(LocationAware... locations) {
        return extent(asList(locations));
    }

    private final Location start;
    private final Location end;

    public LocationRange(Location start) {
        this(start, start);
    }

    public LocationRange(Location start, Location end) {
        this.start = start;
        this.end = end;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (o instanceof LocationRange) {
            LocationRange other = (LocationRange) o;
            return Objects.equals(start, other.start)
                && Objects.equals(end, other.end);
        } else {
            return false;
        }
    }

    public Location getEnd() {
        return end;
    }

    @Override
    public LocationRange getRange() {
        return this;
    }

    public Location getStart() {
        return start;
    }

    @Override
    public int hashCode() {
        return Objects.hash(start, end);
    }

    public boolean isNull() {
        return equals(NULL);
    }

    @Override
    public String toString() {
        String value = "'" + start.getSource() + "' (" + (start.getLine() + 1) + ", " + (start.getColumn() + 1) + ")";
        if (start.equals(end)) {
            return value;
        } else {
            return value + ", (" + (end.getLine() + 1) + ", " + (end.getColumn() + 1) + ")";
        }
    }
}