package de.baumato.loc;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.stream.Stream;

import de.baumato.loc.configuration.Configuration;
import de.baumato.loc.printer.ConsolePrinter;

public class LineCounter {

	private final Configuration conf;
	private final ConsolePrinter printer;

	public LineCounter(Configuration conf, ConsolePrinter printer) {
		this.conf = conf;
		this.printer = printer;
	}

	public long count() {
		return countLinesInDir(conf.getDirectory(), conf.getExcludeDirs());
	}

	private long countLinesInDir(Path dir, Collection<String> excludeDirs) {
		try (Stream<Path> paths = Files.walk(dir)) {
			long sum = paths.filter(p -> p.getFileName().toString().endsWith(".java"))
				.filter(p -> !pathContainsOneOfDirs(p, excludeDirs))
				.peek(p -> printer.step(p.toString()))
				.mapToLong(p -> countLinesInFile(p))
				.sum();
			return sum;
		} catch (IOException e) {
			throw new UncheckedIOException(e);
		}
	}

	private static boolean pathContainsOneOfDirs(Path p, Collection<String> excludeDirs) {
		for (int i = 0; i < p.getNameCount(); i++) {
			if (excludeDirs.contains(p.getName(i).toString())) {
				return true;
			}
		}
		return false;
	}

	private static long countLinesInFile(Path p) {
		try (Stream<String> lines = Files.lines(p)) {
			return lines.count();
		} catch (IOException | RuntimeException e) {
			throw new RuntimeException("Error during processing: " + p, e);
		}
	}
}

@@ -33,27 +33,92 @@
 java.io.
-IOException
+BufferedReader;%0Aimport java.io.IOException;%0Aimport java.io.InputStreamReader
 ;%0Aimport
@@ -203,16 +203,57 @@
 e.Path;%0A
+import java.nio.file.StandardOpenOption;%0A
 import j
@@ -353,24 +353,65 @@
 figuration;%0A
+import de.baumato.loc.messages.Messages;%0A
 import de.ba
@@ -693,74 +693,231 @@
 %7B%0A%09%09
-return countLinesInDir(conf.getDirectory(), conf.getExcludeDirs())
+printer.step(%22sep=;%22);%0A%09%09printer.step(Messages.FILE.get() + %22;%22 + Messages.COUNT.get());%0A%09%09long sum = countLinesInDir(conf.getDirectory(), conf.getExcludeDirs());%0A%09%09printer.step(Messages.SUM.get() + %22;%22 + sum);%0A%09%09return sum
 ;%0A%09%7D
@@ -1178,51 +1178,8 @@
 s))%0A
-%09%09%09%09.peek(p -%3E printer.step(p.toString()))%0A
 %09%09%09%09
@@ -1562,23 +1562,16 @@
 private 
-static 
 long cou
@@ -1600,189 +1600,742 @@
 %7B%0A%09%09
-try (Stream%3CString%3E lines = Files.lines(
+long count = countLinesInFile3(p);%0A%09%09printer.step(p.toString() + %22;%22 + count);%0A%09%09return count;%0A%09%7D%0A%0A%09private static long countLinesInFile3(Path 
 p)
-)
  %7B%0A%09%09
-%09return lines.count();%0A%09%09%7D catch (IOException %7C RuntimeException e) %7B%0A%09%09%09throw new RuntimeException(%22Error during processing: %22 + p, 
+/*%0A%09%09 * We cannot use Files.lines because that uses BufferedReader with the default charset and this results%0A%09%09 * to java.nio.charset.MalformedInputException when a file has not the default charset. We can use new%0A%09%09 * Scanner(p) but the scanner is slower than using BufferedReader like below.%0A%09%09 */%0A%09%09try (BufferedReader reader = new BufferedReader(%0A%09%09%09new InputStreamReader(Files.newInputStream(p, StandardOpenOption.READ)))) %7B%0A%09%09%09int count = 0;%0A%09%09%09while (reader.readLine() != null) %7B%0A%09%09%09%09count++;%0A%09%09%09%7D%0A%09%09%09return count;%0A%09%09%7D catch (IOException e) %7B%0A%09%09%09throw new UncheckedIOException(
 e);%0A

Use BufferedReader instead of Files.lines. Add more info in verbose mode