package edu.ntnu.idi.goldfish;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.eval.IRStatistics;
import org.apache.mahout.cf.taste.eval.RecommenderIRStatsEvaluator;
import org.apache.mahout.cf.taste.impl.eval.GenericRecommenderIRStatsEvaluator;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.common.distance.DistanceMeasure;

public class Evaluator {

	static long getRandomUser(DataModel dataModel) throws TasteException {
		Iterator<Long> it = dataModel.getUserIDs();
		return it.next();
	}
	
	double relevanceThreshold = GenericRecommenderIRStatsEvaluator.CHOOSE_THRESHOLD;
	
	public Evaluator() {	
	}
	
	public void evaluateClustered(int numClusters, DistanceMeasure measure, List<Evaluation> evaluations, EvaluationResults results, DataModel dataModel, double test) throws TasteException, IOException, InterruptedException, ClassNotFoundException {

		DataModel[] dataModels = KMeansWrapper.clusterUsers(dataModel, numClusters, measure, 0.5, 10, true, 0.0, true);
		
		StopWatch.start("totaleval");
		EvaluationResults clusterResults;
		for(Evaluation evaluation : evaluations) {
			long user = getRandomUser(dataModel);
			clusterResults = new EvaluationResults();
			StopWatch.start("cluster-evaluation");
			for(int i=0; i<dataModels.length; i++) {
				Result res  = evaluate(evaluation, dataModel, test, user);
				System.out.println(res);
				clusterResults.add(res);
			}
			Result average = Result.getAverage(clusterResults);
			System.err.format(average+" (in %s) \n", StopWatch.str("cluster-evaluation"));
			results.add(average);
		}
		System.out.format("Evaluated %d clusters with %d configurations in %s\n", numClusters, evaluations.size(), StopWatch.str("totaleval"));
	}
	
	public void evaluateUnclustered(List<Evaluation> evaluations, EvaluationResults results, DataModel dataModel, double test) throws IOException, TasteException {
		System.out.format("Starting evaluation of %d configurations (%d users, %d items) \n", evaluations.size(), dataModel.getNumUsers(), dataModel.getNumItems());
		StopWatch.start("totaleval");
		for(Evaluation evaluation : evaluations) {
			StopWatch.start("evaluate");
			Result res = evaluate(evaluation, dataModel, test, getRandomUser(dataModel));
			System.out.format("%s in %s \n", res, StopWatch.str("evaluate"));
			results.add(res);
		}
		System.out.format("Evaluated %d configurations (%d users, %d items) in %s \n", evaluations.size(), dataModel.getNumUsers(), dataModel.getNumItems(), StopWatch.str("totaleval"));
	}
	
	Result evaluate(Evaluation evaluation, DataModel dataModel, double testFrac, long userID) throws TasteException {
//		RMSE = new RMSRecommenderEvaluator();
//		AAD = new AverageAbsoluteDifferenceRecommenderEvaluator();
		RecommenderIRStatsEvaluator irEvaluator = new GenericRecommenderIRStatsEvaluator();
		
		double rmse = 0;
		double aad = 0;
		
		// recTime
		long recTime;
		
//		rmse = RMSE.evaluate(recommender.getBuilder(), null, dataModel, 1 - testFrac, test);
//		aad = AAD.evaluate(recommender.getBuilder(), null, dataModel, 1 - testFrac, test);
		IRStatistics stats = irEvaluator.evaluate(evaluation.getBuilder(), null, dataModel, null, evaluation.getTopN(), relevanceThreshold, testFrac);

		StopWatch.start("build");
		Recommender recommender = evaluation.getBuilder().buildRecommender(dataModel);
		StopWatch.stop("build");
		
		recTime = getRecommendationTiming(recommender, 20, 10, userID);

		return new Result(evaluation, rmse, aad, stats.getPrecision(), stats.getRecall(), StopWatch.get("build"), recTime);
	}
	
	public long getRecommendationTiming(org.apache.mahout.cf.taste.recommender.Recommender rec, int N, int howMany, long userID) throws TasteException {
		long totalDuration = 0;
		for(int i=0; i< N; i++) {
			StopWatch.start("recommend");
			rec.recommend(userID, howMany);
			totalDuration += StopWatch.get("recommend");
		}
		return totalDuration / N;
	}
	
}

@@ -1470,22 +1470,27 @@
 %09%09%09%09
-Result res  = 
+clusterResults.add(
 eval
@@ -1532,65 +1532,8 @@
 ser)
-;%0A%09%09%09%09System.out.println(res);%0A%09%09%09%09clusterResults.add(res
 );%0A%09
@@ -2249,53 +2249,20 @@
 %0A%09%09%09
-StopWatch.start(%22evaluate%22);%0A%09%09%09Result res = 
+results.add(
 eval
@@ -2324,97 +2324,8 @@
 el))
-;%0A%09%09%09System.out.format(%22%25s in %25s %5Cn%22, res, StopWatch.str(%22evaluate%22));%0A%09%09%09results.add(res
 );%0A%09
@@ -2627,16 +2627,50 @@
 ption %7B%0A
+%09%09StopWatch.start(%22evaluate%22);%0A%09%09%0A
 //%09%09RMSE
@@ -3457,22 +3457,31 @@
 ID);%0A%0A%09%09
-return
+Result result =
  new Res
@@ -3581,16 +3581,117 @@
 ecTime);
+%0A%0A%09%09System.out.format(%22%25s %7C Evaluated in %25s %5Cn%22, result, StopWatch.str(%22evaluate%22));%0A%09%09return result;
 %0A%09%7D%0A%09%0A%09p

Combine debugging output into evaluate method.