/*******************************************************************************
 * Copyright (C) 2017 Philipp Spohr
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 ******************************************************************************/
package de.hhu.ba.yoshikoWrapper.graphModel;

import java.util.ArrayList;
import java.util.HashMap;

import org.cytoscape.model.CyEdge;
import org.cytoscape.model.CyNetwork;
import org.cytoscape.model.CyNode;
import org.cytoscape.model.subnetwork.CySubNetwork;
import org.cytoscape.view.layout.CyLayoutAlgorithm;
import org.cytoscape.view.model.CyNetworkView;
import org.cytoscape.view.presentation.property.BasicVisualLexicon;
import org.cytoscape.view.vizmap.VisualStyle;
import org.cytoscape.view.vizmap.mappings.ContinuousMapping;
import de.hhu.ba.yoshikoWrapper.core.CyCore;
import de.hhu.ba.yoshikoWrapper.core.LocalizationManager;

public class YoshikoSolution {
	
	private CyNetwork originalGraph;
	
	public ArrayList<YoshikoCluster> cluster;
	public int id;
	
	public YoshikoSolution(CyNetwork originalGraph) {
		cluster = new ArrayList<YoshikoCluster>();
		this.originalGraph = originalGraph;
	}

	/**
	 * Transforms this solution in a meta-graph where each cluster is represented by one node
	 * The nodes are linked to subgraphs representing the cluster and also their size is scaled relative to cluster size
	 */
	public void exportMetaGraph() {
		
		CyNetwork metaGraph = CyCore.networkFactory.createNetwork();
		
		metaGraph.getRow(metaGraph).set(CyNetwork.NAME, LocalizationManager.get("metaGraph"));
		
		metaGraph.getDefaultNodeTable().createColumn("clusterSize", Integer.class, false);
		metaGraph.getDefaultEdgeTable().createColumn("edgeStrength", Integer.class, false);

		CyLayoutAlgorithm layout = CyCore.layoutAlgorithmManager.getDefaultLayout();

		
		//Map Cluster to Nodes for further reference
		HashMap<YoshikoCluster,CyNode> map = new HashMap<YoshikoCluster,CyNode>();
		
		
		//Add nodes
		for (YoshikoCluster c: cluster) {
			CyNode clusterNode = metaGraph.addNode();
			CySubNetwork subnet = c.getSubNetwork();
			CyCore.networkManager.addNetwork(subnet);
			//Create network view and register it
			CyNetworkView subnetView = CyCore.networkViewFactory.createNetworkView(subnet);
			CyCore.networkViewManager.addNetworkView(subnetView);
			//layout cluster
			CyCore.dialogTaskManager.execute(
				layout.createTaskIterator(
						subnetView, 
						layout.getDefaultLayoutContext(), 
						CyLayoutAlgorithm.ALL_NODE_VIEWS,
						null
				)
			);
			VisualStyle vs= CyCore.visualStyleFactory.createVisualStyle(CyCore.visualMappingManager.getCurrentVisualStyle());
			CyCore.visualMappingManager.setVisualStyle(vs, subnetView);
			vs.apply(subnetView);
			clusterNode.setNetworkPointer(subnet);
			//Set node attributes
			metaGraph.getRow(clusterNode).set("name", LocalizationManager.get("cluster")+" "+c.getID());
			metaGraph.getRow(clusterNode).set("clusterSize",c.getSize());
			map.put(c, clusterNode);
		}
		
		//Add edges (O(|C|^2*|V|^2) can maybe be improved? //TODO
		for (YoshikoCluster c1:cluster) {
			for (YoshikoCluster c2:cluster) {
				if (
						metaGraph.containsEdge(map.get(c1),map.get(c2))
						|| c1 == c2
						) {
					continue;
				}
				for (CyNode c1n : c1.getSubNetwork().getNodeList()) {
					for (CyNode c2n : c2.getSubNetwork().getNodeList()) {
						if (originalGraph.containsEdge(c1n, c2n) || originalGraph.containsEdge(c2n, c1n)) {
							if (metaGraph.containsEdge(map.get(c1), map.get(c2))){
								//TODO: Update weight
							}
							else {
								CyEdge edge = metaGraph.addEdge(map.get(c1), map.get(c2), false);
								metaGraph.getRow(edge).set("edgeStrength",1);
							}
						}
					}
				}
			}
		}
		
		CyNetworkView view = CyCore.networkViewFactory.createNetworkView(metaGraph);
		//layout solution
		CyCore.dialogTaskManager.execute(
			layout.createTaskIterator(
					view, 
					layout.getDefaultLayoutContext(), 
					CyLayoutAlgorithm.ALL_NODE_VIEWS,
					null
			)
		);
		
		CyCore.networkManager.addNetwork(metaGraph);
		CyCore.networkViewManager.addNetworkView(
				view
		);
		
		//define style for solution
		ContinuousMapping<Integer, Double> contMap = (ContinuousMapping<Integer, Double>)CyCore.continuousMappingFactory.createVisualMappingFunction(
				"clusterSize",
				Integer.class,
				BasicVisualLexicon.NODE_SIZE
			);

		VisualStyle vs= CyCore.visualStyleFactory.createVisualStyle(CyCore.visualMappingManager.getCurrentVisualStyle());
		vs.addVisualMappingFunction(contMap);
		CyCore.visualMappingManager.addVisualStyle(vs);
		CyCore.cy.setCurrentNetworkView(view);
		//Apply visual style
		CyCore.visualMappingManager.setVisualStyle(vs, view);
		vs.apply(view);
		view.updateView();

	}
	
}