/**This is a class that represents an edge,
***Written by Chris Hanusa on January 26, 2006.
**/

class Edge
{
    /***An edge has an initial node, a terminal node, and a list of gains.
     The list of gains represents multiple edges with different gains. ***/
    private Node initial;      
    private Node terminal;
    private int[] gain;       

    /***We only allow the user to declare an edge if all three data types are supplied.***/
    Edge(Node a, Node b, int[] c)
    {
	this.initial=a;
	this.terminal=b;
	this.gain=c;
    }

    /***If we want to modify the private data in the edge, we must use these methods.***/
    public void change(Node a, Node b, int[] c)
    {
	this.initial=a;
	this.terminal=b;
	this.gain=c;
    }
    public void new_init(Node a)
    {
	this.initial=a;
    }
    public void new_term(Node a)
    {
	this.terminal=a;
    }    
    public void new_gain(int[] c)
    {
	this.gain=c;
    }

    /***If we want to add one or more gains to the list of gains, we use this method.  
	Defined for additional gains below.***/
    public void add_gain(int c)   
    {                             
	boolean contains = false;    //First, check to see if the list of gains already 
        int ii;	                     //contains the element to be added.                   
	for(ii=0;ii<gain.length;ii++)
	    {   if(!contains) contains = gain[ii]==c;
	    }
	if(!contains)            // If not, then create a new list of gains and put
	    {                    // the new gain at the end.
		int[] new_gain = new int[this.gain.length+1];   
		int j;
		for(j=0;j<this.gain.length;j++)
		    new_gain[j]=this.gain[j];
		new_gain[this.gain.length] = c;
		this.gain = new_gain;
//System.out.println("Gain added.");
	    }
//else
//   System.out.println("Duplicate gain ignored.");
    }

    public void add_gain(int[] c)
    {
	int ii=0;
	for(ii=0;ii<c.length;ii++)
	    {
		this.add_gain(c[ii]);
	    }	    
    }                             

    /***If we want to remove one gains from the list of gains, we use this method.  ***/
    public void remove_gain(int c) 
    {                             
	boolean contains = false;            //Keeps track if the gain is in the list so far.
        int ii = 0;	                     //Counter                   
	int glength = this.gain.length;      //Length of the current list of gains.
	int[] new_Gain = new int[glength-1]; //A new list containing the gains to keep.
	do
	{
	    if(!contains)                       //As long as we haven't seen the gain yet,
	    {
      		contains = this.gain[ii]==c;    //We redefine contains to be true only if the gain is the next one in the list.
	    }
	    if(this.gain.length!=ii+1)          //If we're not at the end of the list, add the element to the new list.
	    { 
		if(contains)  new_Gain[ii]=this.gain[ii+1];
		else new_Gain[ii]=this.gain[ii];
	    }
	    else                                //If we are at the end of the list, and the gain was found,
	    {	
       		if(contains) 
		{ 
		    this.gain=new_Gain;         //then redefine this.gain to be the new list.Otherwise, leave it alone.
//System.out.println("Gain " + c + " deleted.");
		}
//else  System.out.println("The gain to be deleted was not found in the list. Gains unchanged");
	    }
	    ii++;
	}
	while(ii<glength);  //Tells us where to stop.
     }

    /***In case you want to turn the edge around.***/
    public void orient()  
    {
	Node placeholder = this.initial;
	this.initial = this.terminal;
	this.terminal = placeholder;
	int i;
	for(i=0;i<this.gain.length;i++)
	    this.gain[i] = this.gain[i]*(-1);
    }

    /***The data in an edge are private.  In order to access them, use these methods.***/
    public Node initial()       //Since you can't access the variables, 
    {
	return this.initial;   //this tells what the initial Node is.
    }
    public int initial_name()       //Since you can't access the variables, 
    {
	return this.initial.name();   //this tells what the initial Node is.
    }
    public int initial_weight() 
    {
	return this.initial.weight();   //this tells what the weight of the initial vertex is.
    }
    public Node terminal()
    {
	return this.terminal;  //and this tells what the terminal vertex is.
    }
    public int terminal_name()
    {
	return this.terminal.name();  //and this tells what the terminal vertex is.
    }
    public int terminal_weight()
    {
	return this.terminal.weight();   //this tells what the weight of the terminal vertex is.
    }
    public int[] gain()
    {
	return this.gain;
    }

    /** Determine if this edge is a loop.**/
    public boolean isloop()
    {
	return(this.initial_name()==this.terminal_name());
    }

    /***A toString method gives a way for System.out.print() to print more than just a useless pointer.***/
    /***Here we output the initial and terminal nodes along with the list of gains.***/
    public String toString()
    {
	String output= new String();  //makes the output string and then
	output = this.initial_name() + " -> " + this.terminal_name() + ", with gain(s): " + this.print_gain();
	return output;
    }
    public String print_gain()
    {
        int i;
        String output = new String();
        output = "{";
	for(i=0;i<this.gain.length-1;i++)
	    output = output + this.gain[i] + ",";
	output = output + this.gain[this.gain.length-1] + "}";
	return output;
    }

}
