package etomica.atom;

import etomica.Atom;
import etomica.Debug;

/**
 * Class for constructing linked lists of Atoms.
 *
 * @author David Kofke
 */
public class AtomLinker implements java.io.Serializable {
    public final Atom atom;
    //TODO make these private and access with final methods, but test if performance suffers from change
    public AtomLinker next, previous;
    
    /**
     * Constructor throws exception if given atom is null.  Only
     * AtomLink.Tab instances can have a null atom field.
     */
    public AtomLinker(Atom a) {
        if(a == null && !(this instanceof Tab))
            throw new IllegalArgumentException("Error: cannot create AtomLinker with null atom");
        atom = a; 
        next = previous = this;
    }
    
    /**
     * Disconnects this linker from the one's previous and next to it, and
     * puts them in sequence, repairing the hole.
     */
    public void remove() {
	    previous.next = next;
	    next.previous = previous;
	    if(Debug.ON) next = previous = this;
    }
    
    /**
     * Adds this linker to the list at the position before the given linker,
     * and after the linker that originally preceded the given one.
     */
    public void addBefore(AtomLinker newNext) {
        if(Debug.ON && next != this) {//also implies (previous!=this)
            throw new IllegalStateException("Illegal attempt to add a linker to a list while it has not been removed from another list.");
        }
        if(Debug.ON && this == newNext) {
            throw new IllegalArgumentException("Illegal attempt to link a linker to itself.");
        }
        next = newNext;
        previous = newNext.previous;
        previous.next = this;
        newNext.previous = this;
	}

	/**
	 * Creates a new tab that is flagged as not a header.
	 * @return Tab
	 */
	public static Tab newTab(AtomList list, int type) {
		return new Tab(list, type);
	}
	/**
	 * Creates a new tab that is flagged as being a header of a list.
	 * @return Tab
	 */
	public static Tab newHeader(AtomList list) {
		return new Tab(list, Tab.HEADER_TAB);
	}

    /**
     * Linker that does not reference an atom, but is used to hold or index
     * a position in the linked list.  This is the only type of linker that
     * can have a null atom field.  Tabs also hold references to each other in
     * the list, so it is possible to just directly from one tab to the next
     * (or previous) via the nextTab and previousTab fields.
     */
    public static class Tab extends AtomLinker {
        public Tab nextTab, previousTab;
        public AtomList list;
        private static int lastType = 0;
        public final int type;
        public final static int HEADER_TAB = Tab.requestTabType();
        public final static int ANY_TAB = 0xFFFFFFFF;
        /**
         * Private constructor.  Use AtomLinker methods newTab or newHeader, as
         * appropriate, to make new instance.
         * @param isHeader
         */
        private Tab(AtomList list, int type) {
            super(null);
            nextTab = previousTab = this;
            this.list = list;
            this.type = type;
        }
        
        public static int requestTabType() {
        	if (lastType == 0) {
        		lastType = 1;
        		return lastType;
        	}
        	// would java allow 32?
        	if (lastType == 1<<31) {
        		throw new RuntimeException("Too many tab types.  You can only have 31");
        	}
        	lastType = lastType << 1;
        	return lastType;
        }
        
        public final boolean isHeader() {return type == HEADER_TAB;}
        
        /**
         * Removes references to previous/next tabs while removing linker from list.
         */
        public void remove() {
        	if(isHeader()) throw new RuntimeException("Illegal attempt to remove header from list");
            super.remove();
	        previousTab.nextTab = nextTab;
	        nextTab.previousTab = previousTab;
	        nextTab = previousTab = this;
	        list = null;
        }
        
        /**
         * Adds references to previous/next tabs while adding the linker to the position
         * behind the given one.  Given linker must be in the list for this tab, otherwise
         * an IllegalArgumentException is thrown and the state of this tab is unchanged.
         */
        public void addBefore(AtomLinker newNext) {
	        nextTab = findNextTab(newNext);
	        this.list = nextTab.list;
            super.addBefore(newNext);
 	        previousTab = nextTab.previousTab;
	        previousTab.nextTab = this;
	        nextTab.previousTab = this;
	    }
       /**
        * Finds and returns the first Tab linker beginning at or after the given linker.
        */
        private AtomLinker.Tab findNextTab(AtomLinker e) {
            while(e.atom != null) e = e.next;
            return (AtomLinker.Tab)e;
        }
            
    }//end of Tab
        
}//end of AtomLinker

@@ -924,20 +924,39 @@
 ove() %7B%0A
-%09
    
+     if (Debug.ON &&
  previou
@@ -966,64 +966,451 @@
 ext 
+!
 = 
-next;%0A%09    next.previous = previous;%0A%09
+this %7C%7C next.previous != this) %7B%0A            System.out.println(%22in AtomLinker.remove, this=%22+this+%22 previous.next=%22+previous.next+%22 next.previous=%22+next.previous);%0A            System.out.println(%22in AtomLinker.remove, atom=%22+atom+%22 previous.next.atom=%22+previous.next.atom+%22 next.previous.atom=%22+next.previous.atom);%0A 
     
-if(Debug.ON)
+       throw new RuntimeException(%22stop it%22);%0A        %7D%0A%09    previous.next = next;%0A%09    next.previous = previous;%0A%09   
  nex

add better debugging check and make thorough linker removal non-debug