/**
 * 
 */
package cleman;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
import java.io.BufferedWriter;
import java.io.File;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.io.StringReader;

import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.SVNWCUtil;

import Smells.DuplicatedInfo;
import Smells.Duplicatedcode;
import Smells.Smell;

import treeMapping.ChangedFile;
import treeMapping.MapVisitor;
import util.FileIO;

import CloneTransforming.CloneMapper;
import CloneTransforming.ScriptGen;
import Detectors.THRESHOLDS;

/**
 * @author Nguyen Anh Hoan
 * 
 */
public class Main {
	public static String FILE_SEPARATOR = System.getProperty("file.separator");
	public static String applicationPath = "";
	// public static String applicationPath =
	// "D:\\Iowa State Uni\\Projects\\ASE08\\jedit30source";
	// public static String applicationPath =
	// "D:\\Iowa State Uni\\Projects\\ASE08\\axis-1.3";
	// public static String applicationPath =
	// "D:\\Iowa State Uni\\Projects\\ASE08\\jdk5";
	// public static String applicationPath =
	// "D:\\Iowa State Uni\\Projects\\ICSE09\\test";

	// public static String svnURL, projectName, trunkDir;
	// public static String svnURL = "https://seg-pc1.dnsalias.net:8443/svn/",
	// projectName = "argouml", trunkDir = "trunk";
	// public static String svnURL = "https://seg-pc1.dnsalias.net:8443/svn/",
	// projectName = "columba", trunkDir = "columba/trunk";
	// public static String svnURL = "https://seg-pc1.dnsalias.net:8443/svn/",
	// projectName = "eu.geclipse", trunkDir = "trunk";
	// public static String svnURL = "https://seg-pc1.dnsalias.net:8443/svn/",
	// projectName = "jedit", trunkDir = "jEdit/trunk";
	// public static String svnURL = "https://seg-pc1.dnsalias.net:8443/svn/",
	// projectName = "jedit2", trunkDir = "trunk";
	// public static String svnURL = "https://seg-pc1.dnsalias.net:8443/svn/",
	// projectName = "zk1", trunkDir = "trunk";
	// public static String svnURL =
	// "https://seg-pc2.dnsalias.net:8443/svn/subjects/", projectName = "test",
	// trunkDir = "";
	// public static String svnURL = "file:///D:/Repositories/", projectName =
	// "jhotdraw", trunkDir = "trunk";
	
	public static String projectName = "clonedetector", trunkDir = "src/cleman";
	public static String svnURL = "https://LH406:8443/svn/ins/"+ projectName + "/" + trunkDir;
	public static SVNURL projectSVNURL;
	public static String repUserName = "liuhui", repPassword = "liuhui";
	public static ISVNAuthenticationManager authManager;
	public static SVNRepository repository = null;

	public static String outputDataPath = ".";

	// public static int numOfHash = 16, numOfDim = 4, winSize = 4,
	// minFragmentSize = 40;
	public static int numOfHash = 1, numOfDim = 4, winSize = 4,
			minFragmentSize = 40;
	public static double threshold = 0.00;
	// public static boolean modeIncremental = false;
	public static boolean doReport = true, doManualCheck = false;
	public static int numOfSamples = 100;
	public static long preRevision = 0;

	/**
	 * @param args
	 */
	// svnRUL, projectName, trunkDir,repUserName,repPassword
	public List<Smell> detectClones() {// https://lh406:8443/svn/Ins

		List<Smell> smells;
		//svnURL += "/" + projectName + "/" + trunkDir;
		// preRevision = 3;
		if (preRevision == 0) {
			NonIncrementalDetection();
			smells= getCloneSmells();
		} else {
			IncrementalDetection();
			smells= getCloneSmells();
		}
		
		return  smells;
	}

	
	public void NonIncrementalDetection() {// https://lh406:8443/svn/Ins
		String projectPath;
		int numOfRevisions = 0, numOfChangedFragments = 0, numOfAddedClones = 0, numOfDeletedClones = 0, numOfModifiedClones = 0, numOfUnchangedClones = 0;
		int numOfPairs = 0, numOfDeletedPairs = 0, numOfAddedPairs = 0, numOf1ChangedPairs = 0, numOf2ChangedPairs = 0;
		int numOfInconsistentChanges = 0, numOfStructuralInconsistencies = 0, numOfNamingInconsistencies = 0, numOfLabelInconsistencies = 0;
		int numOfOperations = 0, numOfChangedLines = 0, numOfChangedClonedLines = 0;

		projectPath = outputDataPath + "\\changes\\" + projectName + "_"
				+ minFragmentSize + "_locations_" + preRevision;
		try {
			/*
			 * For using over http:// and https://
			 */
			DAVRepositoryFactory.setup();
			/*
			 * For using over svn:// and svn+xxx://
			 */
			SVNRepositoryFactoryImpl.setup();
			/*
			 * For using over file:///
			 */
			FSRepositoryFactory.setup();
			projectSVNURL = SVNURL.parseURIEncoded(svnURL);
			authManager = SVNWCUtil.createDefaultAuthenticationManager(
					repUserName, repPassword);
			repository = SVNRepositoryFactory.create(projectSVNURL);
			repository.setAuthenticationManager(authManager);
			repository.testConnection();
			System.out.println("Connect OK");
			if (preRevision == 0)
				preRevision = repository.getLatestRevision();
			// svnURL += "/" + projectName + "/" + trunkDir;// +
			// "/src_new/org/argouml/uml/ui";
			projectSVNURL = SVNURL.parseURIEncoded(svnURL);
			authManager = SVNWCUtil.createDefaultAuthenticationManager(
					repUserName, repPassword);
			repository = SVNRepositoryFactory.create(projectSVNURL);
			repository.setAuthenticationManager(authManager);
			repository.testConnection();
			System.out.println("Connect OK");

		} catch (SVNException e) {
			e.printStackTrace();
		}

		Hash.init(numOfHash, numOfDim, winSize, 2500);
		System.out.println(Hash.aGaussian[0][0].length);
		Runtime rt = Runtime.getRuntime();
		long initMem = rt.freeMemory();
		File logFile;
		long startTime = System.currentTimeMillis();
		long stopTime = System.currentTimeMillis();

		File dir = new File(projectPath + "\\inconsistencies");
		if (!dir.exists())
			dir.mkdirs();
		dir = new File(projectPath + "\\inconsistencies\\structure");
		if (!dir.exists())
			dir.mkdirs();
		dir = new File(projectPath + "\\inconsistencies\\naming");
		if (!dir.exists())
			dir.mkdirs();
		dir = new File(projectPath + "\\inconsistencies\\label");
		if (!dir.exists())
			dir.mkdirs();
		ArrayList<Integer> fixRevs = null;

		PrintStream err = System.err;
		try {
			System.setErr(new PrintStream(projectPath + "\\log_all.txt"));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

		// try{
		// applicationPath = projectPath + FILE_SEPARATOR + (preRevision == 0 ?
		// "" : String.format("%05d", preRevision));
		// File logDir = new File(applicationPath);
		// logDir = new File(applicationPath);
		// if (!logDir.exists()) logDir.mkdirs();
		// applicationPath = logDir.getAbsolutePath();
		// logFile = new File(applicationPath + "\\_clemanX_log_" +"Standalone_"
		// + preRevision + "_" +
		// (1-threshold) + "_" + numOfHash + "_" + numOfDim + "_" + winSize +
		// "_" + minFragmentSize + ".txt");
		// if (!logFile.exists()) logFile.createNewFile();
		// System.setOut(new PrintStream(logFile));
		// }
		// catch (IOException e){
		// e.printStackTrace();
		// }

		System.out.println(applicationPath);
		System.out.println("Mode: " + "Standalone");
		System.out.println("Similarity: " + (1 - threshold));
		System.out.println("Number of hash functions: " + numOfHash);
		System.out.println("Number of dimensions: " + numOfDim);
		System.out.println("Hash window size: " + winSize);
		System.out.println("Minimum fragment size: " + minFragmentSize);
		System.out.println("Merge window size: " + Fragment.mergeWindowSize);

		if (svnURL.contains("://"))
			SourceFile.genAllFiles(repository, "", preRevision);
		else
			SourceFile.genAllFiles(new File(applicationPath));
		Fragment.all.putAll(new HashMap<Integer, Fragment>(Fragment.addeds));
		Fragment.addeds.clear();
		System.err.print("Files: " + SourceFile.all.size());
		System.out.println("Files: " + SourceFile.all.size());
		System.err.print("\tFragments: " + Fragment.all.size());
		System.out.println("Fragments: " + Fragment.all.size());
		stopTime = System.currentTimeMillis();
		System.err.println("\t" + (stopTime - startTime) / 1000.0 + "s");
		System.out.println((stopTime - startTime) / 1000.0 + "s");

		/*
		 * for(Fragment f : Fragment.all.values()) System.out.println(f);
		 */

		Hash.reset(Fragment.gram2Index.size());

		// Bucket.all = Bucket.map(new
		// HashSet<Fragment>(Fragment.all.values()));
		Bucket.mapAll();
		System.err.print("Buckets: " + Bucket.all.size());
		System.out.println("Buckets: " + Bucket.all.size());
		stopTime = System.currentTimeMillis();
		System.err.println("\t" + (stopTime - startTime) / 1000.0 + "s");
		System.out.println((stopTime - startTime) / 1000.0 + "s");

		Group.mapPairs(new HashSet<Bucket>(Bucket.all.values()));
		System.err.print("Clones : " + Group.clones.size());
		System.out.println("Clones : " + Group.clones.size());
		stopTime = System.currentTimeMillis();
		System.err.println("\t" + (stopTime - startTime) / 1000.0 + "s");
		System.out.println((stopTime - startTime) / 1000.0 + "s");
		Group.clones = Group.filterPairs(Group.clones);
		System.err.print("Clones : " + Group.clones.size());
		System.out.println("Clones : " + Group.clones.size());
		stopTime = System.currentTimeMillis();
		System.err.println("\t" + (stopTime - startTime) / 1000.0 + "s");
		System.out.println((stopTime - startTime) / 1000.0 + "s");

		System.out.println("Max memory usage: " + (rt.totalMemory() - initMem)
				/ 1024 / 1024 + " MBs");
		System.out.println("Done");
		//-------------------------------
		




		

	}

	public void IncrementalDetection() {// https://lh406:8443/svn/Ins

		String projectPath;
		long currentRevision = 0;
		int numOfRevisions = 0, numOfChangedFragments = 0, numOfAddedClones = 0, numOfDeletedClones = 0, numOfModifiedClones = 0, numOfUnchangedClones = 0;
		int numOfPairs = 0, numOfDeletedPairs = 0, numOfAddedPairs = 0, numOf1ChangedPairs = 0, numOf2ChangedPairs = 0;
		int numOfInconsistentChanges = 0, numOfStructuralInconsistencies = 0, numOfNamingInconsistencies = 0, numOfLabelInconsistencies = 0;
		int numOfOperations = 0, numOfChangedLines = 0, numOfChangedClonedLines = 0;
		projectPath = outputDataPath + "\\changes\\" + projectName + "_"
				+ minFragmentSize + "_locations_" + preRevision;
		
		SourceFile.prev = new HashMap<String, SourceFile>(SourceFile.all);
		Fragment.prev = new HashMap<Integer, Fragment>(Fragment.all);
		Group.prevClones = new HashSet<Integer>(Group.clones);
		
		try {
			/*
			 * For using over http:// and https://
			 */
			DAVRepositoryFactory.setup();
			/*
			 * For using over svn:// and svn+xxx://
			 */
			SVNRepositoryFactoryImpl.setup();
			/*
			 * For using over file:///
			 */
			FSRepositoryFactory.setup();
			projectSVNURL = SVNURL.parseURIEncoded(svnURL );
			authManager = SVNWCUtil.createDefaultAuthenticationManager(
					repUserName, repPassword);
			repository = SVNRepositoryFactory.create(projectSVNURL);
			repository.setAuthenticationManager(authManager);
			repository.testConnection();
			currentRevision = repository.getLatestRevision();
			System.out.println("Connect OK");
			// + "/src_new/org/argouml/uml/ui";
			projectSVNURL = SVNURL.parseURIEncoded(svnURL);
			authManager = SVNWCUtil.createDefaultAuthenticationManager(
					repUserName, repPassword);
			repository = SVNRepositoryFactory.create(projectSVNURL);
			repository.setAuthenticationManager(authManager);
			repository.testConnection();
			System.out.println("Connect OK");
			System.out.println("Revisions  to " + currentRevision);
		} catch (SVNException e) {
			e.printStackTrace();
		}

		Hash.init(numOfHash, numOfDim, winSize, 2500);
		System.out.println(Hash.aGaussian[0][0].length);
		Runtime rt = Runtime.getRuntime();
		long initMem = rt.freeMemory();
		File logFile;
		long startTime = System.currentTimeMillis();
		long stopTime = System.currentTimeMillis();
		File dir = new File(projectPath + "\\inconsistencies");
		if (!dir.exists())
			dir.mkdirs();
		dir = new File(projectPath + "\\inconsistencies\\structure");
		if (!dir.exists())
			dir.mkdirs();
		dir = new File(projectPath + "\\inconsistencies\\naming");
		if (!dir.exists())
			dir.mkdirs();
		dir = new File(projectPath + "\\inconsistencies\\label");
		if (!dir.exists())
			dir.mkdirs();
		ArrayList<Integer> fixRevs = null;
		PrintStream err = System.err;
		try {
			System.setErr(new PrintStream(projectPath + "\\log_all.txt"));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

		System.err.println("Revision: " + currentRevision);
		// try{
		// applicationPath = projectPath + FILE_SEPARATOR + (currentRevision ==
		// 0 ? "" : String.format("%05d", currentRevision));
		// File logDir = new File(applicationPath);
		// logDir = new File(applicationPath);
		// if (!logDir.exists()) logDir.mkdirs();
		// applicationPath = logDir.getAbsolutePath();
		// logFile = new File(applicationPath + "\\_clemanX_log_"
		// +"Incremental_" + currentRevision + "_" +
		// (1-threshold) + "_" + numOfHash + "_" + numOfDim + "_" + winSize +
		// "_" + minFragmentSize + ".txt");
		// if (!logFile.exists()) logFile.createNewFile();
		// System.setOut(new PrintStream(logFile));
		// }
		// catch (IOException e){
		// e.printStackTrace();
		// }

		System.out.println(applicationPath);
		System.out.println("Mode: " + "Incremental");
		System.out.println("Similarity: " + (1 - threshold));
		System.out.println("Number of hash functions: " + numOfHash);
		System.out.println("Number of dimensions: " + numOfDim);
		System.out.println("Hash window size: " + winSize);
		System.out.println("Minimum fragment size: " + minFragmentSize);
		System.out.println("Merge window size: " + Fragment.mergeWindowSize);
		FileChecking fChecker = new FileChecking();
		fChecker.doCheck(repUserName, repPassword, svnURL, preRevision,
				currentRevision);
		numOfChangedLines += fChecker.changedLines;

		System.out.println("Total # of files: " + SourceFile.all.size());
		System.out.println("Added files : " + fChecker.addeds);
		System.out.println("Deleted files : " + fChecker.deleteds);
		System.out.println("Modified files : " + fChecker.modifieds);
		System.out.println();

		System.err.print(SourceFile.all.size() + " files: ");
		System.err.print(fChecker.addeds + " add ");
		System.err.print(fChecker.deleteds + " del ");
		System.err.print(fChecker.modifieds + " mod" + "\t");

		System.out.println();
		System.out.println(SourceFile.all.size() + "\t" + " files");
		System.out.println(Fragment.all.size() + "/"
				+ (Fragment.all.size() + Fragment.addeds.size()) + "\t"
				+ " fragments");
		stopTime = System.currentTimeMillis();
		System.err.println((stopTime - startTime) / 1000.0 + "s");
		System.out.println((stopTime - startTime) / 1000.0 + "s");

		if ((fChecker.addeds + fChecker.deleteds + fChecker.modifieds) == 0) {
			System.out.println("No changes found, execution stopped");

			System.out.println(Bucket.changeds.size() + " buckets");
			System.out.println(Group.all.size() + " group(s)");
			stopTime = System.currentTimeMillis();
			System.out.println((stopTime - startTime) / 1000.0 + "s");
		} else {
			Hash.reset(Fragment.gram2Index.size());

			for (Fragment fragment : Fragment.all.values())
				Fragment.unchangeds.put(fragment.getId(), fragment.clone());
			Fragment.all.putAll(new HashMap<Integer, Fragment>(
					Fragment.unchangeds));
			Fragment.all.putAll(new HashMap<Integer, Fragment>(
					Fragment.modifieds));
			for (int id : Fragment.deleteds.keySet()) {
				Fragment fragment = Fragment.deleteds.get(id);
				for (Bucket b : fragment.getBuckets()) {
					b.fragments.remove(fragment.getId());
					if (b.fragments.isEmpty())
						Bucket.all.remove(b.id);
				}
				for (int cloneID : fragment.getClones()) {
					Fragment clone = Fragment.all.get(cloneID);
					if (clone != null) {
						clone.getClones().remove(id);
						if (clone.getClones().isEmpty())
							Group.clones.remove(cloneID);
					}
				}
				Group.clones.remove(id);
			}
			HashSet<Integer> modClones = new HashSet<Integer>(
					Fragment.modifieds.keySet());
			modClones.retainAll(Group.clones);
			for (int id : modClones) {
				Fragment preFragment = Fragment.prev.get(id);
				for (int cloneID : preFragment.getClones()) {
					Fragment clone = Fragment.prev.get(cloneID);
					CloneMapper cm = new CloneMapper(preFragment, clone,
							preRevision, currentRevision);
					dir = new File(projectPath + "\\inconsistencies\\"
							+ currentRevision + "\\" + id + "_" + cloneID);
					if (!dir.exists())
						dir.mkdirs();
					try {
						BufferedWriter out = new BufferedWriter(
								new FileWriter(dir.getAbsolutePath() + "\\"
										+ id + "_old.java"));
						out.write("File: "
								+ preFragment.getSourceFile().fileLocation
								+ "\n");
						out.write("Line: "
								+ cm.ast1M
										.getProperty(MapVisitor.propertyStartLine)
								+ " "
								+ cm.ast1M
										.getProperty(MapVisitor.propertyEndLine)
								+ "\n");
						out.write("Char: "
								+ cm.ast1M.getStartPosition()
								+ " "
								+ (cm.ast1M.getStartPosition()
										+ cm.ast1M.getLength() - 1) + "\n\n");
						out.write(cm.ast1M.toString());
						out.flush();
						out.close();
						out = new BufferedWriter(new FileWriter(
								dir.getAbsolutePath() + "\\" + cloneID
										+ "_old.java"));
						out.write("File: " + clone.getSourceFile().fileLocation
								+ "\n");
						out.write("Line: "
								+ cm.ast2M
										.getProperty(MapVisitor.propertyStartLine)
								+ " "
								+ cm.ast2M
										.getProperty(MapVisitor.propertyEndLine)
								+ "\n");
						out.write("Char: "
								+ cm.ast2M.getStartPosition()
								+ " "
								+ (cm.ast2M.getStartPosition()
										+ cm.ast2M.getLength() - 1) + "\n\n");
						out.write(cm.ast2M.toString());
						out.flush();
						out.close();
						out = new BufferedWriter(
								new FileWriter(dir.getAbsolutePath() + "\\"
										+ id + "_new.java"));
						out.write("File: "
								+ preFragment.getSourceFile().fileLocation
								+ "\n");
						out.write("Line: "
								+ cm.ast1N
										.getProperty(MapVisitor.propertyStartLine)
								+ " "
								+ cm.ast1N
										.getProperty(MapVisitor.propertyEndLine)
								+ "\n");
						out.write("Char: "
								+ cm.ast1N.getStartPosition()
								+ " "
								+ (cm.ast1N.getStartPosition()
										+ cm.ast1N.getLength() - 1) + "\n\n");
						out.write(cm.ast1N.toString());
						out.flush();
						out.close();
						out = new BufferedWriter(new FileWriter(
								dir.getAbsolutePath() + "\\" + cloneID
										+ "_new.java"));
						out.write("File: " + clone.getSourceFile().fileLocation
								+ "\n");
						out.write("Line: "
								+ cm.ast2N
										.getProperty(MapVisitor.propertyStartLine)
								+ " "
								+ cm.ast2N
										.getProperty(MapVisitor.propertyEndLine)
								+ "\n");
						out.write("Char: "
								+ cm.ast2N.getStartPosition()
								+ " "
								+ (cm.ast2N.getStartPosition()
										+ cm.ast2N.getLength() - 1) + "\n\n");
						out.write(cm.ast2N.toString());
						out.flush();
						out.close();
						out = new BufferedWriter(new FileWriter(
								dir.getAbsolutePath() + "\\info.txt"));
						out.write("#Change = 1 | 2 ( 1 side or 2 side)\r\n");
						out.write("#Inconsistent = No | {S, N, L} (No or any combination of structure, naming and label\r\n");
						out.write("#Sync = 2T | 2F | 1T | 1F (1 | 2 side and correct | incorrect)\r\n\r\n");
						out.write("Change: \r\n");
						out.write("Inconsistent: \r\n");
						out.write("Sync: \r\n");
						out.write("Locations: \r\n");
						out.write("Correct: \r\n");
						out.write("Miss: \r\n");
						out.write("Comment:");
						out.flush();
						out.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
			for (int id : Fragment.modifieds.keySet()) {
				Fragment fragment = Fragment.modifieds.get(id), preFragment = Fragment.prev
						.get(id);
				for (int cloneID : new HashSet<Integer>(preFragment.getClones())) {
					if (!fragment.getClones().contains(cloneID)) {
						Fragment clone = Fragment.all.get(cloneID);
						if (clone != null) {
							clone.getClones().remove(id);
							if (clone.getClones().isEmpty())
								Group.clones.remove(cloneID);
							/*
							 * if(fragment.clonedTo(clone) <= Main.threshold) {
							 * fragment.getClones().add(cloneID);
							 * clone.getClones().add(id);
							 * Group.changedClones.add(id);
							 * Group.changedClones.add(cloneID);
							 * Group.clones.remove(id);
							 * Group.clones.remove(cloneID); } else {
							 * clone.getClones().remove(id);
							 * if(clone.getClones().isEmpty())
							 * Group.clones.remove(cloneID); }
							 */
						}
					}
				}
			}
			Fragment.all
					.putAll(new HashMap<Integer, Fragment>(Fragment.addeds));

			System.out.println("All fragments: " + Fragment.all.size());
			System.out.println("Added fragments: " + Fragment.addeds.size());
			System.out
					.println("Deleted fragments: " + Fragment.deleteds.size());
			System.out.println("Modified fragments: "
					+ Fragment.modifieds.size());
			System.err.print("All frags: " + Fragment.all.size() + " ");
			System.err.print("Add frags: " + Fragment.addeds.size() + " ");
			System.err.print("Del frags: " + Fragment.deleteds.size() + " ");
			System.err.print("Mod frags: " + Fragment.modifieds.size() + " ");
			System.err.print("Unchanged frags: " + Fragment.unchangeds.size());
			stopTime = System.currentTimeMillis();
			System.err.println("\t" + (stopTime - startTime) / 1000.0 + "s");
			System.out.println((stopTime - startTime) / 1000.0 + "s");

			HashMap<Integer, Fragment> changedFragments = new HashMap<Integer, Fragment>(
					Fragment.addeds);
			changedFragments.putAll(Fragment.modifieds);
			Bucket.map2All(new HashSet<Fragment>(changedFragments.values()));
			Bucket.all.putAll(new HashMap<Integer, Bucket>(Bucket.changeds));
			changedFragments = null;

			System.err.print("Buckets: " + Bucket.changeds.size() + " + "
					+ Bucket.all.size() + "/"
					+ (Bucket.all.size() + Bucket.changeds.size()));
			System.out.println("Buckets: " + Bucket.changeds.size() + " + "
					+ Bucket.all.size() + "/"
					+ (Bucket.all.size() + Bucket.changeds.size()));
			stopTime = System.currentTimeMillis();
			System.err.println("\t" + (stopTime - startTime) / 1000.0 + "s");
			System.out.println((stopTime - startTime) / 1000.0 + "s");

			Group.mapPairs2All(new HashSet<Bucket>(Bucket.changeds.values()));
			Bucket.changeds.clear();
			System.err.print("Clones : " + Group.changedClones.size() + "/"
					+ Group.clones.size());
			System.out.println("Clones : " + Group.changedClones.size() + "/"
					+ Group.clones.size());
			stopTime = System.currentTimeMillis();
			System.err.println("\t" + (stopTime - startTime) / 1000.0 + "s");
			System.out.println((stopTime - startTime) / 1000.0 + "s");

			// Group.clones = Group.filterPairs(Group.clones);
			Group.filterChangedPairs();
			Group.changedClones.clear();
			System.err.print("Clones : " + Group.clones.size());
			System.out.println("Clones : " + Group.clones.size());
			stopTime = System.currentTimeMillis();
			System.err.println("\t" + (stopTime - startTime) / 1000.0 + "s");
			System.out.println((stopTime - startTime) / 1000.0 + "s");

			Fragment.unchangeds.clear();
			Fragment.addeds.clear();
			Fragment.deleteds.clear();
			Fragment.modifieds.clear();

			stopTime = System.currentTimeMillis();
			System.out.println((stopTime - startTime) / 1000.0 + "s");
		}
		System.out.println("Max memory usage: " + (rt.totalMemory() - initMem)
				/ 1024 / 1024 + " MBs");
		System.out.println("Done");
		Main.preRevision=currentRevision;
		/*
		 * if(doReport) { System.out.println("Reporting"); for(Group g :
		 * Group.group(Group.clones).values()) g.report(applicationPath +
		 * "\\Report"); Group.reportPairs(applicationPath + "\\pairs.txt");
		 * stopTime = System.currentTimeMillis(); System.out.println((stopTime -
		 * startTime)/1000.0 + "s"); }
		 */

		// SourceFile.prev = new HashMap<String, SourceFile>(SourceFile.all);
		// Fragment.prev = new HashMap<Integer, Fragment>(Fragment.all);
		// Group.prevClones = new HashSet<Integer>(Group.clones);
		//
		// stopTime = System.currentTimeMillis();
		// System.out.println((stopTime - startTime)/1000.0 + "s");
		// System.err.println((stopTime - startTime)/1000.0 + "s");
		//
		// System.out.flush();
		// System.out.close();
		//
		// preRevision = currentRevision;
		//
		// if(doReport)
		// {
		// System.out.println("Reporting");
		// for(Group g : Group.all.values())
		// g.report(applicationPath + "\\Report" +"Incremental_");
		// stopTime = System.currentTimeMillis();
		// System.out.println((stopTime - startTime)/1000.0 + "s");
		// }
		// System.err.flush();
		// System.err.close();
		// System.setErr(err);
		//
		// logFile = new File(projectPath);
		// if(!logFile.exists())
		// logFile.mkdirs();
		// String tmp = projectPath + "\\_clemanX_" + "Incremental_" +
		// preRevision + "_" +
		// (1-threshold) + "_" + numOfHash + "_" + numOfDim + "_" + winSize +
		// "_" + minFragmentSize;
		//
		// logFile = new File(tmp + ".txt");
		// // if (!logFile.exists()) logFile.createNewFile();
		// // System.setOut(new PrintStream(logFile));
		// System.out.println(projectPath);
		// System.out.println("Mode: " + "Incremental");
		// System.out.println("Similarity: " + (1-threshold));
		// System.out.println("Number of hash functions: " + numOfHash);
		// System.out.println("Number of dimensions: " + numOfDim);
		// System.out.println("Window size: " + winSize);
		// System.out.println("Minimum fragment size: " + minFragmentSize);
		// System.out.println("Fragments: " + Fragment.all.size());
		// System.out.println("Features: " + Fragment.index2Gram.size());
		// int cCs = 0, cMs = 0, cOs = 0;
		// for(Group g : Group.all.values())
		// {
		// for(Fragment f : g.fragments)
		// {
		// if(f.getType() == Fragment.ClassFragment)
		// cCs += g.fragments.size();
		// else if(f.getType() == Fragment.MethodFragment)
		// cMs += g.fragments.size();
		// else
		// cOs += g.fragments.size();
		// break;
		// }
		// }
		// System.out.println(cCs + " class clones\t" +
		// cMs + " method clones\t" + cOs + " other clones");
		// if(numOfRevisions > 0)
		// {
		// System.out.println("Number of revisions: " + numOfRevisions);
		// System.out.println("Changed fragments: " +
		// numOfChangedFragments*1.0/numOfRevisions);
		// System.out.println("C+: " + numOfAddedClones*1.0/numOfRevisions);
		// System.out.println("C-: " + numOfDeletedClones*1.0/numOfRevisions);
		// System.out.println("C*: " + numOfModifiedClones*1.0/numOfRevisions);
		// System.out.println("C0: " + numOfUnchangedClones*1.0/numOfRevisions);
		// System.out.println("All Clone Pairs: " +
		// numOfPairs/2.0/numOfRevisions);
		// System.out.println("New Clone Pairs: " +
		// numOfAddedPairs/2.0/numOfRevisions);
		// System.out.println("Deleted Pairs: " +
		// numOfDeletedPairs/2.0/numOfRevisions);
		// System.out.println("1-side changed pairs: " +
		// numOf1ChangedPairs/2.0/numOfRevisions);
		// System.out.println("2-side changed pairs: " +
		// numOf2ChangedPairs/2.0/numOfRevisions);
		// System.out.println("Inconsistent changes: " +
		// numOfInconsistentChanges/2.0/numOfRevisions);
		// System.out.println("Inconsistent structural changes: " +
		// numOfStructuralInconsistencies/2.0/numOfRevisions);
		// System.out.println("Inconsistent naming changes: " +
		// numOfNamingInconsistencies/2.0/numOfRevisions);
		// System.out.println("Inconsistent labeling changes: " +
		// numOfLabelInconsistencies/2.0/numOfRevisions);
		// System.out.println("Operations: " +
		// numOfOperations*1.0/numOfRevisions);
		// System.out.println("Changed lines: " +
		// numOfChangedLines*1.0/numOfRevisions);
		// System.out.println("Changed lines in clones: " +
		// numOfChangedClonedLines*1.0/numOfRevisions);
		// }
		// System.out.println("Max memory usage: " + (rt.totalMemory() -
		// initMem)/1024/1024 + " MBs");
		// System.out.println("Done");
		// stopTime = System.currentTimeMillis();
		// System.out.println((stopTime - startTime)/1000.0 + "s");
		// stopTime = System.currentTimeMillis();
		// System.out.println((stopTime - startTime)/1000.0 + "s");
		//
		//
		//
		// {
		// FileIO.saveObjectToFile(Fragment.index2Gram, projectPath +
		// "\\index2Gram.dat");
		// FileIO.saveObjectToFile(Fragment.gram2Index, projectPath +
		// "\\gram2Index.dat");
		// }

	}

	public static void main(String[] args) {
	

	}

	public static List<Smell> getCloneSmells() {
		List<Smell> smells=new ArrayList<Smell>();
		System.out.println("Beging of the getCloneSmells");
		HashSet<Integer> newClones = new HashSet<Integer>();
		HashSet<Integer> oldClones = new HashSet<Integer>();
		if (Group.prevClones == null) 
			newClones = Group.clones;
			else
			{
				if( Group.prevClones.size() == 0)
					newClones = Group.clones;	
				else {
			       for (Integer i : Group.clones) {

				   if (!Group.prevClones.contains(i))
					     newClones.add(i);
				   else
					   oldClones.add(i);
			       }
			}
		}
		if(newClones.size()<1) return smells;
		smells.addAll(getCloneSmells(newClones, true));
		smells.addAll(getCloneSmells(oldClones,false));
		return smells;
	}
	public static List<Smell> getCloneSmells( HashSet<Integer> clones, boolean isNew) {
		//print all new clones
				
		List<Smell> smells=new ArrayList<Smell>();
		HashMap<Integer, Group> allgroups = Group.group(clones);

				Collection<Group> groups = allgroups.values();
				for (Group curGroup : groups) {
					Duplicatedcode asmell=new Duplicatedcode();
				   String explain = "";
					HashSet<Fragment> fragments = curGroup.fragments;
					String tab = "";
					
					for (Fragment curFragment : fragments) {
//							if(curFragment.getStartLine()+curFragment.getEndLine()==0)
//						    assignedSourceRange(curFragment);
						// DuplicatedInfo(int starth,int startl,int endh,int endl,String Filename)
					   DuplicatedInfo info=new DuplicatedInfo();
					   info.StartChart=curFragment.getStartChar();
					   info.lengthinChart=curFragment.getLength();
					   info.filename=curFragment.getSourceFile().fileLocation;
					   asmell.infos.add(info);
					   explain += tab;
						tab = THRESHOLDS.Clonetab;
						explain += curFragment.getSourceFile().fileLocation;
						explain += ":";
						explain += curFragment.getStartLine();
						explain += " ";
						explain += curFragment.getEndLine();

					}
					asmell.explaination=explain;
					if(isNew) asmell.appearTime=(new Date()).getTime();
					else 
						asmell.appearTime=(new Date()).getTime()-1000*60;
					smells.add(asmell);
					System.out.println(explain);
				
				}//end of for Group
		       return smells;	
		
	}
//	public static void assignedSourceRange(Fragment frag) {
//
//		//frag.getSourceFile().
//		ByteArrayOutputStream out = new ByteArrayOutputStream();
//		ArrayList<Integer> p_lines = new ArrayList<Integer>();
//		try {
//			repository.getFile(frag.getSourceFile().fileLocation, preRevision, null, out);
//			
//			BufferedReader in = new BufferedReader(new StringReader(out.toString()));
//			
//			String line = "";
//	    	int charCount = 0, lineCount = 0;
//	    	StringBuffer strBuf = new StringBuffer();
//	    	while ((line = in.readLine()) != null) { 
//					lineCount++;
//					p_lines.add(charCount);
//					charCount += line.length() + 2;
//					//line.replaceAll("/" + '*' + '*', "/" + '*' + " ");
//					
//					/*while (line.indexOf("/**") > -1) {
//						int i = line.indexOf("/**");
//						line = line.substring(0, i) + "/* " + line.substring(i + 3);
//					}
//					strBuf.append(line + "\r\n");*/
//					char[] chs = line.toCharArray();
//					for (int i = 0; i < chs.length - 2; i++)
//						if (chs[i] == '/' && chs[i+1] == '*') chs[i+2] = ' '; 
//					strBuf.append(chs);
//					strBuf.append("\r\n");
//					
//				}
//				in.close();
//				p_lines.set(0, lineCount);
//			
//		} catch (Exception e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//		
//		   	
////    	frag.setStartLine(VectorVisitor.binSearch(frag.getStartChar(), p_lines));
////    	frag.setEndLine(VectorVisitor.binSearch(frag.getStartChar()+frag.getLength(), p_lines));
//
//	}

}
