package de.hhu.ba.yoshikoWrapper.cytoUtil;

import java.util.List;

import org.cytoscape.model.CyColumn;
import org.cytoscape.model.CyEdge;
import org.cytoscape.model.CyNetwork;
import org.cytoscape.model.CyRow;
//import org.slf4j.Logger;

//import de.hhu.ba.yoshikoWrapper.logging.YoshikoLogger;


public class GraphAnalyzer {

	//private static Logger logger = YoshikoLogger.getInstance().getLogger();

	public static boolean isMultiGraph(CyNetwork net) {
		//TODO: Better algorithm?


		int n = net.getNodeCount();
		List<CyEdge> edges = net.getEdgeList();

		//Easiest check: Check if the graph contains more edges than a complete graph
		if (edges.size() > (n*(n-1))/2) {
			return true;
		}

		for (int i = 0; i < edges.size()-1; i++) {
			for (int j=i+1; j<edges.size();j++) {
				if (connectSameNodes(edges.get(i),edges.get(j))){
					return true;
				}
			}
		}

		return false;
	}

	/**
	 * Checks whether two edges connect the same pair of nodes
	 * This function is symmetric
	 * @param e1 An arbitrary CyEdge
	 * @param e2 An arbitrary CyEdge
	 * @return true if the edges connect the same pair of nodes, false otherwise
	 */
	private static boolean connectSameNodes(CyEdge e1, CyEdge e2) {
		if (//Treating all edges as undirected here
				(e1.getSource() == e2.getTarget() && e1.getTarget() == e2.getSource()) ||
				(e1.getSource() == e2.getSource() && e1.getTarget() == e2.getTarget())
				) {
			return true;
		}
		return false;
	}

	public static boolean isDirected(CyNetwork net) {
		for (CyEdge e: net.getEdgeList()) {
			if (e.isDirected()) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Generates a fitting bitmask by choosing the reduction rules that appear to be the best choice based on current research
	 * @param containsRealValues
	 * @param heuristic
	 * @return The bitmask as a String
	 */
	public static String suggestReductionRules(boolean containsRealValues, boolean heuristic) {

		//TODO: Maybe also choose SNR Factor?
		//TODO: More research, identify good rules

		boolean useCRule = false,useCCRule= false,useACRule= false,useHERule= false,usePDRRule= false,useSNRule = false;
		String ret = "";

		//First of all: We don't choose any rules when in heuristic mode
		if (!heuristic) {
			//We check if the graph contains real weights
			if (!containsRealValues) {
				useCRule = true;
				useCCRule = true;
				useACRule = true;
				useHERule = true;
			}
			usePDRRule = true;
			useSNRule = true;
		}

		ret += (useCRule ? "1" : "0");
		ret += (useCCRule ? "1" : "0");
		ret += (useACRule ? "1" : "0");
		ret += (useHERule ? "1" : "0");
		ret += (usePDRRule ? "1" : "0");
		ret += (useSNRule ? "1" : "0");

		//logger.info("Suggesting the following reduction-rules bitmask: "+ret);
		System.out.println("Suggesting the following reduction-rules bitmask: "+ret);

		return ret;
	}

	public static boolean containsRealValues(
			CyNetwork net,
			CyColumn weightColumn,
			CyColumn permanentColumn,
			CyColumn forbiddenColumn,
			double defaultInsertionCost,
			double defaultDeletionCost)
	{
		//Simple checks: Deletion and Insertion Costs
		if (defaultInsertionCost % 1 != 0 || defaultDeletionCost % 1 != 0) {
			return true;
		}

		if (net != null){
			//Fetch edges
			List<CyEdge> edges = net.getEdgeList();

			//Loop over edges
			for (CyEdge e : edges) {

				//Fetch entry and check if it exists
				CyRow edgeEntry = net.getRow(e);

				//Check if there is a weight column defined, else skip
				if (weightColumn != null){
					//Check if the column contains an entry for the respective edge
					//It is possible, that there are missing entries
					if (edgeEntry.get(weightColumn.getName(), weightColumn.getType()) != null){
						if (weightColumn.getType() == Double.class) {
							double weight = edgeEntry.get(weightColumn.getName(), Double.class);
							if (weight%1!=0) {
								return true;
							}
						}
					}
				}
			}
		}
		return false;
	}
}