package com.ejlchina.searcher;

import com.ejlchina.searcher.dialect.Dialect;
import com.ejlchina.searcher.dialect.DialectSensor;
import com.ejlchina.searcher.implement.DialectWrapper;
import com.ejlchina.searcher.operator.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 字段运算符池（支持的运算符都在这里）
 * @author Troy.Zhou @ 2022-01-19
 * @since v3.3.0
 */
public class FieldOpPool extends DialectWrapper {

    private List<FieldOp> fieldOps;

    private final Map<Object, FieldOp> cache = new ConcurrentHashMap<>();


    public FieldOpPool(List<FieldOp> fieldOps) {
        this.fieldOps = Objects.requireNonNull(fieldOps);
    }

    public FieldOpPool() {
        fieldOps = new ArrayList<>();
        fieldOps.add(new Equal());
        fieldOps.add(new NotEqual());
        fieldOps.add(new GreaterThan());
        fieldOps.add(new GreaterEqual());
        fieldOps.add(new LessThan());
        fieldOps.add(new LessEqual());
        fieldOps.add(new Between());
        fieldOps.add(new NotBetween());
        fieldOps.add(new Contain());
        fieldOps.add(new StartWith());
        fieldOps.add(new EndWith());
        fieldOps.add(new InList());
        fieldOps.add(new NotIn());
        fieldOps.add(new IsNull());
        fieldOps.add(new NotNull());
        fieldOps.add(new Empty());
        fieldOps.add(new NotEmpty());
    }


    public FieldOp getFieldOp(Object key) {
        if (key == null) {
            return null;
        }
        FieldOp fOp = cache.get(key);
        if (fOp == null && key instanceof FieldOp) {
            fOp = cache.get(((FieldOp) key).name());
        }
        if (fOp != null) {
            return fOp;
        }
        for (FieldOp op: fieldOps) {
            if (isMatch(op, key)) {
                if (key instanceof FieldOp) {
                    // 防止用户对同一个运算符 new 了很多次导致 cache 膨胀
                    cache.put(((FieldOp) key).name(), op);
                } else {
                    cache.put(key, op);
                }
                return op;
            }
        }
        return null;
    }

    private boolean isMatch(FieldOp op, Object key) {
        if (key instanceof FieldOp) {
            return op.sameTo((FieldOp) key);
        }
        if (key instanceof String) {
            return op.isNamed((String) key);
        }
        if (key instanceof Class) {
            return op.getClass() == key;
        }
        return false;
    }

    public List<FieldOp> getFieldOps() {
        return fieldOps;
    }

    public synchronized void setFieldOps(List<FieldOp> fieldOps) {
        this.fieldOps = fieldOps;
        updateAllOpDialect();
    }

    public synchronized void addFieldOp(FieldOp fieldOp) {
        this.fieldOps.add(fieldOp);
        updateOpDialect(fieldOp);
    }

    @Override
    public synchronized void setDialect(Dialect dialect) {
        super.setDialect(dialect);
        updateAllOpDialect();
    }

    private void updateAllOpDialect() {
        for (FieldOp op : fieldOps) {
            updateOpDialect(op);
        }
    }

    private void updateOpDialect(FieldOp op) {
        if (op instanceof DialectSensor) {
            ((DialectSensor) op).setDialect(getDialect());
        }
    }

}

@@ -2674,24 +2674,47 @@
 ldOps = 
+Objects.requireNonNull(
 fieldOps
 ;%0A      
@@ -2701,24 +2701,25 @@
 ull(fieldOps
+)
 ;%0A        up
@@ -2796,32 +2796,67 @@
 ldOp fieldOp) %7B%0A
+        if (fieldOp != null) %7B%0A    
         this.fie
@@ -2875,32 +2875,36 @@
 eldOp);%0A        
+  
+  
 updateOpDialect(
@@ -2909,24 +2909,34 @@
 t(fieldOp);%0A
+        %7D%0A
     %7D%0A%0A    @
@@ -2999,24 +2999,59 @@
  dialect) %7B%0A
+        if (dialect != null) %7B%0A    
         supe
@@ -3073,32 +3073,36 @@
 alect);%0A        
+  
+  
 updateAllOpDiale
@@ -3099,32 +3099,42 @@
 AllOpDialect();%0A
+        %7D%0A
     %7D%0A%0A    priva
@@ -3338,24 +3338,107 @@
 ctSensor) %7B%0A
+            Dialect dialect = getDialect();%0A            if (dialect != null) %7B%0A    
             
@@ -3473,22 +3473,31 @@
 ect(
-getD
+d
 ialect
-()
 );
+%0A            %7D
 %0A   

优化 FieldOpPool