//PRET-Extractor
//Copyright (c) 2013 Tetsuya Kanda
//
//http://sel.ist.osaka-u.ac.jp/pret/
//
//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 jp.ac.osaka_u.ist.sel.pret.evotree;

import gnu.trove.map.TObjectIntMap;
import gnu.trove.map.hash.TObjectIntHashMap;
import gnu.trove.set.TIntSet;
import gnu.trove.set.hash.THashSet;

import java.nio.file.Path;
import java.util.Collection;
import java.util.Set;

import jp.ac.osaka_u.ist.sel.pret.engine.Target;
import jp.ac.osaka_u.ist.sel.pret.engine.data.DirectedEdge;
import jp.ac.osaka_u.ist.sel.pret.engine.data.DirectedGroup;
import jp.ac.osaka_u.ist.sel.pret.engine.data.Edge;
import jp.ac.osaka_u.ist.sel.pret.engine.data.FileInfo;
import jp.ac.osaka_u.ist.sel.pret.engine.data.Group;
import jp.ac.osaka_u.ist.sel.pret.engine.data.ISimilarity;
import jp.ac.osaka_u.ist.sel.pret.engine.graph.Dot;
import jp.ac.osaka_u.ist.sel.pret.engine.graph.SpanningTree;

/**
 * cost: number of edges between projects<br>
 * direction: size
 * 
 * @author t-kanda
 * 
 */
public class Counter1 extends Counter {
	private TIntSet projects;

	private TObjectIntMap<Edge> count;
	private TObjectIntMap<Edge> incCount;
	private TObjectIntMap<Edge> decCount;

	public Counter1(Target target, ISimilarity similarity) {
		super(target, similarity);

		count = new TObjectIntHashMap<>();
		incCount = new TObjectIntHashMap<>();
		decCount = new TObjectIntHashMap<>();
	}

	public void count(float threshold) {
		Collection<FileInfo> files = target.getCopyOfFileSet();
		for (FileInfo fi1 : files) {
			for (FileInfo fi2 : files) {
				if (fi1.fileId() < fi2.fileId()) {
					Edge edge = new Edge(fi1.fileId(), fi2.fileId());
					if (similarityMap.getSimilarity(edge) >= threshold) {
						int p1 = fi1.projectId();
						int p2 = fi2.projectId();
						if (p1 != p2 && (projects == null || projects.contains(p1) && projects.contains(p2))) {
							// System.out.println(similarityMap.getSimilarity(edge)
							// + ": " + fi1.fileName() + fi1.fileId() + " _ " +
							// fi2.fileName() + fi2.fileId());
							Edge e = new Edge(p1, p2);
							count.put(e, count.get(e) - 1); // negative integer
							incCount.put(e, incCount.get(e) + similarityMap.getInc(edge));
							decCount.put(e, decCount.get(e) + similarityMap.getDec(edge));
						}
					}
				}
			}
		}
		// for (Edge e : count.keySet()) {
		// System.out.println(e + ": " + count.get(e));
		// System.out.println(e + ": " + incCount.get(e));
		// System.out.println(e + ": " + decCount.get(e));
		// }
		// System.out.println();
		// System.out.println(incCount);
		// System.out.println();
		// System.out.println(decCount);
	}

	public Path output(Path outputdir) {

		DummysForApp dummy = new DummysForApp();
		ISimilarity s = dummy.new DummySimilarity(count);
		Group g = new Group('A');
		for (Edge e : count.keySet()) {
			g.addEdge(e);
		}
		g.noGather();
		Group sp = SpanningTree.getSpanningTree(g, s, false);

		Set<DirectedEdge> de = new THashSet<>();
		for (Edge e : sp.edges()) {
			int p1 = e.fileId1();
			int p2 = e.fileId2();
			int fw = incCount.get(e);
			int bw = decCount.get(e);
			if (fw > bw) {
				de.add(new DirectedEdge(p1, p2));
			} else if (fw < bw) {
				de.add(new DirectedEdge(p2, p1));
			} else {
				de.add(new DirectedEdge(p1, p2, false));
			}
		}

		return Dot.dot(outputdir, 1, new DirectedGroup(sp, de), dummy.new Dummytarget(sp, target), s);

	}

	public Path output2(Path outputdir) {

		DummysForApp dummy = new DummysForApp();
		ISimilarity s = dummy.new DummySimilarity(count);
		Group g = new Group('A');
		for (Edge e : count.keySet()) {
			g.addEdge(e);
		}
		g.noGather();

		Set<DirectedEdge> de = new THashSet<>();
		for (Edge e : g.edges()) {
			int p1 = e.fileId1();
			int p2 = e.fileId2();
			int fw = incCount.get(e);
			int bw = decCount.get(e);
			if (fw > bw) {
				de.add(new DirectedEdge(p1, p2));
			} else if (fw < bw) {
				de.add(new DirectedEdge(p2, p1));
			} else {
				de.add(new DirectedEdge(p1, p2, false));
			}
		}

		return Dot.dot(outputdir, 1, new DirectedGroup(g, de), dummy.new Dummytarget(g, target), s);

	}

}
