package vnt;
/**
 * Node.java - v1.0
 * Began: June 30, 2005
 * Last Updated: July 21, 2005 
 * 
 * Copyright (C) 2005 - Michael D. Miller - mdm162@truman.edu
 * Truman State University
 * 100 E. Normal
 * Kirksville, MO - 63501
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */


/**
 * <p>A class that holds the circular (X,Y) coordinate center,
 * radius data, and adjacency list information.
 * Acts as a Graph Theory node (vertex).</p>
 * 
 * <p>Note: This class is used heavily by the Node_Analysis
 * plug-in, which is still very recent and needs significant
 * testing. As a result, this class has a large number of print
 * statements for debugging purposes.</p> 
 *  
 * @author Michael Miller - Truman State University
 * @version 1.0
 * @since 1.0
 */
class Node {
    /**
     * The x-coordinate (in the image) of this node.
     */
    private int x;
    /**
     * The y-coordinate (in the image) of this node.
     */
    private int y;
    /**
     * The radius (in pixels) of this node.
     */
    private int radius;
    /**
     * The adjacency list for this node.
     * The list points to an instantiated Node_LinkedList who's
     * myNode == this.
     */
    private Node_LinkedList adjacent;
    /**
     * The number of adjacencies to this node.
     * This is not merely the size of the list 'adjacent', as that contains
     * a link to this node. The adjacencyCount is the number of other
     * nodes connected to this one. 
     */
    private int adjacencyCount;
    
    /**
     * Initializes the class with the given information.
     * 
     * @param myX The x-coordinate of the pixel.
     * @param myY The y-coordinate of the pixel.
     * @param myColor The grayscale color value of the pixel.
     */
    public Node (int myX, int myY, int myRadius) {
        x = myX;
        y = myY;
        radius = myRadius;
        adjacencyCount = 0;
        adjacent = new Node_LinkedList(this);
    }

    /**
     * Adds a given node to the adjacency list.
     * Also adds this to the given node's adjacency list (preserves symmetry).
     * 
     * <p>Pre: The given node must exist and the local member adjacent must be non-null. Assumes the list is not improperly linked (broken chains, infinite loops, etc)
     * <br />Post: If the node was not a duplicate, then it is added to the adjacency list of this node. Symmetry is preserved. 
     * @param addMe The node to add to the adjacency list.
     * @return Returns whether the connection was new (and therefore added) or not.
     * @see #listInsert
     */
    public boolean addAdjacency(Node addMe) {
        if ((addMe == null) || (adjacent == null)) {
            return false;
        }
        boolean added = false;
        if (adjacent.listInsert(addMe)) {
            added = true;
            adjacencyCount ++;
            // make sure the symmetry is preserved
            addMe.addAdjacency(this);
        }
        return added;
    }

    /**
     * This node is kept. The given node mergeMe is deleted.
     * All the connections mergeMe had are added to this node.
     * Since topological information is the only concern,
     * we are interested in preserving the structure of the graph only.
     * The only reason node location needs adjustment is the possibility
     * of capturing more node overlap.
     * 
     * <p>Pre: The given node must exist and the local member adjacent must be non-null. Assumes the list is not improperly linked (broken chains, infinite loops, etc)
     * <br />Post: This node gains all the non-duplicate connections (with symmetry preserved) of mergeMe. In addition, mergeMe is dissolve()'d.  
     * @param mergeMe The node to be deleted. All information is unioned to this node.
     * @see #listUnion
     * @see #dissolve
     */ 
    public void mergeNodes(Node mergeMe) {
        if ((mergeMe == null) || (adjacent == null)) {
            return;
        }
        int amount, myX, myY;
        // add mergeMe's connections to this        
        amount = adjacent.listUnion(mergeMe.getAdjacency(), true);
        // destroy mergeMe's connections
        amount = mergeMe.dissolve();
        // adjust coordinates of this node
        myX = radius*radius*x + mergeMe.getRadius()*mergeMe.getRadius()*mergeMe.getX();
        myY = radius*radius*y + mergeMe.getRadius()*mergeMe.getRadius()*mergeMe.getY();
        
        x= myX / (radius*radius+mergeMe.getRadius()*mergeMe.getRadius());
        y= myY / (radius*radius+mergeMe.getRadius()*mergeMe.getRadius());
        // take the max
        if (radius < mergeMe.getRadius()) {
            radius = mergeMe.getRadius();
        }// else, stay the same
    }
    
    /**
     * Kill the adjacency linked list.
     * Preserves symmetry (adjacent nodes lose reference to this one).
     * 
     * <p>Pre: This adjacent must not be null.
     * <br />Post: Removes all adjacencies this node has with other nodes. Preserves symmetry.
     * @return Returns the number of adjacent connections that were dissolved.
     * @see #listDissolve
     */
    public int dissolve() {
        if (adjacent == null) {
            return 0;
        }
        return adjacent.listDissolve(true);
    }
    
    /**
     * Searches this node's adjacency list for the given node.
     * If it is found, it is removed.
     * 
     * <p>Pre: This adjacent must not be null.
     * <br />Post: Searches all adjacencies this node has with other nodes. If the given node is found, the connection is deleted. Preserves symmetry.
     * @param removeMe The node to search for. If it is found, it is deleted.
     * @return Returns whether or not the node was found (and consequently removed).
     * @see #listDeleteItem
     */
    public boolean removeAdjacency(Node removeMe) {
        if (adjacent == null) {
            return false;
        }
        boolean removed = false;
        if (adjacent.listDeleteItem(removeMe)) {
            removed = true;
            adjacencyCount --;
            // make sure the symmetry is preserved
            if (!((x == removeMe.getX()) && (y == removeMe.getY()))) {
                removeMe.removeAdjacency(this);
            }
        }
        return removed;
    }
    
    /**
     * A standard accessor to the adjacency list variable.
     * <p>Pre: This class must exist.
     * <br />Post: No change.
     * @return Returns the adjacency list for this node.
     * @see #adjacent
     */
    public Node_LinkedList getAdjacency () {
        return adjacent;
    }
    
    /**
     * Returns the number of nodes in the adjacency list.
     * Nodes cannot be identical (same X and Y coordinate).
     * <p>Pre: This class must exist.
     * <br />Post: No change.
     * @return Returns the number of nodes in the adjacency list.
     * @see #adjacencyCount
     */
    public int getAdjacencySize() {
        return adjacencyCount;
    }

    /**
     * Accessor for X variable.
     * <p>Pre: This class must exist.
     * <br />Post: No change.
     * @return x pixel coordinate value
     * @see #x
     */ 
    public int getX() {
        return x;
    }

    /**
     * Accessor for Y variable.
     * <p>Pre: This class must exist.
     * <br />Post: No change.
     * @return y pixel coordinate value
     * @see #y
     */ 
    public int getY() {
        return y;
    }

    /**
     * Accessor for radius variable.
     * <p>Pre: This class must exist.
     * <br />Post: No change.
     * @return radius radius pixel distance value
     * @see #radius
     */ 
    public int getRadius() {
        return radius;
    }
}