// ** This file was generated with DemFGen (vers:4/15/2011)

package nwf;

import edu.neu.ccs.demeterf.lib.*;
import edu.neu.ccs.demeterf.lib.*;
import scg.*;
import edu.neu.ccs.demeterf.lib.*;
import edu.neu.ccs.demeterf.*;
import java.util.Iterator;





/** Representation of NWFInstance */
public class NWFInstance implements InstanceI{
    protected EdgeLabeledGraph<Node, EdgeCapacity, EdgeFlow> g;
    protected Node source;
    protected Node sink;

    /** Construct a(n) NWFInstance Instance */
    public NWFInstance(EdgeLabeledGraph<Node, EdgeCapacity, EdgeFlow> g, Node source, Node sink){
        this.g = g;
        this.source = source;
        this.sink = sink;
    }
    /** Is the given object Equal to this NWFInstance? */
    public boolean equals(Object o){
        if(!(o instanceof NWFInstance))return false;
        if(o == this)return true;
        NWFInstance oo = (NWFInstance)o;
        return (((Object)g).equals(oo.g))&&(((Object)source).equals(oo.source))&&(((Object)sink).equals(oo.sink));
    }
    /** Parse an instance of NWFInstance from the given String */
    public static NWFInstance parse(String inpt) throws nwf.ParseException{
        return new nwf.TheParser(new java.io.StringReader(inpt)).parse_NWFInstance();
    }
    /** Parse an instance of NWFInstance from the given Stream */
    public static NWFInstance parse(java.io.InputStream inpt) throws nwf.ParseException{
        return new nwf.TheParser(inpt).parse_NWFInstance();
    }
    /** Parse an instance of NWFInstance from the given Reader */
    public static NWFInstance parse(java.io.Reader inpt) throws nwf.ParseException{
        return new nwf.TheParser(inpt).parse_NWFInstance();
    }

    /** Field Class for NWFInstance.g */
    public static class g extends edu.neu.ccs.demeterf.Fields.any{}
    /** Field Class for NWFInstance.source */
    public static class source extends edu.neu.ccs.demeterf.Fields.any{}
    /** Field Class for NWFInstance.sink */
    public static class sink extends edu.neu.ccs.demeterf.Fields.any{}


	/**
	 * Checks if a solution is valid with respect to this nwfInstance.
	 * 
	 * @author liangyu  1st April
	 * @param SolutionI solution, Config config
	 * @return 1, if valid; 0 if invalid.
	 */
	
	public double valid(SolutionI solution, Config config) {

		/**
		 *  Cast the SolutionI object to a NWFSolution object,
		 *  if cannot be casted, return 0;
		 */
		double retVal = 0;
		NWFSolution nwfSolution = null;
		
		if (solution instanceof NWFSolution) {
			nwfSolution = (NWFSolution) solution;
		} else {
			return retVal;
		}
		
		String source = nwfSolution.getSource().getV();
		String sink = nwfSolution.getSink().getV();
		
		if (areAllNodeFlowBalanced(nwfSolution.getG(), source, sink) 
			    && areAllEdgeFlowValid(nwfSolution.getG())) {
			retVal = 1;
		} else {
			retVal = 0;
		}
		
		return retVal;
	}
	
	/**
	 * check whether all the nodes are flow balanced
	 * @param g
	 * @return
	 */
	private boolean areAllNodeFlowBalanced(
			EdgeLabeledGraph<Node, EdgeCapacity, EdgeFlow> g,
			String source, String sink) {

		Iterator<Adjacency<Node, EdgeCapacity, EdgeFlow>> i 
	        = g.getAdjs().iterator();
		
		for (;i.hasNext();) {
			
			// keep the element in the iterator in a tmp variable,
			// or else it causes some problem in the next step.
			Adjacency<Node, EdgeCapacity, EdgeFlow> tmpA = i.next();
			Node n = tmpA.getSource(); 
			// node not source,not sink

			if (!(n.getV().equals(source)) && !(n.getV().equals(sink))) {
				
				// it works well, tested.
				int outFlowValue = getNodeOutFlowValue(tmpA);
				
				// get the rest list of adjacency
				List<Adjacency<Node, EdgeCapacity, EdgeFlow>> tempList 
				    = g.getAdjs().remove(tmpA);
				
				int inFlowValue = getNodeInFlowVaue(n, tempList);
				
				if (!(outFlowValue == inFlowValue)) {
					return false;
				}
			}
		}
		
        return true;
	}	

	/**
	 * for a perticular node, get the in flow value
	 * @param n
	 * @param tempList
	 * @return
	 */
	private int getNodeInFlowVaue(Node n,
			List<Adjacency<Node, EdgeCapacity, EdgeFlow>> tempList) {
		int inFlowValue = 0;

		Iterator<Adjacency<Node, EdgeCapacity, EdgeFlow>> i =
			tempList.iterator();
		
		for (;i.hasNext() ;) {
			Adjacency<Node, EdgeCapacity, EdgeFlow> tmp = i.next();
			
			Iterator<NodeAndLabel<Node, EdgeCapacity, EdgeFlow>> i1 =
				tmp.getSuccessors().iterator();
			
			for (;i1.hasNext() ;) {
				NodeAndLabel<Node, EdgeCapacity, EdgeFlow> tmp1 = i1.next();
				
				
				if (n.getV().equals(tmp1.getN().getV())) {
					inFlowValue += tmp1.getLabel2().getV();
				}
			}
		}
		return inFlowValue;
	}
	
	/**
	 * for a particular node, get the outside flow value
	 * @param adj
	 * @return
	 */
	
	private int getNodeOutFlowValue(Adjacency<Node, EdgeCapacity, EdgeFlow> adj) {
		int outFlowValue = 0;
		
		Iterator<NodeAndLabel<Node, EdgeCapacity, EdgeFlow>> i =
			adj.getSuccessors().iterator();
		
		for (;i.hasNext() ;) {
			NodeAndLabel<Node, EdgeCapacity, EdgeFlow> tmp = i.next();
			outFlowValue += tmp.getLabel2().getV();
		}
		
		return outFlowValue;
	}
	
	
	
	private boolean areAllEdgeFlowValid(
			EdgeLabeledGraph<Node, EdgeCapacity, EdgeFlow> g) {
		
		Iterator<Adjacency<Node, EdgeCapacity, EdgeFlow>> i 
		    = g.getAdjs().iterator();
		
		for (; i.hasNext();) {
			Adjacency<Node, EdgeCapacity, EdgeFlow> tmpA = i.next();
			
			if (areAllEdgeFlowValidHelper(tmpA.getSuccessors())) {
				return true;
			}
			// if find any edgeflow is invalid, just terminate
			// this loop, and return false;
			break;
		}
		return false;
	}
	
	private boolean areAllEdgeFlowValidHelper(
			List<NodeAndLabel<Node, EdgeCapacity, EdgeFlow>> successors) {
		
		Iterator<NodeAndLabel<Node, EdgeCapacity, EdgeFlow>> i = 
			successors.iterator();
		
		for (; i.hasNext();) {
			
			NodeAndLabel<Node, EdgeCapacity, EdgeFlow> tmpN = i.next();
			
			if (tmpN.getLabel2().getV() >
				    tmpN.getLabel1().getV()) {
				return false;
			}
		}
		return true;
	}
	

    /**
     * Calculate the quality of a solution with respect to this
     * nwfInstance.
     *
     * @return double quality
     * @param SolutionI solution
     * @author liangyu 1st April
     */
	public double quality(SolutionI solution) {

		double quality = 0;
		NWFSolution nwfSolution = null;
		
		/* not long avaiable
		if (valid(solution) != 1) {
			System.out.println("solution is invalid," +
					"no quality will be get for it");
		}
		*/
		
		
		nwfSolution = (NWFSolution) solution;
		int flowValue = getValueAtSource(nwfSolution, "flow");
		int capValue = getValueAtSource(nwfSolution, "cap");
		quality = (double)flowValue / capValue;
		
		return quality;
	}
	
	/**
	 * getValueAtSource function, it will call the helper function
	 * getValueAtSourceHelper.
	 * 
	 * @param Flow f
	 * @param String string, two options: 
	 *        "cap" means the value we want to get is the capacity
	 *        "flow" means the value we want to get is the flow
	 * @return int value
	 */
	
	private int getValueAtSource(NWFSolution nwfSolution, String string) {

		int value = 0;
		String source = nwfSolution.getSource().getV();
		
		Iterator<Adjacency<Node, EdgeCapacity, EdgeFlow>> adj1 
		    = nwfSolution.getG().getAdjs().iterator();
		
		for (; adj1.hasNext();) {
			
			Adjacency<Node, EdgeCapacity, EdgeFlow> tmpA = adj1.next();
			
			if (tmpA.getSource().getV().equals(source)) {
				value = getValueAtSourceHelper(tmpA, string);
			}
		}
		return value;
	}
	
	/**
	 * getValueAtSourceHelper Function
	 * 
	 * @param adj2
	 * @param string
	 * @return
	 */
	
	private int getValueAtSourceHelper(
			Adjacency<Node, EdgeCapacity, EdgeFlow> adj2, String string) {

		int result = 0;
		// get every NodeAndLabel element from the list
		Iterator<NodeAndLabel<Node, EdgeCapacity, EdgeFlow>> inl 
		    = adj2.getSuccessors().iterator();
		
		for (; inl.hasNext();) {
			
			NodeAndLabel<Node, EdgeCapacity, EdgeFlow> tmpN = inl.next();
			
			if (string.equals("cap")) {
				result = result + tmpN.getLabel1().getV();
			} else if (string.equals("flow")) {
				result = result + tmpN.getLabel2().getV();
			}
		}
		return result;
	}


    /** DGP method from Class Display */
    public String display(){ return nwf.Display.DisplayM(this); }
    /** DGP method from Class Print */
    public String print(){ return nwf.Print.PrintM(this); }
    /** DGP method from Class ToStr */
    public String toStr(){ return nwf.ToStr.ToStrM(this); }
    /** DGP method from Class PrintToString */
    public String toString(){ return nwf.PrintToString.PrintToStringM(this); }
    /** DGP method from Class HashCode */
    public int hashCode(){ return nwf.HashCode.HashCodeM(this); }
    /** Setter for field NWFInstance.g */
    public void setG(EdgeLabeledGraph<Node,EdgeCapacity,EdgeFlow> _g){ g = _g; }
    /** Setter for field NWFInstance.source */
    public void setSource(Node _source){ source = _source; }
    /** Setter for field NWFInstance.sink */
    public void setSink(Node _sink){ sink = _sink; }
    /** Getter for field NWFInstance.g */
    public EdgeLabeledGraph<Node,EdgeCapacity,EdgeFlow> getG(){ return g; }
    /** Getter for field NWFInstance.source */
    public Node getSource(){ return source; }
    /** Getter for field NWFInstance.sink */
    public Node getSink(){ return sink; }

}


