package info.javaspec.console;

import info.javaspec.Spec;
import info.javaspec.SpecCollection;

import java.io.PrintStream;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;

final class NewConsoleReporter implements Reporter {
  private final PrintStream output;
  private final Deque<CollectionScope> scopes;

  private boolean hasPrintedAnyLines;
  private String collectionIndentation;
  private String specIndentation;
  private int numCollectionsInScope;

  public NewConsoleReporter(PrintStream output) {
    this.output = output;
    this.scopes = new ArrayDeque<>();
    this.hasPrintedAnyLines = false;
    this.collectionIndentation = "";
    this.specIndentation = "";
    this.numCollectionsInScope = 0;
  }

  /* HelpObserver */

  @Override
  public void writeMessage(List<String> lines) {
    lines.forEach(this.output::println);
  }

  /* RunObserver */

  @Override
  public void beginCollection(SpecCollection collection) {
    CollectionScope containingScope = this.scopes.peekLast();
    if(containingScope.hasPrintedAnything())
      this.output.println();

    this.output.println(this.collectionIndentation + collection.description());
    containingScope.somethingPrinted();
    this.hasPrintedAnyLines = true;
    this.numCollectionsInScope += 1;

    this.collectionIndentation += "  ";
    if(this.numCollectionsInScope > 1)
      this.specIndentation += "  ";

    this.scopes.addLast(CollectionScope.forCollection(collection));
  }

  @Override
  public void endCollection(SpecCollection collection) {
    this.collectionIndentation = this.collectionIndentation.substring(0, this.collectionIndentation.length() - 2);
    this.specIndentation = this.specIndentation.substring(0, Math.max(0, this.specIndentation.length() - 2));
    this.numCollectionsInScope -= 1;
    this.scopes.removeLast();
  }

  @Override
  public boolean hasFailingSpecs() {
    throw new UnsupportedOperationException();
  }

  @Override
  public void runStarting() {
    this.scopes.addLast(CollectionScope.forRoot());
  }

  @Override
  public void runFinished() {
    if(this.hasPrintedAnyLines)
      this.output.println();

    this.output.println("[Testing complete] Passed: 0, Failed: 0, Total: 0");
  }

  @Override
  public void specStarting(Spec spec) {
    this.output.print(this.specIndentation + "- " + spec.intendedBehavior());
  }

  @Override
  public void specFailed(Spec spec) {
    this.output.println(": FAIL");
    this.hasPrintedAnyLines = true;
  }

  @Override
  public void specPassed(Spec spec) {
    this.output.println(": PASS");
    this.hasPrintedAnyLines = true;
  }

  private static final class CollectionScope {
    private final String source;
    private int numItemsPrinted;

    public static CollectionScope forRoot() {
      return new CollectionScope("root");
    }

    public static CollectionScope forCollection(SpecCollection collection) {
      return new CollectionScope(collection.description());
    }

    private CollectionScope(String source) {
      this.source = source;
      this.numItemsPrinted = 0;
    }

    public boolean hasPrintedAnything() {
      return this.numItemsPrinted > 0;
    }

    public void somethingPrinted() {
      this.numItemsPrinted++;
    }
  }
}

@@ -374,48 +374,8 @@
 es;%0A
-  private String collectionIndentation;%0A
   pr
@@ -597,45 +597,8 @@
 se;%0A
-    this.collectionIndentation = %22%22;%0A
     
@@ -1031,121 +1031,50 @@
     
-this.output.println(this.collectionIndentation + collection.description());%0A    containingScope.somethingPrinted(
+containingScope.beginCollection(collection
 );%0A 
@@ -1150,48 +1150,8 @@
 1;%0A%0A
-    this.collectionIndentation += %22  %22;%0A
     
@@ -1226,36 +1226,43 @@
 %22;%0A%0A    
-this.scopes.addLast(
+CollectionScope newScope = 
 Collecti
@@ -1293,17 +1293,68 @@
 llection
-)
+, containingScope);%0A    this.scopes.addLast(newScope
 );%0A  %7D%0A%0A
@@ -1426,123 +1426,8 @@
 ) %7B%0A
-    this.collectionIndentation = this.collectionIndentation.substring(0, this.collectionIndentation.length() - 2);%0A
     
@@ -1795,16 +1795,27 @@
 forRoot(
+this.output
 ));%0A  %7D%0A
@@ -2454,29 +2454,82 @@
 e final 
-String source
+PrintStream output;%0A    private final String collectionIndentation
 ;%0A    pr
@@ -2597,251 +2597,559 @@
  for
-Root() %7B%0A      return new CollectionScope(%22root%22);%0A    %7D%0A%0A    public static CollectionScope forCollection(SpecCollection collection) %7B%0A      return new CollectionScope(collection.description());%0A    %7D%0A%0A    private CollectionScope(String source
+Collection(SpecCollection collection, CollectionScope parentScope) %7B%0A      return new CollectionScope(parentScope.output, parentScope.collectionIndentation + %22  %22);%0A    %7D%0A%0A    public static CollectionScope forRoot(PrintStream output) %7B%0A      return new CollectionScope(output, %22%22);%0A    %7D%0A%0A    private CollectionScope(PrintStream output, String collectionIndentation) %7B%0A      this.output = output;%0A      this.collectionIndentation = collectionIndentation;%0A      this.numItemsPrinted = 0;%0A    %7D%0A%0A    public void beginCollection(SpecCollection collection
 ) %7B%0A
@@ -3163,55 +3163,103 @@
 his.
-s
 ou
-rce = source;%0A      this.numItems
+tput.println(this.collectionIndentation + collection.description());%0A      something
 Printed
- = 0
+()
 ;%0A  

Move collection indentation to CollectionScope