001/*-----------------------------------------------------------------------+
002 | com.teamscale.ui
003 |                                                                       |
004   $Id$            
005 |                                                                       |
006 | Copyright (c)  2009-2013 CQSE GmbH                                 |
007 +-----------------------------------------------------------------------*/
008package org.conqat.lib.commons.diff;
009
010import java.io.Serializable;
011import java.util.ArrayList;
012import java.util.List;
013
014import org.conqat.lib.commons.assertion.CCSMAssert;
015import org.conqat.lib.commons.collections.CollectionUtils;
016import org.conqat.lib.commons.collections.UnmodifiableList;
017import org.conqat.lib.commons.js_export.ExportToJavaScript;
018
019import com.fasterxml.jackson.annotation.JsonProperty;
020
021/**
022 * A class describing a diff.
023 */
024@ExportToJavaScript
025public class DiffDescription implements Serializable {
026
027        /** Serial version UID. */
028        private static final long serialVersionUID = 1;
029
030        /** The name of this description. */
031        @JsonProperty("name")
032        private final String name;
033
034        /**
035         * Line changes for the left lines. The integers are organized in pairs, giving
036         * the start (inclusive) and end (exclusive) lines of a region.
037         */
038        @JsonProperty("leftChangeLines")
039        private final List<Integer> leftChangeLines = new ArrayList<>();
040
041        /**
042         * Line changes for the right lines. The integers are organized in pairs, giving
043         * the start (inclusive) and end (exclusive) lines of a region.
044         */
045        @JsonProperty("rightChangeLines")
046        private final List<Integer> rightChangeLines = new ArrayList<>();
047
048        /**
049         * Change tokens for the left text. These are used to highlight the exact change
050         * within changed lines. The integers are organized in pairs, giving the start
051         * (inclusive) and end (exclusive) offsets of a region.
052         */
053        @JsonProperty("leftChangeRegions")
054        private final List<Integer> leftChangeRegions = new ArrayList<>();
055
056        /**
057         * Change tokens for the left text. These are used to highlight the exact change
058         * within changed lines. The integers are organized in pairs, giving the start
059         * (inclusive) and end (exclusive) offsets of a region.
060         */
061        @JsonProperty("rightChangeRegions")
062        private final List<Integer> rightChangeRegions = new ArrayList<>();
063
064        /** Constructor. */
065        public DiffDescription(String name) {
066                this.name = name;
067        }
068
069        /** Returns the name. */
070        public String getName() {
071                return name;
072        }
073
074        /**
075         * Adds a line region that is matched between the left and right element. This
076         * denotes a part where these regions differ. First lines are inclusive, last
077         * lines are exclusive. All lines are 1-based. Adding regions must be performed
078         * in ascending order.
079         */
080        public void addLineRegion(int leftFirstLine, int leftEndLine, int rightFirstLine, int rightEndLine) {
081                addLineRegion(leftFirstLine, leftEndLine, leftChangeLines);
082                addLineRegion(rightFirstLine, rightEndLine, rightChangeLines);
083        }
084
085        /**
086         * Inserts a line region into either {@link #leftChangeLines} or
087         * {@link #rightChangeLines}.
088         */
089        private static void addLineRegion(int firstLine, int endLine, List<Integer> changeLines) {
090                CCSMAssert.isTrue(firstLine >= 0, "May only insert positive lines!");
091                CCSMAssert.isTrue(firstLine <= endLine, "End must not be before start!");
092                CCSMAssert.isTrue(changeLines.isEmpty() || CollectionUtils.getLast(changeLines) - 1 <= firstLine,
093                                "Must insert in ascending order!");
094                changeLines.add(firstLine);
095                changeLines.add(endLine);
096        }
097
098        /**
099         * Adds a change within a line region (that is highlighted) for the left side.
100         * Start is inclusive, end is exclusive.
101         */
102        public void addLeftChange(int startOffset, int endOffset) {
103                addChange(startOffset, endOffset, leftChangeRegions);
104        }
105
106        /**
107         * Adds a change within a line region (that is highlighted) for the right side.
108         * Start is inclusive, end is exclusive.
109         */
110        public void addRightChange(int startOffset, int endOffset) {
111                addChange(startOffset, endOffset, rightChangeRegions);
112        }
113
114        /**
115         * Adds a change within a line region. Start is inclusive, end is exclusive.
116         */
117        private static void addChange(int startOffset, int endOffset, List<Integer> changeTokens) {
118                if (!changeTokens.isEmpty() && startOffset <= CollectionUtils.getLast(changeTokens)) {
119                        changeTokens.set(changeTokens.size() - 1, endOffset);
120                } else {
121                        changeTokens.add(startOffset);
122                        changeTokens.add(endOffset);
123                }
124        }
125
126        /**
127         * Returns the change regions for the left lines. The integers are organized in
128         * pairs, giving the start (inclusive) and end (exclusive) index of a region.
129         */
130        public UnmodifiableList<Integer> getLeftChangeRegions() {
131                return CollectionUtils.asUnmodifiable(leftChangeRegions);
132        }
133
134        /**
135         * Returns the change regions for the right lines. The integers are organized in
136         * pairs, giving the start (inclusive) and end (exclusive) index of a region.
137         */
138        public UnmodifiableList<Integer> getRightChangeRegions() {
139                return CollectionUtils.asUnmodifiable(rightChangeRegions);
140        }
141
142        /**
143         * Adds the given list to the leftChangeRegions
144         */
145        public void addLeftChangeRegions(UnmodifiableList<Integer> leftChangeRegions) {
146                this.leftChangeRegions.addAll(leftChangeRegions);
147        }
148
149        /**
150         * Adds the given list to the rightChangeRegions
151         */
152        public void addRightChangeRegions(UnmodifiableList<Integer> rightChangeRegions) {
153                this.rightChangeRegions.addAll(rightChangeRegions);
154        }
155
156        /**
157         * Returns the line changes for the left lines. The integers are organized in
158         * pairs, giving the start (inclusive) and end (exclusive) lines of a region.
159         */
160        public UnmodifiableList<Integer> getLeftChangeLines() {
161                return CollectionUtils.asUnmodifiable(leftChangeLines);
162        }
163
164        /**
165         * Returns the line changes for the right lines. The integers are organized in
166         * pairs, giving the start (inclusive) and end (exclusive) lines of a region.
167         */
168        public UnmodifiableList<Integer> getRightChangeLines() {
169                return CollectionUtils.asUnmodifiable(rightChangeLines);
170        }
171}