package org.nl.acs.auto.run;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.nl.acs.auto.initial.ApplicationAutoInitial;
import org.nl.common.exception.BadRequestException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 初始化启动线程
 */
@Service
@Slf4j
public class AutoRunServiceImpl implements AutoRunService, ApplicationAutoInitial {
    @Autowired(required = false)
    private List<AbstractAutoRunnable> abstractAutoRunnableList;
    private List<AbstractAutoRunnable> thread_autoRun = new ArrayList(); // 线程类
    private List<String> autoRun_code_index = new ArrayList(); // key
    private List<Thread> threads = new ArrayList(); // 运行线程
    private List<String> thread_code_index = new ArrayList(); // key

    @Override
    public synchronized void startThread(String threadCode) {
        Thread thread = this.getThreadByCode(threadCode);
        if (thread == null) {
            throw new BadRequestException("线程不存在");
        } else if (thread.isAlive()) {
            throw new BadRequestException("已运行的无法开启运行");
        } else {
            int index = this.thread_code_index.indexOf(threadCode);
            thread = new Thread(this.getRunablebyCode(threadCode));
            this.threads.set(index, thread);
            thread.start();
        }
    }

    @Override
    public synchronized void stopThread(String threadCode) {
        Thread thread = this.getThreadByCode(threadCode);
        if (thread == null) {
            throw new BadRequestException("线程不存在");
        } else if (!thread.isAlive()) {
            throw new BadRequestException("已停止的无法再次停止");
        } else {
            AbstractAutoRunnable runable = this.getRunablebyCode(threadCode);
            runable.stop();
            thread.stop();
            thread.interrupt();

            try {
                thread.join();
            } catch (InterruptedException arg4) {
                arg4.printStackTrace();
            }

            runable.setStopMessage("人工停止");
            runable.setStopTime(new Date());

        }
    }

    @Override
    public Thread getThreadByCode(String code) {
        int index = this.thread_code_index.indexOf(code);
        return index < 0 ? null : (Thread) this.threads.get(index);
    }

    private AbstractAutoRunnable getRunablebyCode(String code) {
        int index = this.thread_code_index.indexOf(code);
        return index < 0 ? null : (AbstractAutoRunnable) this.thread_autoRun.get(index);
    }

    @Override
    public List<ThreadDto> findAll() {
        ArrayList list = new ArrayList();
        List list2 = this.getAllAutoThread();
        Iterator arg2 = list2.iterator();

        AbstractAutoRunnable t;
        ThreadDto e;
        while (arg2.hasNext()) {
            t = (AbstractAutoRunnable) arg2.next();
            if (ThreadUsedStatusEnum.unUsed.equals(t.getUsedStatus())) {
                e = new ThreadDto();
                BeanUtil.copyProperties(t, e, true);
                list.add(e);
            }
        }

        arg2 = this.thread_autoRun.iterator();

        while (arg2.hasNext()) {
            t = (AbstractAutoRunnable) arg2.next();
            e = new ThreadDto();
            BeanUtil.copyProperties(t, e, true);
            Thread thread = this.getThreadByCode(t.getCode());
            e.setCode(t.getCode());
            e.setName(t.getName());

            e.setThread_alive(Boolean.valueOf(thread.isAlive()));
            e.setThread_name(thread.getName());
            e.setThread_id(thread.getId() + "");
            e.setThread_state(thread.getState().toString());
            list.add(e);
        }

        return list;
    }

    @Override
    public List<ThreadDto> findByCondition(Map whereJson) {
        List ori_threads = this.findAll();
        ArrayList return_threads = new ArrayList();
        if (CollectionUtil.isEmpty(whereJson)) {
            return ori_threads;
        } else {
            Iterator it = ori_threads.iterator();

            while (it.hasNext()) {
                ThreadDto thread = (ThreadDto) it.next();
                Map<String, Object> properties = BeanUtil.beanToMap(thread);

                Iterator<Map.Entry<String, Object>> entries = whereJson.entrySet().iterator();

                while (entries.hasNext()) {
                    Map.Entry<String, Object> entry = entries.next();
                    String column = entry.getKey();
                    String value = (String) entry.getValue();
                    if (properties.containsKey(column)) {
                        String propert = (String) properties.get(column);

                        if (!StrUtil.isEmpty(propert)
                                && propert.contains(value)) {
                            return_threads.add(thread);
                        }
                    }
                }
            }

            return return_threads;
        }

    }


    @Override
    public ThreadDto findByCode(String thread_code, String thread_id) {
        List ori_threads = this.findAll();
        Iterator arg3 = ori_threads.iterator();

        ThreadDto thread;
        do {
            if (!arg3.hasNext()) {
                return null;
            }

            thread = (ThreadDto) arg3.next();
        } while (!StrUtil.equals(thread.getCode(), thread_code)
                || !StrUtil.equals(thread.getThread_id(), thread_id));

        return thread;
    }


    private List<AbstractAutoRunnable> getAllAutoThread() {
        return ObjectUtil.isNotEmpty(abstractAutoRunnableList)
                ? this.abstractAutoRunnableList
                : new LinkedList();
    }

    /**
     * 自动初始化线程
     * @throws Exception
     */
    @Override
    public void autoInitial() throws Exception {
        // 获取所有的类型为AbstractAutoRunnable的bean
        List<AbstractAutoRunnable> list = this.getAllAutoThread();
        Iterator it = list.iterator();

        AbstractAutoRunnable t;
        while (it.hasNext()) {
            t = (AbstractAutoRunnable) it.next();
            t.setUsedStatus(ThreadUsedStatusEnum.unUsed);
            String a;
            if (StrUtil.isEmpty(t.getCode())) {
                a = "code 因为空而未加载";
                log.warn(a);
                t.setStopMessage(a);
                this.autoRun_code_index.add(t.getCode());
            } else if (this.autoRun_code_index.contains(t.getCode())) {
                a = String.format("code:%s 因为重复而未加载", new Object[]{t.getCode()});
                log.warn(a);
                t.setStopMessage(a);
                this.autoRun_code_index.add(t.getCode());
            } else {
                t.setUsedStatus(ThreadUsedStatusEnum.used);
                this.thread_autoRun.add(t);
                this.autoRun_code_index.add(t.getCode());
            }
        }

        it = this.thread_autoRun.iterator();

        while (it.hasNext()) {
            t = (AbstractAutoRunnable) it.next();
            this.threads.add(new Thread(t));
            this.thread_code_index.add(t.getCode());
        }

        for (int i = 0; i < this.threads.size(); ++i) {
            Thread thread = (Thread) this.threads.get(i);
            AbstractAutoRunnable runnable = (AbstractAutoRunnable) this.thread_autoRun.get(i);
            if (runnable.getForbidStop().booleanValue()) {
                thread.start();
            } else if (SystemConfig.thread_auto_run.booleanValue() && (!DevelopConfig.develop.booleanValue()
                    || !DevelopConfig.thread_auto_run_force_stop.contains(this.thread_code_index.get(i)))) {
                thread.start();
            }
        }

    }
}
