package org.academiadecodigo.enuminatti.wordreader;

import java.io.*;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * MIT License
 * (c) 2017 Ricardo Constantino
 */

public class WordReader implements Iterable<String> {
    private String fileName;
    private int totalWordCount;

    public WordReader(String fileName) {
        this.fileName = fileName;
    }

    public int getWordCount() {
        return totalWordCount;
    }

    @Override
    public Iterator<String> iterator() {

        return new Iterator<String>() {
            FileReader fileReader;
            BufferedReader reader;
            private String[] currentLineWords;
            private int wordsSaid;
            private int wordCount;

            private void openReaders() {
                try {
                    fileReader = new FileReader(fileName);
                    reader = new BufferedReader(fileReader);
                } catch (FileNotFoundException e) {
                    System.err.println("file not found");
                    System.exit(1);
                }
            }

            private void closeReaders() {
                try {
                    fileReader.close();
                    reader.close();
                } catch (IOException e) {
                    System.err.println("couldn't close file");
                }
            }

            private void getNewWords() {
                try {
                    String line = reader.readLine();
                    String[] words;

                    // if next line is empty, get a new one
                    while (line != null) {
                        words = line.split("\\s+");

                        // if there's any non-whitespace, leave the loop
                        if (words.length > 0 && words[0].length() != 0) {
                            currentLineWords = words;
                            wordsSaid = 0;
                            updateWordCount(currentLineWords.length);
                            return;
                        }

                        line = reader.readLine();
                    }

                    // in case there's empty lines immediately before EOF
                    throw new IOException();
                } catch (IOException e) {
                    closeReaders();
                }
            }

            @Override
            public boolean hasNext() {
                // only runs once, at start of iteration
                if (currentLineWords == null) {
                    openReaders();
                    getNewWords();
                }

                // runs after iterating through all words in current line
                if (wordsSaid == currentLineWords.length) {
                    getNewWords();
                }

                return wordsSaid < currentLineWords.length;
            }

            @Override
            public String next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }

                return currentLineWords[wordsSaid++];
            }

            private void updateWordCount(int newWordsCount) {
                wordCount += newWordsCount;
                totalWordCount += (totalWordCount < wordCount) ? newWordsCount : 0;
            }
        };
    }
}
