code: package gr.uom.java.ast.metrics;
  
  import gr.uom.java.ast.ClassObject;
  import gr.uom.java.ast.FieldInstructionObject;
  import gr.uom.java.ast.FieldObject;
  import gr.uom.java.ast.MethodInvocationObject;
  import gr.uom.java.ast.MethodObject;
  import gr.uom.java.ast.SystemObject;
  
  import java.util.ArrayList;
  import java.util.LinkedHashMap;
  import java.util.List;
  import java.util.ListIterator;
  import java.util.Map;
  import java.util.Set;
  
  public class LCOM {
  
  	private Map<String, Double> lcom2Map;
  	private Map<String, Double> lcom3Map;
  	
  	public LCOM(SystemObject system) {
  		this.lcom2Map = new LinkedHashMap<String, Double>();
  		this.lcom3Map = new LinkedHashMap<String, Double>();
  		ListIterator<ClassObject> classIterator = system.getClassListIterator();
  		while(classIterator.hasNext()) {
  			ClassObject classObject = classIterator.next();
  			classLCOM(classObject);
  		}
  	}
  	
  	private void classLCOM(ClassObject classObject) {
  		List<FieldObject> fields = new ArrayList<FieldObject>();
  		ListIterator<FieldObject> fieldIterator = classObject.getFieldIterator();
  		while(fieldIterator.hasNext()) {
  			FieldObject field = fieldIterator.next();
  			if(!field.isStatic())
  				fields.add(field);
  		}
  		if(fields.size() == 0) {
  			lcom2Map.put(classObject.getName(), null);
  			lcom3Map.put(classObject.getName(), null);
  		}
  		List<MethodObject> methods = new ArrayList<MethodObject>();
  		List<MethodObject> accessors = new ArrayList<MethodObject>();
  		ListIterator<MethodObject> methodIterator = classObject.getMethodIterator();
  		while(methodIterator.hasNext()) {
  			MethodObject method = methodIterator.next();
  			if(!method.isStatic() && method.getMethodBody() != null) {
  				FieldInstructionObject fieldInstruction = method.isGetter();
  				if(fieldInstruction != null) {
  					accessors.add(method);
  				}
  				if(fieldInstruction == null) {
  					fieldInstruction = method.isSetter();
  					if(fieldInstruction != null) {
  						accessors.add(method);
  					}
  				}
  				if(fieldInstruction == null) {
  					fieldInstruction = method.isCollectionAdder();
  					if(fieldInstruction != null) {
  						accessors.add(method);
  					}
  				}
  				if(fieldInstruction == null)
  					methods.add(method);
  			}
  		}
  		if(methods.size() == 0)
  			lcom2Map.put(classObject.getName(), null);
  		if(methods.size() <= 1)
  			lcom3Map.put(classObject.getName(), null);
  		
  		int sum = 0;
  		for(FieldObject field : fields) {
  			int mA = 0;
  			for(MethodObject method : methods) {
  				boolean found = false;
  				List<FieldInstructionObject> fieldInstructions = method.getFieldInstructions();
  				for(FieldInstructionObject fieldInstruction : fieldInstructions) {
  					if(field.equals(fieldInstruction)) {
  						found = true;
  						break;
  					}
  				}
  				if(found) {
  					mA++;
  				}
  				else {
  					List<MethodInvocationObject> methodInvocations = method.getMethodInvocations();
  					for(MethodInvocationObject methodInvocation : methodInvocations) {
  						if(methodInvocation.getOriginClassName().equals(classObject.getName())) {
  							MethodObject methodObject = classObject.getMethod(methodInvocation);
  							if(accessors.contains(methodObject)) {
  								List<FieldInstructionObject> accessorFieldInstructions = methodObject.getFieldInstructions();
  								FieldInstructionObject accessorFieldInstruction = accessorFieldInstructions.get(0);
  								if(field.equals(accessorFieldInstruction)) {
  									mA++;
  									break;
  								}
  							}
  						}
  					}
  				}
  			}
  			sum += mA;
  		}
  		int a = fields.size();
  		int m = methods.size();
  		if(a > 0 && m > 0) {
  			double lcom2 = 1.0 - (double)sum / (double)(m*a);
  			lcom2Map.put(classObject.getName(), lcom2);
  		}
  		if(a > 0 && m > 1) {
  			double lcom3 = ((double)m - ((double)sum/(double)a)) / ((double)m - 1.0);
  			lcom3Map.put(classObject.getName(), lcom3);
  		}
  	}
  	
  	public double getSystemAverageLCOM2() {
  		Set<String> keySet = lcom2Map.keySet();
  		double sum = 0;
  		int notDefined = 0;
  		for(String key : keySet) {
  			Double value = lcom2Map.get(key);
  			if(value != null)
  				sum += value;
  			else
  				notDefined++;
  		}
  		if(keySet.size() == notDefined)
  			return 0;
  		else
  			return sum/(double)(keySet.size()-notDefined);
  	}
  	
  	public double getSystemAverageLCOM3() {
  		Set<String> keySet = lcom3Map.keySet();
  		double sum = 0;
  		int notDefined = 0;
  		for(String key : keySet) {
  			Double value = lcom3Map.get(key);
  			if(value != null)
  				sum += value;
  			else
  				notDefined++;
  		}
  		if(keySet.size() == notDefined)
  			return 0;
  		else
  			return sum/(double)(keySet.size()-notDefined);
  	}
  }
  