import java.util.*; import java.text.SimpleDateFormat; public class Repository { private String name; private Commit head; private int size; public Repository(String name) { if (name == null || name.isEmpty()) { throw new IllegalArgumentException("Repository needs a name!"); } this.name = name; } public String getRepoHead() { if (head == null) { return null; } return head.id; } public int getRepoSize() { Commit temp = head; int size = 0; while (temp != null) { size++; temp = temp.past; } this.size = size; return size; } public String toString() { if (head == null) { return name + " - No commits"; } return name + " - Current head: " + head.toString(); } public boolean contains(String targetId) { Commit temp = head; while (temp != null) { if (temp.id.equals(targetId)) { return true; } temp = temp.past; } return false; } public String getHistory(int n) { if (n <= 0) { throw new IllegalArgumentException("do you want the history or not?"); } Commit temp = head; String history = ""; if (n > size) { while (temp != null) { history += temp.toString() + "\n"; temp = temp.past; } } for (int i = 0; i < n && temp != null; i++) { history += temp.toString() + "\n"; temp = temp.past; } return history; } public String commit(String message) { if (head == null) { head = new Commit(message); return head.id; } Commit old = head; head = new Commit(message, old); size++; return head.id; } public boolean drop(String targetId) { // list is empty if (head == null) { return false; } size--; Commit temp = head; // front if (temp.id.equals(targetId)) { head = temp.past; return true; } // middle while (temp.past != null && temp.past.past != null) { if (temp.past.id == targetId) { temp.past = temp.past.past; return true; } temp = temp.past; } // end if (temp.past != null && temp.past.id.equals(targetId)) { temp.past = null; return true; } // if we get here, targetId was not found, return size to initial state size++; return false; } public void synchronize(Repository other) { if (head == null && other.head == null) { head = null; } else if (head == null) { head = other.head; other.head = null; } else if (other.head == null) { other.head = null; } else { List commitList = new ArrayList<>(); Comparator commitComparator = new Comparator() { public int compare(Commit one, Commit two) { return Long.compare(one.timeStamp, two.timeStamp); } }; Commit temp = head; while (temp != null) { commitList.add(temp); temp = temp.past; } temp = other.head; while (temp != null) { commitList.add(temp); temp = temp.past; } commitList.sort(commitComparator); Commit prev = null; for (Commit commit : commitList) { commit.past = prev; prev = commit; } head = commitList.get(commitList.size() - 1); other.head = null; } } /** * DO NOT MODIFY * A class that represents a single commit in the repository. * Commits are characterized by an identifier, a commit message, * and the time that the commit was made. A commit also stores * a reference to the immediately previous commit if it exists. * * Staff Note: You may notice that the comments in this * class openly mention the fields of the class. This is fine * because the fields of the Commit class are public. In general, * be careful about revealing implementation details! */ public class Commit { private static int currentCommitID; /** * The time, in milliseconds, at which this commit was created. */ public final long timeStamp; /** * A unique identifier for this commit. */ public final String id; /** * A message describing the changes made in this commit. */ public final String message; /** * A reference to the previous commit, if it exists. Otherwise, null. */ public Commit past; /** * Constructs a commit object. The unique identifier and timestamp * are automatically generated. * @param message A message describing the changes made in this commit. * @param past A reference to the commit made immediately before this * commit. */ public Commit(String message, Commit past) { this.id = "" + currentCommitID++; this.message = message; this.timeStamp = System.currentTimeMillis(); this.past = past; } /** * Constructs a commit object with no previous commit. The unique * identifier and timestamp are automatically generated. * @param message A message describing the changes made in this commit. */ public Commit(String message) { this(message, null); } /** * Returns a string representation of this commit. The string * representation consists of this commit's unique identifier, * timestamp, and message, in the following form: * "[identifier] at [timestamp]: [message]" * @return The string representation of this collection. */ @Override public String toString() { SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z"); Date date = new Date(timeStamp); return id + " at " + formatter.format(date) + ": " + message; } /** * Resets the IDs of the commit nodes such that they reset to 0. * Primarily for testing purposes. */ public static void resetIds() { Commit.currentCommitID = 0; } } }