/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.alibaba.nacos.istio.common;

import com.alibaba.nacos.istio.mcp.NacosMcpService;
import com.alibaba.nacos.istio.misc.Loggers;
import com.alibaba.nacos.istio.util.IstioExecutor;
import com.alibaba.nacos.istio.xds.NacosXdsService;
import com.alibaba.nacos.sys.utils.ApplicationUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * EventProcessor.
 *
 * @author special.fy
 */
@Component
public class EventProcessor {

    private static final int MAX_WAIT_EVENT_TIME = 100;

    @Autowired
    private NacosMcpService nacosMcpService;

    @Autowired
    private NacosXdsService nacosXdsService;

    private NacosResourceManager resourceManager;

    private final BlockingQueue<Event> events;

    public EventProcessor() {
        events = new ArrayBlockingQueue<>(20);
    }
    
    /**
     * notify.
     *
     * @param event event
     */
    public void notify(Event event) {
        try {
            events.put(event);
        } catch (InterruptedException e) {
            Loggers.MAIN.warn("There are too many events, this event {} will be ignored.", event.getType());
            // set the interrupted flag
            Thread.currentThread().interrupt();
        }
    }

    @PostConstruct
    public void handleEvents() {
        new Consumer("handle events").start();
    }

    private class Consumer extends Thread {

        Consumer(String name) {
            setName(name);
        }

        @Override
        @SuppressWarnings("InfiniteLoopStatement")
        public void run() {
            Future<Void> task = null;
            boolean hasNewEvent = false;
            Event lastEvent = null;
            while (true) {
                try {
                    // Today we only care about service event,
                    // so we simply ignore event until the last task has been completed.
                    Event event = events.poll(MAX_WAIT_EVENT_TIME, TimeUnit.MILLISECONDS);
                    if (event != null) {
                        hasNewEvent = true;
                        lastEvent = event;
                    }
                    if (hasClientConnection() && needNewTask(hasNewEvent, task)) {
                        task = IstioExecutor.asyncHandleEvent(new EventHandleTask(lastEvent));
                        hasNewEvent = false;
                        lastEvent = null;
                    }
                } catch (InterruptedException e) {
                    Loggers.MAIN.warn("Thread {} is be interrupted.", getName());
                    // set the interrupted flag
                    Thread.currentThread().interrupt();
                }
            }
        }
    }

    private boolean hasClientConnection() {
        return nacosMcpService.hasClientConnection() || nacosXdsService.hasClientConnection();
    }

    private boolean needNewTask(boolean hasNewEvent, Future<Void> task) {
        return hasNewEvent && (task == null || task.isDone());
    }

    private class EventHandleTask implements Callable<Void> {

        private final Event event;

        EventHandleTask(Event event) {
            this.event = event;
        }

        @Override
        public Void call() throws Exception {
            if (null == resourceManager) {
                resourceManager = ApplicationUtils.getBean(NacosResourceManager.class);
            }
            ResourceSnapshot snapshot = resourceManager.createResourceSnapshot();
            nacosXdsService.handleEvent(snapshot, event);
            nacosMcpService.handleEvent(snapshot, event);

            return null;
        }
    }
}

@@ -908,71 +908,8 @@
 ls;%0A
-import org.springframework.beans.factory.annotation.Autowired;%0A
 impo
@@ -953,16 +953,16 @@
 ponent;%0A
+
 %0Aimport 
@@ -993,16 +993,42 @@
 struct;%0A
+import java.util.Objects;%0A
 import j
@@ -1374,31 +1374,16 @@
 = 100;%0A%0A
-    @Autowired%0A
     priv
@@ -1424,23 +1424,8 @@
 e;%0A%0A
-    @Autowired%0A
     
@@ -2531,32 +2531,253 @@
           try %7B%0A
+                    if (!checkDependenceReady()) %7B%0A                        // Make sure dependency service has ready before consumer service event.%0A                        TimeUnit.SECONDS.sleep(1);%0A                    %7D%0A
                 
@@ -4265,153 +4265,8 @@
 n %7B%0A
-            if (null == resourceManager) %7B%0A                resourceManager = ApplicationUtils.getBean(NacosResourceManager.class);%0A            %7D%0A
     
@@ -4459,17 +4459,16 @@
 event);%0A
-%0A
         
@@ -4480,24 +4480,24 @@
 eturn null;%0A
-
         %7D%0A  
@@ -4500,10 +4500,576 @@
 %7D%0A    %7D%0A
+    %0A    private boolean checkDependenceReady() %7B%0A        if (null == resourceManager) %7B%0A            resourceManager = ApplicationUtils.getBean(NacosResourceManager.class);%0A        %7D%0A        if (null == nacosXdsService) %7B%0A            nacosXdsService = ApplicationUtils.getBean(NacosXdsService.class);%0A        %7D%0A        if (null == nacosMcpService) %7B%0A            nacosMcpService = ApplicationUtils.getBean(NacosMcpService.class);%0A        %7D%0A        return Objects.nonNull(resourceManager) && Objects.nonNull(nacosMcpService) && Objects.nonNull(nacosXdsService);%0A    %7D%0A
 %7D%0A

Fix #8405, Remove Autowired in EventProcessor.