001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright 2005-2011 the ConQAT Project                                   |
004|                                                                          |
005| Licensed under the Apache License, Version 2.0 (the "License");          |
006| you may not use this file except in compliance with the License.         |
007| You may obtain a copy of the License at                                  |
008|                                                                          |
009|    http://www.apache.org/licenses/LICENSE-2.0                            |
010|                                                                          |
011| Unless required by applicable law or agreed to in writing, software      |
012| distributed under the License is distributed on an "AS IS" BASIS,        |
013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
014| See the License for the specific language governing permissions and      |
015| limitations under the License.                                           |
016+-------------------------------------------------------------------------*/
017package org.conqat.lib.commons.region;
018
019import java.io.Serializable;
020import java.util.Comparator;
021import java.util.Objects;
022
023import org.conqat.lib.commons.js_export.ExportToJavaScript;
024
025import com.fasterxml.jackson.annotation.JsonProperty;
026
027/**
028 * A simple region with only start and end. If you also need a description
029 * string (origin), use {@link Region}. Both start and end positions are
030 * inclusive.
031 */
032@ExportToJavaScript
033public class SimpleRegion implements Comparable<SimpleRegion>, Serializable {
034
035        /** Version for serialization. */
036        private static final long serialVersionUID = 1;
037
038        /** The name of the JSON property name for {@link #start}. */
039        protected static final String START_PROPERTY = "start";
040
041        /** The name of the JSON property name for {@link #end}. */
042        protected static final String END_PROPERTY = "end";
043
044        /**
045         * Compares {@link SimpleRegion}s first by their start and then by their end.
046         */
047        public static final Comparator<SimpleRegion> START_AND_END_COMPARATOR = Comparator.comparing(SimpleRegion::getStart)
048                        .thenComparing(SimpleRegion::getEnd);
049
050        /** Region start position (inclusive). */
051        @JsonProperty(START_PROPERTY)
052        private final int start;
053
054        /** Region end position (inclusive). */
055        @JsonProperty(END_PROPERTY)
056        private final int end;
057
058        /** Constructor. */
059        public SimpleRegion(int start, int end) {
060                this.start = start;
061                this.end = end;
062        }
063
064        /** Checks if the region contains a position */
065        public boolean containsPosition(int position) {
066                return (start <= position && end >= position);
067        }
068
069        /** Checks if two regions are overlapping */
070        public boolean overlaps(SimpleRegion r) {
071                // Region with smaller start value performs overlap check
072                if (r.start < start) {
073                        return r.overlaps(this);
074                }
075
076                return (start <= r.start && end >= r.start);
077        }
078
079        /** Checks if two regions are adjacent */
080        public boolean adjacent(SimpleRegion r) {
081                // Region with smaller start value performs adjacency check
082                if (r.start < start) {
083                        return r.adjacent(this);
084                }
085
086                return (end + 1 == r.start);
087        }
088
089        /**
090         * Gets the end position of the region. This may be less than start for an empty
091         * region (see also {@link #isEmpty()}).
092         */
093        public int getEnd() {
094                return end;
095        }
096
097        /** Gets the start position of the region */
098        public int getStart() {
099                return start;
100        }
101
102        /**
103         * Gets the length of the region. Empty regions have a length of 0.
104         */
105        public int getLength() {
106                if (isEmpty()) {
107                        return 0;
108                }
109                return end - start + 1;
110        }
111
112        /** Returns whether this region is empty. */
113        public boolean isEmpty() {
114                return end < start;
115        }
116
117        /** {@inheritDoc} */
118        @Override
119        public String toString() {
120                return "[" + start + "-" + end + "]";
121        }
122
123        /** Compares regions by their start position */
124        @Override
125        public int compareTo(SimpleRegion other) {
126                return Integer.compare(start, other.start);
127        }
128
129        /**
130         * Returns whether start and end of the region is the same as for this region.
131         */
132        public boolean equalsStartEnd(SimpleRegion other) {
133                return start == other.start && end == other.end;
134        }
135
136        /** {@inheritDoc} */
137        @Override
138        public int hashCode() {
139                return Objects.hash(start, end);
140        }
141
142        /** {@inheritDoc} */
143        @Override
144        public boolean equals(Object other) {
145                if (this == other) {
146                        return true;
147                }
148                if (other == null) {
149                        return false;
150                }
151                if (getClass() != other.getClass()) {
152                        return false;
153                }
154
155                SimpleRegion otherRegion = (SimpleRegion) other;
156                return equalsStartEnd(otherRegion);
157        }
158}