import java.util.ArrayList;

class Word {
	String word;
	int paragraph;
}

public class TestEfficiency {
	static final int repeatInsert = 2;
	static final int repeatFrequency = 200000;
	static final int repeatDiffWords = 100000;
	static final int repeatMeanWordCount = 100000;
	static final int repeatWordsFreq = 5000;
	static final int repeatWordsStart = 5000;

  static final int prime = 101;
  static int line = 1;
	
	public static void main(String[] args) {
		Out.println("--- 1. WordIndexList ---");
		testEfficiency(new WordIndexList());
		Out.println("--- 2. WordIndexTree ---");
		testEfficiency(new WordIndexTree());
	}
	private static Word readWord() {
		StringBuilder b = new StringBuilder();
		char ch;
		// read over non-words
		do {
			ch = In.read();
			if(ch == '\n') line++;
		} while(In.done() && !Character.isLetter(ch));
		// read word until whitespace
		while(In.done() && Character.isLetter(ch)) {
			b.append(ch);
			ch = In.read();
			if(ch == '\'') {
				do {
					ch = In.read();
					if(ch == '\n') line++;
				} while(!Character.isWhitespace(ch));
			}
		}
		Word w = new Word();
		w.word = b.toString().toLowerCase();
		w.paragraph = line;
		return w;
	}
  static void testEfficiency(WordIndex list) {
    String fn;        // file name for efficiency test
    ArrayList<Word> words;  // words in file
    int size;         // amount of words in ArrayList
    Word word;      // temorary word (file, ArrayList)
    WordIndex[] wlarr; // array of wordlists for testing purpose
    WordIndex wl;      // single wordlist for testing purpose
    String wordStart; // start of a word in the list
    int i, j;         // loop variables
    int freq;         // frequency of words
    long start1;      // start time
    long start2;      // intermediate time
    long end;         // end time
    // intermediate - start => WordList independant time
    // end - intermediate => total time
    // (end - intermediate) - (intermediate - start) => total time, Wordlist dependant

		fn = "Alice.txt";
    // Open file and read content into ArrayList
    In.open(fn);
    if (!In.done()) {
      return;
    }
    words = new ArrayList<Word>();
		Word w = readWord();
		while(In.done()) {
			words.add(w);
			w = readWord();
		}
    In.close();

    size = words.size();
    Out.println("File " + fn + " read (" + size + " words).");

    // Test inserting words
    wlarr = new WordIndex[repeatInsert];
    for (i = 0; i < repeatInsert; i ++) {
      wlarr[i] = list;
    }
    start1 = System.currentTimeMillis();
    for (i = 0; i < repeatInsert; i ++) {
      for (j = 0; j < size; j ++) {
        word = words.get(j);
      }
    }
    start2 = System.currentTimeMillis();
    for (i = 0; i < repeatInsert; i ++) {
      for (j = 0; j < size; j ++) {
        word = words.get(j);
        wlarr[i].insert(word.word, word.paragraph);
      }
    }
    end = System.currentTimeMillis();
    wl = wlarr[0];
		Out.println(
			String.format("Inserting %d words needs %.2f  milliseconds (dw = %d, mean = %.2f | %d/%d)", 
				size,
				((double)(end - start2 - (start2 - start1))) / repeatInsert,
				wl.getDifferentWordCount(),
				wl.getMeanWordFrequency(),
				(end - start2),
				(start2 - start1)
			)
		);

    // Test getFrequency
    start1 = System.currentTimeMillis();
    for (i = 0; i < repeatFrequency; i ++) {
      word = words.get((i * prime) % size);
    }
    start2 = System.currentTimeMillis();
    for (i = 0; i < repeatFrequency; i ++) {
      word = words.get((i * prime) % size);
      wl.getFrequency(word.word);
    }
    end = System.currentTimeMillis();
    Out.println(
			String.format("getFrequency needs %.6f milliseconds (%d/%d)",
				((double)(end - start2 - (start2 - start1))) / repeatFrequency,
				(end - start2),
				(start2 - start1)
 			)
		);

    // Test getDifferentWordCount
    start1 = System.currentTimeMillis();
    for (i = 0; i < repeatDiffWords; i ++) {
    }
    start2 = System.currentTimeMillis();
    for (i = 0; i < repeatDiffWords; i ++) {
      wl.getDifferentWordCount();
    }
    end = System.currentTimeMillis();
    Out.println(
			String.format("getDifferentWordCount needs %.6f milliseconds (%d/%d)",
				((double)(end - start2 - (start2 - start1))) / repeatDiffWords,
				(end - start2),
				(start2 - start1)
			)
		);

    // Test meanWordCount
    start1 = System.currentTimeMillis();
    for (i = 0; i < repeatMeanWordCount; i ++) {
    }
    start2 = System.currentTimeMillis();
    for (i = 0; i < repeatMeanWordCount; i ++) {
      wl.getMeanWordFrequency();
    }
    end = System.currentTimeMillis();
    Out.println(
			String.format("meanWordCount needs %.6f milliseconds (%d/%d)",
				((double)(end - start2 - (start2 - start1))) / repeatMeanWordCount,
				(end - start2),
				(start2 - start1)
			)
		);

    // Test getWords (1)
    start1 = System.currentTimeMillis();
    for (i = 0; i < repeatWordsFreq; i ++) {
      freq = i % 399 + 1;
    }
    start2 = System.currentTimeMillis();
    for (i = 0; i < repeatWordsFreq; i ++) {
      freq = i % 399 + 1;
      wl.getWordsWithMinFrequency(freq);
    }
    end = System.currentTimeMillis();
    Out.println(
			String.format("getWords (1-400) needs %.6f milliseconds (%d/%d)",
 				((double)(end - start2 - (start2 - start1))) / repeatWordsFreq,
 				(end - start2),
 				(start2 - start1)
 			)
		);

    // Test getWords (2)
    start1 = System.currentTimeMillis();
    for (i = 0; i < repeatWordsFreq; i ++) {
      freq = i % 19 + 1;
    }
    start2 = System.currentTimeMillis();
    for (i = 0; i < repeatWordsFreq; i ++) {
      freq = i % 19 + 1;
      wl.getWordsWithMinFrequency(freq);
    }
    end = System.currentTimeMillis();
    Out.println(
			String.format("getWords (1-20) needs %.6f milliseconds (%d/%d)",
				((double)(end - start2 - (start2 - start1))) / repeatWordsFreq,
				(end - start2),
				(start2 - start1)
			)
		);

    // Test getWordsStartingWith
    start1 = System.currentTimeMillis();
    for (i = 0; i < repeatWordsStart; i ++) {
      wordStart = words.get((i * prime) % size).word;
      wordStart = wordStart.substring(0, Math.min(i % 5 + 1, wordStart.length()));
    }
    start2 = System.currentTimeMillis();
    for (i = 0; i < repeatWordsStart; i ++) {
      wordStart = words.get((i * prime) % size).word;
      wordStart = wordStart.substring(0, Math.min(i % 5 + 1, wordStart.length()));
      wl.getWordsStartingWith(wordStart);
    }
    end = System.currentTimeMillis();
    Out.println(
			String.format("getWordsStartingWith needs %.6f milliseconds (%d/%d)",
				((double)(end - start2 - (start2 - start1))) / repeatWordsStart,
				(end - start2),
				(start2 - start1)
			)
		);
  }
}

