package com.brilliance.mda.runtime.mda.impl;

import com.brilliance.mda.runtime.annotation.Module;
import com.brilliance.mda.runtime.mda.IBaseObject;
import com.brilliance.mda.runtime.mda.IDatafield;
import com.brilliance.mda.runtime.mda.IModule;
import com.brilliance.mda.runtime.mda.IModuleRoot;
import com.brilliance.mda.runtime.mda.driver.MdaDriver;
import com.brilliance.mda.runtime.mda.util.MdaUtils;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

@JsonFilter("fieldFilter")
@Module
public abstract class AbstractModule implements IModule, IModuleRoot {

    protected Logger logger = LoggerFactory.getLogger(this.getClass().getName());

    private String _path;

    private String _name;

    private IModule _parent;

    private boolean _entityflg;

    private String serialNum;

    private Map<String, Object> attrMaps = new HashMap<>();

    public AbstractModule() {
    }

    public AbstractModule(String name, IModule parent) {
        this._name = name;
        this._parent = parent;
        String prefix = parent.getPath();
        if (prefix == null || prefix.length() == 0)
            this._path = this._name;
        else
            this._path = prefix + "." + this._name;
        this._entityflg = false;
    }

    public AbstractModule(String name, IModule parent, boolean isEntity) {
        this(name, parent);
        this._entityflg = true;
    }

    public String getFieldPath(String fieldName) {
        try {
            IBaseObject baseObj = MdaDriver.getBaseObject(this, fieldName);
            if (baseObj == null)
                return "";
            return baseObj.getPath();
//			Field field = this.getClass().getDeclaredField(fieldName);
//			if(field.getType() == DatafieldImpl.class) //是引用模式的
//			{
//				return ((DatafieldImpl)field.get(this)).getPath();
//			}
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
//		if(null==this._path || this._path.length() ==0 )
//			return fieldName;
//		return this._path +"."+ fieldName;
    }

    @JsonIgnore
    public String getPath() {
        if (this._parent != null && this._parent instanceof ModuleList) {
            int idx = ((ModuleList) this._parent).indexOf(this);
            String path = this._parent.getPath() + "(" + (idx + 1) + ")";
            return path;
        }

        String _name = this._name;
        if (_name == null) {
            return separator;
        }

        IModule _this = this._parent;
        StringBuilder sb = new StringBuilder(_name);
        while (!(_this.getParent() instanceof ModuleList) && _this.getParent() != null) {
            sb.insert(0, _this.getName() + separator);
            _this = _this.getParent();
        }
        if (_this.getParent() == null) {
            return this._path == null ? separator : this._path.toUpperCase();
        } else {
            return _this.getPath() + separator + sb.toString().toUpperCase();
        }
    }

    @JsonIgnore
    public String getName() {
        return _name;
    }

    @JsonIgnore
    public IModule getParent() {
        return _parent;
    }

    @JsonIgnore
    public boolean isEntity() {
        return this._entityflg;
    }

    @Override
    public String getSerialNum() {
        return serialNum;
    }

    public void setSerialNum(String serialNum) {
        this.serialNum = serialNum;
    }

    @Override
    public void copyValue(IModule src) {
        MdaDriver.copyValues(this, src);
    }

    @Override
    public void copyValues(IModule src) {
        MdaDriver.copyValues(this, src);
    }

    public void clear() {
        MdaDriver.clearModule(this);
    }

    /**
     * 废弃的方法，不要再使用了
     *
     * @return
     */
    @Deprecated
    @Override
    @JsonIgnore
    public Collection<IDatafield> getDatafields() {
        List<IDatafield> list = new ArrayList<>();
        Field[] fs = this.getClass().getDeclaredFields();
        for (int i = 0; i < fs.length; i++) {
            Field field = fs[i];
            if (field.getName().charAt(0) == '_') {
                continue;
            }
            if (field.getType() == DatafieldImpl.class) {
                try {
                    list.add((IDatafield) field.get(this));
                } catch (IllegalAccessException e) {
                    logger.warn("get field exception", e);
                }
            }
            list.add(new DatafieldImpl(this._parent, field));
        }
        return new ArrayList<>();
    }

    /**
     * 基于反射实现，尽量不用
     *
     * @return 当前模型下所有的子模型，包括ModuleList
     */
    @JsonIgnore
    public List<IModule> getModules() {
        Class clazz = this.getClass();
        ArrayList<IModule> moduleList = new ArrayList<>();
        try {
            for (Field field : clazz.getDeclaredFields()) {
                String name = field.getName(); //获取
                String getterName = "get" + MdaDriver.firstUpper(name);
                try {
                    Method m = clazz.getMethod(getterName);
                    if (IModule.class.isAssignableFrom(m.getReturnType())) {
                        moduleList.add((IModule) m.invoke(this));
                    }
                } catch (Exception e) {

                }

            }
        } catch (Exception e) {

        }
        return moduleList;
    }

    /**
     * todo
     *
     * @param key
     * @return
     */
    public IBaseObject get(String key) {
        return null;
    }

    @Override
    public void assignSerialNum() {
        if (StringUtils.isEmpty(this.serialNum)) {
            this.setSerialNum(MdaUtils.generateSerialNum());
        }
    }

    @Override
    public Map<String, Object> getAttrMaps() {
        return attrMaps;
    }

    public void setAttrMaps(Map<String, Object> attrMaps) {
        this.attrMaps = attrMaps;
    }


}
