package com.annimon.stream;

import com.annimon.stream.function.Function;
import com.annimon.stream.function.ThrowableFunction;
import com.annimon.stream.function.ToIntFunction;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * Real example of calculate ratings.
 */
public class RatingsTest {
    
    private static Map<String, String> fileContents;
    
    @BeforeClass
    public static void setUpData() {
        fileContents = new HashMap<String, String>(5);
        fileContents.put("ahilla.txt", 
                "LongFlight     3 2 2 1 2\n" +
                "Units2D        2 1 1 0 1\n" +
                "SpaceCatcher   1 1 2 1 1\n" +
                "Galaxy         1 0 0 0 0\n" +
                "SonicTime3D    3 2 2 0 3\n" +
                "aPlatformer    1 1 0 1 0");
        fileContents.put("bogdan.txt", 
                "LongFlight     1 2 0 2 1\n" +
                "Units2D        0 1 0 1 0\n" +
                "SpaceCatcher   0 1 0 1 1\n" +
                "Galaxy         0 1 0 0 0\n" +
                "SonicTime3D    0 3 0 1 1\n" +
                "aPlatformer    1 1 0 1 1");
        fileContents.put("holdfast.txt", 
                "LongFlight     1 2 4 2 2\n" +
                "Units2D        0 2 1 2 1\n" +
                "SpaceCatcher   1 2 2 1 2\n" +
                "Galaxy         0 3 1 1 1\n" +
                "SonicTime3D    0 3 3 2 1\n" +
                "aPlatformer    1 0 0 1 1");
        fileContents.put("senderman.txt", 
                "LongFlight     1 3 2 3 2\n" +
                "Units2D        0 2 3 2 1\n" +
                "SpaceCatcher   0 2 5 3 1\n" +
                "Galaxy         0 3 0 0 0\n" +
                "SonicTime3D    0 3 1 1 0\n" +
                "aPlatformer    0 0 5 1 1");
    }

    @Test
    public void testRatings() {
        String ratings = Stream.of(fileContents.keySet()) // list files
                // read content of files
                .flatMap(Function.Util.safe(new ThrowableFunction<String, Stream<String>, Throwable>() {
                    @Override
                    public Stream<String> apply(String filename) throws IOException {
                        return readLines(filename);
                    }
                }))
                // split line by whitespaces
                .map(new Function<String, String[]>() {
                    @Override
                    public String[] apply(String line) {
                        return line.split("\\s+");
                    }
                })
                // calculate sum by line and store in pair <int, string>
                .map(new Function<String[], IntPair<String>>() {
                    @Override
                    public IntPair<String> apply(String[] arr) {
                        // <sum of marks, name>
                        return new IntPair<String>(
                                Stream.of(arr)
                                        .skip(1)
                                        .mapToInt(new ToIntFunction<String>() {
                                            @Override
                                            public int applyAsInt(String t) {
                                                return Integer.parseInt(t);
                                            }
                                        })
                                        .sum(),
                                arr[0]
                        );
                    }
                })
                // Group by name
                .groupBy(new Function<IntPair<String>, String>() {
                    @Override
                    public String apply(IntPair<String> t) {
                        return t.getSecond();
                    }
                })
                // Calculate summary ratings
                .map(new Function<Map.Entry<String, List<IntPair<String>>>, IntPair<String>>() {
                    @Override
                    public IntPair<String> apply(Map.Entry<String, List<IntPair<String>>> entry) {
                        final String name = entry.getKey();
                        final int ratings = Stream.of(entry.getValue())
                                .mapToInt(Functions.<String>intPairIndex())
                                .sum();
                        return new IntPair<String>(ratings, name);
                    }
                })
                // Sort by total rating descending
                .sortBy(new Function<IntPair<String>, Integer>() {
                    @Override
                    public Integer apply(IntPair<String> value) {
                        return -value.getFirst();
                    }
                })
                // Convert to formatted string
                .map(new Function<IntPair<String>, String>() {
                    @Override
                    public String apply(IntPair<String> value) {
                        return String.format("%12s: %d", value.getSecond(), value.getFirst());
                    }
                })
                // lines to string
                .collect(Collectors.joining("\n"));
        
        /* Scala analogue
        .flatMap(filename => Source.fromFile(filename, "UTF-8").getLines)
  	.map(s => s.split("\\s+"))
  	.map { arr => (arr(0), arr
  	    .drop(1)
  	    .map(_.toInt)
  	    .sum) }
  	.groupBy(_._1)
  	.map { case (name, ratings) => (name, ratings.map(_._2).sum)  }
  	.toSeq
  	.sortBy(- _._2)
  	.map { case (name, rating) => "%12s: %d".format(name, rating) }
  	.foreach(println);
        */
        
        Assert.assertEquals(
                "  LongFlight: 38\n" +
                " SonicTime3D: 29\n" +
                "SpaceCatcher: 28\n" +
                "     Units2D: 21\n" +
                " aPlatformer: 17\n" +
                "      Galaxy: 11", ratings);
    }
    
    /*
     * Emulates read lines from file
     */
    private static Stream<String> readLines(String filename) throws IOException {
        return Stream.of(fileContents.get(filename).split("\n"));
    }
}

@@ -5342,25 +5342,30 @@
 getLines)%0A  
-%09
+      
 .map(s =%3E s.
@@ -5377,25 +5377,30 @@
 (%22%5C%5Cs+%22))%0A  
-%09
+      
 .map %7B arr =
@@ -5416,17 +5416,22 @@
 , arr%0A  
-%09
+      
     .dro
@@ -5437,21 +5437,26 @@
 op(1)%0A  
-%09
+   
     
+   
 .map(_.t
@@ -5463,17 +5463,22 @@
 oInt)%0A  
-%09
+      
     .sum
@@ -5483,17 +5483,22 @@
 um) %7D%0A  
-%09
+      
 .groupBy
@@ -5502,25 +5502,30 @@
 pBy(_._1)%0A  
-%09
+      
 .map %7B case 
@@ -5578,17 +5578,22 @@
 m)  %7D%0A  
-%09
+      
 .toSeq%0A 
@@ -5593,17 +5593,22 @@
 toSeq%0A  
-%09
+      
 .sortBy(
@@ -5617,17 +5617,22 @@
 _._2)%0A  
-%09
+      
 .map %7B c
@@ -5693,9 +5693,14 @@
 %7D%0A  
-%09
+      
 .for

Replace tabs with spaces