package com.qiniu.android.transaction;

import com.qiniu.android.utils.Utils;

import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * Created by yangsen on 2020/6/9
 */
public class TransactionManager {

    /// 事务链表
    private ConcurrentLinkedQueue<Transaction> transactionList = new ConcurrentLinkedQueue<>();
    /// 事务定时器
    private Timer timer;

    private static final TransactionManager transactionManager = new TransactionManager();

    private TransactionManager() {
    }

    public static TransactionManager getInstance() {
        return transactionManager;
    }

    /// 根据name查找事务
    public ArrayList<Transaction> transactionsForName(String name) {
        ArrayList<Transaction> arrayList = new ArrayList<>();
        for (Transaction transaction : transactionList) {
            if ((name == null && transaction.name == null) || (transaction.name != null && transaction.name.equals(name))) {
                arrayList.add(transaction);
            }
        }
        return arrayList;
    }

    /// 是否存在某个名称的事务
    public boolean existTransactionsForName(String name) {
        boolean isExist = false;
        for (Transaction transaction : transactionList) {
            if ((name == null && transaction.name == null) || (transaction.name != null && transaction.name.equals(name))) {
                isExist = true;
                break;
            }
        }
        return isExist;
    }

    /// 添加一个事务
    public synchronized void addTransaction(Transaction transaction) {
        if (transaction == null) {
            return;
        }
        transactionList.add(transaction);
        createTimer();
    }

    /// 移除一个事务
    public synchronized void removeTransaction(Transaction transaction) {
        if (transaction == null) {
            return;
        }
        transactionList.remove(transaction);
    }

    /// 在下一次循环执行事务, 该事务如果未被添加到事务列表，会自动添加
    public synchronized void performTransaction(Transaction transaction) {
        if (transaction == null) {
            return;
        }

        if (!transactionList.contains(transaction)) {
            transactionList.add(transaction);
        }
        transaction.createTime = Utils.currentSecondTimestamp() - transaction.interval;
    }

    /// 销毁资源 清空事务链表 销毁常驻线程
    public synchronized void destroyResource() {
        invalidateTimer();
        transactionList.clear();
    }


    private void handleAllTransaction() {
        for (Transaction transaction : transactionList) {
            handleTransaction(transaction);
            if (transaction.maybeCompleted()) {
                removeTransaction(transaction);
            }
        }
    }

    private void handleTransaction(Transaction transaction) {
        transaction.handleAction();
    }


    private synchronized void createTimer() {
        if (timer != null) {
            return;
        }
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                timerAction();
            }
        }, 0, 1000);
    }

    private void invalidateTimer() {
        timer.cancel();
        timer = null;
    }

    private void timerAction() {
        handleAllTransaction();
    }


    public static class Transaction {

        // 事务名称
        public final String name;
        // 事务延迟执行时间 单位：秒
        public final int after;
        // 事务内容
        public final Runnable actionHandler;


        // 普通类型事务，事务体仅会执行一次
        private static final int TransactionTypeNormal = 0;
        // 定时事务，事务体会定时执行
        private static final int TransactionTypeTime = 1;
        private final int type;

        // 事务延后时间 单位：秒
        private final int interval;
        // 创建时间
        private long createTime;

        // 已执行次数
        private long executedCount = 0;
        private boolean isExecuting = false;


        public Transaction(String name,
                           int after,
                           Runnable actionHandler) {

            this.type = TransactionTypeNormal;
            this.name = name;
            this.after = after;
            this.interval = 0;
            this.actionHandler = actionHandler;
            this.createTime = Utils.currentSecondTimestamp();
        }


        public Transaction(String name,
                           int after,
                           int interval,
                           Runnable actionHandler) {

            this.type = TransactionTypeTime;
            this.name = name;
            this.after = after;
            this.interval = interval;
            this.actionHandler = actionHandler;
            this.createTime = Utils.currentSecondTimestamp();
        }

        private boolean shouldAction() {
            long currentTime = Utils.currentSecondTimestamp();
            if (this.type == TransactionTypeNormal) {
                return executedCount < 1 && (currentTime - createTime) >= after;
            } else if (this.type == TransactionTypeTime) {
                return (currentTime - createTime) >= (executedCount * interval + after);
            } else {
                return false;
            }
        }

        private boolean maybeCompleted() {
            if (this.type == TransactionTypeNormal) {
                return executedCount > 0;
            } else if (this.type == TransactionTypeTime) {
                return false;
            } else {
                return false;
            }
        }

        private synchronized void handleAction() {
            if (!shouldAction()) {
                return;
            }
            if (actionHandler != null) {
                executedCount += 1;
                isExecuting = true;
                actionHandler.run();
                isExecuting = false;
            }
        }

        public boolean isExecuting() {
            return isExecuting;
        }
    }

}

@@ -100,16 +100,39 @@
 ayList;%0A
+import java.util.List;%0A
 import j
@@ -329,16 +329,22 @@
 private 
+final 
 Concurre
@@ -718,16 +718,29 @@
  public 
+synchronized 
 ArrayLis
@@ -847,24 +847,114 @@
 ayList%3C%3E();%0A
+        Transaction%5B%5D transactionList = this.transactionList.toArray(new Transaction%5B0%5D);%0A
         for 
@@ -1248,32 +1248,45 @@
 %E7%A7%B0%E7%9A%84%E4%BA%8B%E5%8A%A1%0A    public 
+synchronized 
 boolean existTra
@@ -1342,32 +1342,122 @@
 sExist = false;%0A
+        Transaction%5B%5D transactionList = this.transactionList.toArray(new Transaction%5B0%5D);%0A
         for (Tra
@@ -2727,32 +2727,199 @@
 Transaction() %7B%0A
+        Transaction%5B%5D transactionList = null;%0A        synchronized (this) %7B%0A            transactionList = this.transactionList.toArray(new Transaction%5B0%5D);%0A        %7D%0A%0A
         for (Tra

optimize transaction manager