package wspp;

import java.io.*;
import java.util.*;

/**
 * @author Nikita Doschennikov (me@fymio.us)
 */
public class WsppPosition {

    public static void main(String[] args) {
        if (args.length != 2) {
            System.err.println(
                "usage: java WsppPosition <inputFilePath> <outputFilePath>"
            );
        }

        final String inputFileName = args[0];
        final String outputFileName = args[1];

        Map<String, WordInfo> words = new LinkedHashMap<>();

        try (
            BufferedReader br = new BufferedReader(
                new FileReader(inputFileName)
            );
            FileWriter fw = new FileWriter(outputFileName)
        ) {
            String line;
            int wordPos = 1;
            int lineNumber = 1;
            while ((line = br.readLine()) != null) {
                line = line.toLowerCase();
                StringBuilder word = new StringBuilder();

                for (char c : line.toCharArray()) {
                    if (
                        Character.isLetter(c) ||
                        c == '\'' ||
                        Character.getType(c) == Character.DASH_PUNCTUATION ||
                        Character.isDigit(c) ||
                        c == '$' ||
                        c == '_'
                    ) {
                        word.append(c);
                    } else {
                        if (!word.isEmpty()) {
                            if (words.containsKey(word.toString())) {
                                var lO = words.get(
                                    word.toString()
                                ).lineOccurrences;
                                if (lO.containsKey(lineNumber)) {
                                    lO.get(lineNumber).put(wordPos++);
                                } else {
                                    var intList = new IntList();
                                    intList.put(wordPos++);
                                    lO.put(lineNumber, intList);
                                }
                            } else {
                                WordInfo info = new WordInfo(
                                    word.toString(),
                                    wordPos
                                );
                                var intList = new IntList();
                                intList.put(wordPos++);
                                info.lineOccurrences.put(lineNumber, intList);
                                words.put(word.toString(), info);
                            }
                        }

                        word = new StringBuilder();
                    }
                }

                if (!word.isEmpty()) {
                    if (words.containsKey(word.toString())) {
                        var lO = words.get(word.toString()).lineOccurrences;
                        if (lO.containsKey(lineNumber)) {
                            lO.get(lineNumber).put(wordPos++);
                        } else {
                            var intList = new IntList();
                            intList.put(wordPos++);
                            lO.put(lineNumber, intList);
                        }
                    } else {
                        WordInfo info = new WordInfo(word.toString(), wordPos);
                        var intList = new IntList();
                        intList.put(wordPos++);
                        info.lineOccurrences.put(lineNumber, intList);
                        words.put(word.toString(), info);
                    }
                }

                lineNumber++;
            }

            List<WordInfo> sortedWords = new ArrayList<>(words.values());
            sortedWords.sort(
                Comparator.comparingInt((WordInfo w) ->
                    w.word.length()
                ).thenComparingInt(w -> w.firstOccurrence)
            );

            for (WordInfo info : sortedWords) {
                int totalNumberOfOccurrences = 0;
                var lO = info.lineOccurrences;
                String word = info.word;
                for (int key : lO.keySet()) {
                    totalNumberOfOccurrences += lO.get(key).getLength();
                }

                fw.write(word + " " + totalNumberOfOccurrences);

                for (int key : lO.keySet()) {
                    var occurrences = lO.get(key);

                    for (int i = 0; i < occurrences.getLength(); i++) {
                        fw.write(
                            " " + key + ":" + (wordPos - occurrences.get(i))
                        );
                    }
                }
                fw.write("\n");
            }
        } catch (IOException e) {
            System.out.println("Error reading file.");
        }
    }
}
