code: /*
   *This file is part of AdmissibleFPG.
   *
   * Copyright (C) 2014 William Pettersson <william@ewpettersson.se>
   *
   *    AdmissibleFPG 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 3 of the License, or
   *    (at your option) any later version.
   *
   *    AdmissibleFPG 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 AdmissibleFPG.  If not, see <http://www.gnu.org/licenses/>.
   */
  package se.ewpettersson.admissiblefpg;
  
  import java.util.ArrayList;
  import java.util.List;
  
  public class EdgeConfig {
  	
  	public class Pair {
  		TFE[] pair;
  		int degree;
  		public Pair(TFE a, TFE b) {
  			super();
  			pair = new TFE[2];
  			pair[0] = a;
  			pair[1] = b;
  			degree = 1;
  		}
  
  		public Pair(TFE a, TFE b, int d) {
  			super();
  			pair = new TFE[2];
  			pair[0] = a;
  			pair[1] = b;
  			degree = d;
  		}
  		
  		public Pair clone() {
  			Pair p = new Pair(pair[0],pair[1],degree);
  			return p;
  		}
  		
  		public TFE[] getPairs() {
  			return pair;
  
  		}
  
  		public void increaseDegree(int i) {
  			degree+=i;
  			
  		}
  
  		public boolean degreeOk() {
  			return degree >= 4;
  		}
  		
  		public String toString() {
  			return "{" + pair[0].toString() + "," + pair[1].toString() + "}";
  		}
  		
  	}
  	
  	
  	List<Pair> pairs;
  	
  	public EdgeConfig() {
  		super();
  		pairs = new ArrayList<Pair>();
  		
  
  	}
  
  	public EdgeConfig(EdgeConfig ec) {
  		pairs = new ArrayList<Pair>();
  		for(Pair entry: ec.getPairs()) {
  			Pair newEntry = (Pair) entry.clone();
  			pairs.add(newEntry);
  		}
  	}
  
  	public List<Pair> getPairs() {
  		return pairs;
  	}
  
  	public void addTetrahedra(int i) {
  		TFE[] pair = new TFE[2];
  
  		pair[0] = new TFE(i,2,1);
  		pair[1] = new TFE(i,3,1);
  		pairs.add(new Pair(pair[0],pair[1]));
  		
  		pair = new TFE[2];
  		pair[0] = new TFE(i,1,2);
  		pair[1] = new TFE(i,3,2);
  		pairs.add(new Pair(pair[0],pair[1]));
  		
  		pair = new TFE[2];
  		pair[0] = new TFE(i,1,3);
  		pair[1] = new TFE(i,2,3);
  		pairs.add(new Pair(pair[0],pair[1]));
  		
  		pair = new TFE[2];
  		pair[0] = new TFE(i,0,4);
  		pair[1] = new TFE(i,3,4);
  		pairs.add(new Pair(pair[0],pair[1]));
  		
  		pair = new TFE[2];
  		pair[0] = new TFE(i,0,5);
  		pair[1] = new TFE(i,2,5);
  		pairs.add(new Pair(pair[0],pair[1]));
  		
  		pair = new TFE[2];
  		pair[0] = new TFE(i,0,6);
  		pair[1] = new TFE(i,1,6);
  		pairs.add(new Pair(pair[0],pair[1]));
  		
  	}
  	
  
  	
  	public int numPairs() {
  		return pairs.size();
  	}
  	
  	public boolean addGluing(TFE [] gluing) {
  		TFE pairOne = null;
  		Pair removePair = null;
  		int degree_increase = 0;
  
  		if (gluing[0].tet == gluing[1].tet && gluing[0].edge == gluing[1].edge) {
  //			System.out.println("Loop?");
  //			System.out.println(gluing[0].toString());
  //			System.out.println(gluing[1].toString());
  			degree_increase = 1;
  		}
  		for(Pair pair : pairs) {
  			int o = pair.pair[0].orientTo(gluing[0]);
  			if (o != 0) {
  				int o2 = pair.pair[1].orientTo(gluing[1]);
  				if (o2 == o) {
  					// MINIMAL
  					pair.increaseDegree(degree_increase);
  					if (!pair.degreeOk()) {
  						//System.out.println("Low degree edge!");
  						return false;
  					}
  					// Can remove this pair as it's being closed up.
  					pairs.remove(pair);
  					return true;
  				}
  				if (o2 == -o) {
  					// Gluing edge to itself in reverse
  					//System.out.println("Edge to itself!");
  					return false;
  				}
  				if (pairOne == null) {
  					pairOne = pair.pair[1];
  					if (o==-1) {
  						pairOne.edge=-pairOne.edge;
  					}
  					removePair = pair;
  					degree_increase += pair.degree;
  				} else {
  					if (o==-1) {
  						pairOne.edge=-pairOne.edge;
  					}
  					pair.pair[0] = pairOne;
  					pair.increaseDegree(degree_increase);
  					
  					pairs.remove(removePair);
  					return true;
  				}
  			}
  			o = pair.pair[1].orientTo(gluing[0]);
  			if (o != 0) {
  				int o2 = pair.pair[0].orientTo(gluing[1]);
  				if (o2 == o) {
  					// MINIMAL
  					pair.increaseDegree(degree_increase);
  					if (!pair.degreeOk()) {
  						//System.out.println("Low degree edge!");
  						return false;
  					}
  					// Can remove this pair as it's being closed up.
  					pairs.remove(pair);
  					return true;
  				}
  				if (o2 == -o) {
  					// Gluing edge to itself in reverse
  					//System.out.println("Edge to itself!");
  					return false;
  				}
  				if (pairOne == null) {
  					pairOne = pair.pair[0];
  					if (o==-1) {
  						pairOne.edge=-pairOne.edge;
  					}
  					removePair = pair;
  					degree_increase += pair.degree;
  				} else {
  					if (o==-1) {
  						pairOne.edge=-pairOne.edge;
  					}
  					pair.pair[1] = pairOne;
  					pair.increaseDegree(degree_increase);
  					pairs.remove(removePair);
  					return true;
  				}
  			}
  			o = pair.pair[0].orientTo(gluing[1]);
  			if (o != 0) {
  				if (pairOne == null) {
  					pairOne = pair.pair[1];
  					if (o==-1) {
  						pairOne.edge=-pairOne.edge;
  					}
  					removePair = pair;
  					degree_increase += pair.degree;
  				} else {
  					if (o==-1) {
  						pairOne.edge=-pairOne.edge;
  					}
  					pair.pair[0] = pairOne;
  					pair.increaseDegree(degree_increase);
  					pairs.remove(removePair);
  					return true;
  				}
  			}
  			o = pair.pair[1].orientTo(gluing[1]);
  			if (o != 0) {
  				if (pairOne == null) {
  					pairOne = pair.pair[0];
  					if (o==-1) {
  						pairOne.edge=-pairOne.edge;
  					}
  					removePair = pair;
  					degree_increase += pair.degree;
  				} else {
  					if (o==-1) {
  						pairOne.edge=-pairOne.edge;
  					}
  					pair.pair[1] = pairOne;
  					pair.increaseDegree(degree_increase);
  					pairs.remove(removePair);
  					return true;
  				}
  			}
  
  			 
  		}
  		//System.out.println("Bad!");
  		return false;
  	}
  	
  	public String toString() {
  		String s= "[";
  		for(Pair pair : pairs) {
  			TFE[] p = pair.getPairs();
  			s+= "["+ p[0].toString() + " to " + p[1].toString() + "], ";
  		}
  		if (s.endsWith(", ")) {
  			s = s.substring(0,s.length()-2);
  		}
  		return s + "]";
  	}
  
  	public boolean pairs(TFE p1, TFE p2) {
  		for(Pair pair : pairs) {
  			TFE[] p = pair.getPairs();
  			if ((p[0] == p1 && p[1] == p2) || (p[0] == p2 && p[1] == p1)) {
  				return true;
  			}
  		}
  		return false;
  	}
  	
  	public boolean equals(EdgeConfig other) {
  		for(Pair pair : pairs) {
  			TFE[] p = pair.getPairs();
  			if( ! other.pairs(p[0], p[1])) {
  				return false;
  			}
  		}
  		return true;
  	}
  
  	public void mergeWith(EdgeConfig ec) {
  		pairs.addAll(ec.getPairs());
  		
  	}
  	
  	public boolean onBoundary(int tet, int face) {
  		for (Pair p: pairs) {
  			if (p.pair[0].tet == tet && p.pair[0].face == face) {
  				return true;
  			}
  			if (p.pair[1].tet == tet && p.pair[1].face == face) {
  				return true;
  			}
  		}
  		return false;
  	}
  
  }
  