package io.github.vcuswimlab.stackintheflow.model.difficulty;

import com.intellij.openapi.project.Project;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.messages.MessageBusConnection;
import io.github.vcuswimlab.stackintheflow.controller.component.TermStatComponent;
import io.github.vcuswimlab.stackintheflow.controller.component.ToolWindowComponent;
import io.github.vcuswimlab.stackintheflow.model.difficulty.events.DifficultyTrigger;
import io.github.vcuswimlab.stackintheflow.model.difficulty.events.EditorEventType;
import io.github.vcuswimlab.stackintheflow.view.SearchToolWindowGUI;

import java.util.ArrayDeque;
import java.util.EnumMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Created by Chase on 5/23/2017.
 */
public class DifficultyModel {

    private static final double DELETE_RATIO = .6;
    private static final int QUERY_DELAY = 30; //Delay in seconds
    private static final int INACTIVE_DELAY = 15; //Delay in minutes
    private final int MAX_QUEUE_SIZE = 25;

    private Project project;
    private MessageBus messageBus;
    private MessageBusConnection connection;

    private Map<EditorEventType, Integer> eventCounts;

    private Queue<EditorEventType> eventQueue;
    private State currentState;
    private ScheduledThreadPoolExecutor timer;
    private ScheduledFuture<?> inactiveTaskFuture;
    private SearchToolWindowGUI gui;

    public DifficultyModel(Project project) {
        this.project = project;
        messageBus = project.getMessageBus();
        connection = messageBus.connect();
        eventCounts = new EnumMap<>(EditorEventType.class);
        eventQueue = new ArrayDeque<>(MAX_QUEUE_SIZE);

        currentState = State.COLLECT;
        timer = new ScheduledThreadPoolExecutor(1);

        gui = project.getComponent(ToolWindowComponent.class).getSearchToolWindowGUI();

        connection.subscribe(DifficultyTrigger.DIFFICULTY_TRIGGER_TOPIC, event -> {

            switch (currentState) {
                case PAUSE:
                    //Transition to collect state, queue event
                    currentState = State.COLLECT;
                    System.out.println("COLLECT!");
                case COLLECT:
                    eventCounts.put(event.getType(), eventCounts.getOrDefault(event.getType(), 0) + 1);

                    //Reset Inactive Task
                    if (inactiveTaskFuture != null) {
                        inactiveTaskFuture.cancel(true);
                    }
                    inactiveTaskFuture = timer.schedule(() -> {
                        currentState = State.PAUSE;
                        System.out.println("PAUSE!");
                    }, INACTIVE_DELAY, TimeUnit.MINUTES);

                    if (isFull()) {
                        EditorEventType oldEventType = eventQueue.poll();
                        eventCounts.put(oldEventType, eventCounts.getOrDefault(oldEventType, 1) - 1);

                        // If we have crossed the threshold, initiate a query and transition to query state
                        if (getRatio(EditorEventType.DELETE) >= DELETE_RATIO) {

                            //Generate the autoQuery
                            String autoQuery = project.getComponent(TermStatComponent.class).generateQuery(event.getEditor());

                            //Execute Search
                            SearchToolWindowGUI toolWindowGUI = project.getComponent(ToolWindowComponent.class).getSearchToolWindowGUI();
                            toolWindowGUI.executeQuery(autoQuery, true);

                            System.out.println("QUERY!");
                            eventQueue.clear();
                            currentState = State.QUERY;

                            //After QUERY_DELAY seconds, transition to collect state
                            timer.schedule(() -> currentState = State.COLLECT, QUERY_DELAY, TimeUnit.SECONDS);

                            //Remove the inactive task as we no longer need it in this state
                            inactiveTaskFuture.cancel(true);
                        }
                    }

                    eventQueue.offer(event.getType());
                    break;
                case QUERY:
                    //Do nothing
                    break;
            }
        });
    }

    private boolean isFull() {
        return eventQueue.size() == 25;
    }

    private double getRatio(EditorEventType eventType) {

        if (eventCounts.isEmpty()) {
            return 0;
        }

        return eventCounts.getOrDefault(eventType, 0) / (double) eventQueue.size();
    }

    private enum State {
        COLLECT, QUERY, PAUSE
    }
}

@@ -101,16 +101,109 @@
 roject;%0A
+import com.intellij.openapi.wm.ToolWindow;%0Aimport com.intellij.openapi.wm.ToolWindowManager;%0A
 import c
@@ -1116,24 +1116,25 @@
 LAY = 30; //
+ 
 Delay in sec
@@ -1190,16 +1190,17 @@
 = 15; //
+ 
 Delay in
@@ -2267,16 +2267,17 @@
       //
+ 
 Transiti
@@ -2363,60 +2363,8 @@
 CT;%0A
-                    System.out.println(%22COLLECT!%22);%0A
     
@@ -2516,16 +2516,17 @@
       //
+ 
 Reset In
@@ -2736,137 +2736,34 @@
  -%3E 
-%7B%0A                        currentState = State.PAUSE;%0A                        System.out.println(%22PAUSE!%22);%0A                    %7D
+currentState = State.PAUSE
 , IN
@@ -3226,18 +3226,307 @@
         
-//
+ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow(%22StackInTheFlow%22);%0A%0A                            // Check to see if the tool window is active before generating the query.%0A                            if (toolWindow.isActive()) %7B%0A                                // 
 Generate
@@ -3540,16 +3540,20 @@
 toQuery%0A
+    
         
@@ -3700,18 +3700,23 @@
         
+   
+ 
 //
+ 
 Execute 
@@ -3722,16 +3722,20 @@
  Search%0A
+    
         
@@ -3892,16 +3892,20 @@
         
+    
 toolWind
@@ -3941,17 +3941,16 @@
  true);%0A
-%0A
         
@@ -3973,37 +3973,10 @@
     
-System.out.println(%22QUERY!%22);
+%7D%0A
 %0A   
@@ -4107,16 +4107,17 @@
       //
+ 
 After QU
@@ -4305,16 +4305,17 @@
       //
+ 
 Remove t
@@ -4611,16 +4611,17 @@
       //
+ 
 Do nothi

Add check to prevent auto-query generation via difficulty detection when the tool window is closed.