package com.codeborne.selenide.impl;

import com.codeborne.selenide.logevents.LogEventListener;

import java.util.ArrayList;
import java.util.List;

/**
 * Logs Selenide test steps and notifies all registered LogEventListener about it
 */
public class SelenideLogger {
  public enum EventStatus {
    IN_PROGRESS, PASSED, FAILED
  }

  protected static ThreadLocal<List<LogEventListener>> listeners =
      new ThreadLocal<List<LogEventListener>>();

  protected static ThreadLocal<SelenideLog> eventLog = new ThreadLocal<SelenideLog>();

  public static void addListener(LogEventListener listener) {
    List<LogEventListener> list = listeners.get();
    if (list == null) {
      list = new ArrayList<LogEventListener>();
    }

    list.add(listener);
    listeners.set(list);
  }

  public static void beginStep(Object el, String subject) {
    if (el instanceof AbstractSelenideElement) {
      eventLog.set(new SelenideLog(((AbstractSelenideElement) el).getSearchCriteria(), subject));
    }
    if (el instanceof Navigator) {
      eventLog.set(new SelenideLog("", subject));
    }
  }

  public static void commitStep(EventStatus status) {
    SelenideLog currentLog = eventLog.get();
    if (currentLog == null) {
      throw new IllegalStateException("Cannot commit step that is not started: " + status);
    }
    
    currentLog.setStatus(status);

    List<LogEventListener> listeners = getEventLoggerListeners();
    for (LogEventListener listener : listeners) {
      listener.onEvent(currentLog);
    }

    eventLog.set(null);
  }

  private static List<LogEventListener> getEventLoggerListeners() {
    if (listeners.get() == null) {
      listeners.set(new ArrayList<LogEventListener>());
    }
    return listeners.get();
  }

  public static void clearListeners() {
    listeners.remove();
  }
}

@@ -112,20 +112,73 @@
 il.Array
-List
+Deque;%0Aimport java.util.ArrayList;%0Aimport java.util.Deque
 ;%0Aimport
@@ -520,32 +520,38 @@
 tic ThreadLocal%3C
+Deque%3C
 SelenideLog%3E eve
@@ -546,16 +546,17 @@
 nideLog%3E
+%3E
  eventLo
@@ -575,16 +575,22 @@
 adLocal%3C
+Deque%3C
 Selenide
@@ -593,18 +593,139 @@
 nideLog%3E
+%3E
 ()
+ %7B%0A    @Override%0A    protected Deque%3CSelenideLog%3E initialValue() %7B%0A      return new ArrayDeque%3CSelenideLog%3E();%0A    %7D%0A  %7D
 ;%0A%0A  pub
@@ -1003,18 +1003,22 @@
 (Object 
+sourc
 e
-l
 , String
@@ -1029,30 +1029,85 @@
 ject) %7B%0A    
-if (el
+Deque%3CSelenideLog%3E eventLogs = eventLog.get();%0A    if (source
  instanceof 
@@ -1139,36 +1139,37 @@
 %7B%0A      eventLog
-.set
+s.add
 (new SelenideLog
@@ -1196,18 +1196,22 @@
 lement) 
+sourc
 e
-l
 ).getSea
@@ -1250,14 +1250,23 @@
     
-if (el
+else if (source
  ins
@@ -1300,20 +1300,21 @@
 eventLog
-.set
+s.add
 (new Sel
@@ -1343,16 +1343,110 @@
 ;%0A    %7D%0A
+    else %7B%0A      throw new IllegalArgumentException(%22Unknown event source: %22 + source);%0A    %7D%0A
   %7D%0A%0A  p
@@ -1500,16 +1500,22 @@
 ) %7B%0A    
+Deque%3C
 Selenide
@@ -1517,27 +1517,27 @@
 enideLog
- curr
+%3E ev
 entLog
+s
  = event
@@ -1559,26 +1559,29 @@
 if (
-curr
+ev
 entLog
- == null
+s.size() == 0
 ) %7B%0A
@@ -1678,20 +1678,63 @@
 ;%0A    %7D%0A
+%0A
     
+SelenideLog currentLog = eventLogs.peek();
 %0A    cur
@@ -1936,17 +1936,17 @@
 tLog
-.set(null
+s.remove(
 );%0A 

support multiple events within one call