package edu.ntnu.idi.goldfish;

import edu.ntnu.idi.goldfish.configurations.Configuration;
import edu.ntnu.idi.goldfish.mahout.SMRMSEevaluator;
import edu.ntnu.idi.goldfish.preprocessors.KMeansWrapper;
import org.apache.commons.lang3.StringUtils;
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.AbstractDifferenceRecommenderEvaluator;
import org.apache.mahout.cf.taste.impl.eval.AverageAbsoluteDifferenceRecommenderEvaluator;
import org.apache.mahout.cf.taste.impl.eval.GenericRecommenderIRStatsEvaluator;
import org.apache.mahout.cf.taste.impl.eval.RMSRecommenderEvaluator;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.common.RandomUtils;
import org.apache.mahout.common.RandomWrapper;
import org.apache.mahout.common.distance.DistanceMeasure;

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

public class Evaluator {

	static long getRandomUser(DataModel dataModel) throws TasteException {
		RandomWrapper random = RandomUtils.getRandom();
		Iterator<Long> it = dataModel.getUserIDs();
		while (it.hasNext()) {
			if (random.nextDouble() >= 0.1) {
				continue;
			}
			return it.next();
		}
		return 0;
	}

	double relevanceThreshold = GenericRecommenderIRStatsEvaluator.CHOOSE_THRESHOLD;

	public Evaluator() {
	}

	public void evaluateClustered(int numClusters, DistanceMeasure measure, List<Configuration> configurations, ResultList results, DataModel dataModel, double train, double eval) throws TasteException, IOException, InterruptedException, ClassNotFoundException {

		DataModel[] dataModels = KMeansWrapper.clusterUsers(dataModel, numClusters, measure, 0.5, 10, true, 0.0, true);

		StopWatch.start("totaleval");
		ResultList clusterResults;
		for(Configuration configuration : configurations) {
			long user = getRandomUser(dataModel);
			clusterResults = new ResultList(dataModel);
			StopWatch.start("cluster-configuration");
			for(int i=0; i<dataModels.length; i++) {
				clusterResults.add(evaluate(configuration, dataModel, train, eval, user));
			}
			Result average = Result.getAverage(clusterResults);
			System.err.format(average+" (in %s) \n", StopWatch.str("cluster-configuration"));
			results.add(average);
		}
		System.out.format("Evaluated %d clusters with %d configurations in %s\n", numClusters, configurations.size(), StopWatch.str("totaleval"));
	}

	public void evaluateUnclustered(List<Configuration> configurations, ResultList results, DataModel dataModel, double train, double eval) throws IOException, TasteException {
//		System.out.format("Starting evaluation of %d configurations (%d users, %d items) \n", configurations.size(), dataModel.getNumUsers(), dataModel.getNumItems());
		StopWatch.start("totaleval");
		for(Configuration configuration : configurations) {
			results.add(evaluate(configuration, dataModel, train, eval, getRandomUser(dataModel)));
		}
//		System.out.println(StringUtils.repeat("=", 190));
//		System.out.println(Result.getTotal(results));
		System.out.format("train: %.2f  eval: %.2f  %s\n",train, eval, Result.getAverage(results));
//		System.out.format("Evaluated %d configurations (%d users, %d items) in %s \n", configurations.size(), dataModel.getNumUsers(), dataModel.getNumItems(), StopWatch.str("totaleval"));
	}

	Result evaluate(Configuration configuration, DataModel dataModel, double train, double eval, long userID) throws TasteException {
		StopWatch.start("evalTime");

		// initialize variables
		double rmse = 0;
		double aad = 0;
		double precision = 0;
		double recall = 0;

		// initialize evaluators
		AbstractDifferenceRecommenderEvaluator RMSE = new SMRMSEevaluator();
//		AverageAbsoluteDifferenceRecommenderEvaluator AAD = new AverageAbsoluteDifferenceRecommenderEvaluator();
//        RecommenderIRStatsEvaluator irEvaluator = new GenericRecommenderIRStatsEvaluator();


        // do evaluations
        // NOTE: when a result is not needed, the respective line may be commented out here for increased configuration speed
		rmse = RMSE.evaluate(configuration.getRecommenderBuilder(), null, dataModel, train, eval);
//		aad = AAD.evaluate(configuration.getRecommenderBuilder(), null, dataModel, 0.9, testFrac);
//        IRStatistics stats = irEvaluator.evaluate(configuration.getRecommenderBuilder(), configuration.getModelBuilder(), dataModel, null, configuration.getTopN(), relevanceThreshold, testFrac);
//        precision = stats.getPrecision();
//        recall = stats.getRecall();

        // calculate build time
		StopWatch.start("buildTime");
		configuration.getRecommenderBuilder().buildRecommender(dataModel);
		long buildTime = StopWatch.get("buildTime");

		// calculate recommendation time
		long recTime = 0; //getRecommendationTiming(recommender, 20, 10, userID);

		// get time of total configuration
        long evalTime = StopWatch.get("evalTime");
		Result result = new Result(configuration, rmse, aad, 0, 0, buildTime, recTime, evalTime);

		// print each result to show progress
//		System.out.println(result);
		return result;
	}

	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;
	}

}

@@ -2688,18 +2688,16 @@
 ption %7B%0A
-//
 %09%09System
@@ -3031,18 +3031,16 @@
 ));%0A%09%09%7D%0A
-//
 %09%09System
@@ -3079,26 +3079,24 @@
 %22=%22, 190));%0A
-//
 %09%09System.out
@@ -3148,60 +3148,16 @@
 out.
-format(%22train: %25.2f  eval: %25.2f  %25s%5Cn%22,train, eval, 
+println(
 Resu
@@ -3181,18 +3181,16 @@
 ults));%0A
-//
 %09%09System

Enable debugging output