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<Commit> commitList = new ArrayList<>();
            Comparator commitComparator = new Comparator<Commit>() {
                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;
        }
    }
}
