package cn.ibizlab.core.data.dto;

import cn.ibizlab.core.data.domain.DOModel;
import cn.ibizlab.core.data.domain.DTOModel;
import cn.ibizlab.core.data.model.POSchema;
import cn.ibizlab.core.data.model.PojoSchema;
import cn.ibizlab.util.security.AuthenticationUser;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@JsonInclude(JsonInclude.Include.ALWAYS)
@JsonIgnoreProperties(ignoreUnknown = true)
public class BaseData extends DataObj
{

	public BaseData set(String key, Object value)
	{
		this.put(key,value);
		return this;
	}

	public Serializable getSerializableValue(String key)
	{
		Object obj=this.get(key);
		if(obj!=null)
			return (Serializable)obj;
		else
			return null;
	}

	public BaseData setAll(Map map)
	{
		if(map!=null)
			this.putAll(map);
		else if(this.size()==0)
			return null;
		return this;
	}



	@Override
	public Object put(Object key, Object value) {
		if(key instanceof String)
			return super.put(key.toString().toLowerCase(), value);
		return super.put(key, value);
	}



	@Override
	public BaseData remove(Object key) {
		super.remove(key);
		return this;
	}

	@JsonIgnore
	@JSONField(serialize = false)
	private POSchema _poschema;
	@JsonIgnore
	@JSONField(serialize = false)
	public POSchema getPOSchema()
	{
		return _poschema;
	}

	public BaseData setPOSchema(POSchema poSchema)
	{
		this._poschema=poSchema;
		return this;
	}


	@JsonIgnore
	@JSONField(serialize = false)
	private DOModel _domodel;
	@JsonIgnore
	@JSONField(serialize = false)
	public DOModel getDOModel()
	{
		return _domodel;
	}

	public BaseData setDOModel(DOModel doModel)
	{
		this._domodel=doModel;
		return this;
	}

	@JsonIgnore
	@JSONField(serialize = false)
	private DTOModel _dtomodel;
	@JsonIgnore
	@JSONField(serialize = false)
	public DTOModel getDTOModel()
	{
		return _dtomodel;
	}

	public BaseData setDTOModel(DTOModel dtoModel)
	{
		this._dtomodel=dtoModel;
		return this;
	}

	@JsonIgnore
	@JSONField(serialize = false)
	private PojoSchema _pojoschema;
	@JsonIgnore
	@JSONField(serialize = false)
	public PojoSchema getPojoSchema()
	{
		if(_pojoschema==null)
		{
			DOModel doModel=this.getDOModel();
			if(doModel!=null)
				_pojoschema=doModel.getSchema();
		}
		if(_pojoschema==null)
		{
			DTOModel dtoModel=this.getDTOModel();
			if(dtoModel!=null)
				_pojoschema=dtoModel.getSchema();
		}
		return _pojoschema;
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public BaseData getParams()
	{
		BaseData param=null;
		Object obj=this.get("params");
		if(obj!=null)
		{
			if(obj instanceof BaseData)
				param=(BaseData)obj;
			else if(obj instanceof Map)
			{
				param=new BaseData().setAll((Map)obj);
				this.set("params",param);
			}
		}
		else
		{
			return this;
		}
		return param;
	}

	public BaseData setParams(BaseData params)
	{
		return this.set("params",params);
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public BaseData getDatacontext() {
		return getParams();
	}


	@JsonIgnore
	@JSONField(serialize = false)
	public BaseData getWebcontext() {
		return getParams();
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public BaseData sessioncontext;
	@JsonIgnore
	@JSONField(serialize = false)
	public BaseData getSessioncontext() {
		if(sessioncontext==null)
			sessioncontext=new BaseData().setAll(AuthenticationUser.getAuthenticationUser().getSessionParams());
		return sessioncontext;
	}

	@Override
	public Object get(Object key) {
		if(key==null)
			return null;
		if(key.toString().equalsIgnoreCase("datacontext"))
			return getDatacontext();
		else if(key.toString().equalsIgnoreCase("webcontext"))
			return getWebcontext();
		else if(key.toString().equalsIgnoreCase("sessioncontext"))
			return getSessioncontext();
		else if(key instanceof String)
			return super.get(key.toString().toLowerCase());
		return super.get(key);
	}



	public BaseData setKey(Object key)
	{
		if(ObjectUtils.isEmpty(key))
			return this;
		return this.set("_id",key);
	}

	@JsonIgnore
	@JSONField(serialize = false)
	public Serializable getKey()
	{
		return getSerializableValue("_id");
	}


	@JsonIgnore
	@JSONField(serialize = false)
	private Map<String,BaseData> parentDatas;

	@JsonIgnore
	@JSONField(serialize = false)
	public Map<String,BaseData> getParentDatas()
	{
		return parentDatas;
	}

	public BaseData setParentDatas(Map<String,BaseData> parentDatas)
	{
		this.parentDatas=parentDatas;
		return this;
	}

	public BaseData addParentData(String entity,Map data)
	{
		if(StringUtils.isEmpty(entity)||ObjectUtils.isEmpty(data))
			return this;
		if(parentDatas==null)
			parentDatas=new LinkedHashMap<>();
		BaseData parent=null;
		if(parentDatas.containsKey(entity))
			parent=parentDatas.get(entity);
		else {
			parent = new BaseData();
			parentDatas.put(entity,parent);
		}
		parent.setAll(data);

		return this;
	}

	public BaseData addParent(String entity,String key)
	{
		if(StringUtils.isEmpty(entity)||StringUtils.isEmpty(key))
			return this;
		if(parentDatas==null)
			parentDatas=new LinkedHashMap<>();
		BaseData parent=null;
		if(parentDatas.containsKey(entity))
			parent=parentDatas.get(entity);
		else {
			parent = new BaseData();
			parentDatas.put(entity,parent);
		}
		parent.setKey(key);
		return this;
	}


	public static BaseData fromContext(Map map)
	{
		if(map==null)
			return null;
		map.remove("datasource");
		if(map.size()==0)
			return null;
		return new BaseData().setAll(map);
	}


	public Serializable getKeyBySchema(boolean genKeyWhenNotExists)
	{
		if(this.getPojoSchema()!=null)
			return this.getPojoSchema().getKeyValue(this, genKeyWhenNotExists);
		else if(this.getPOSchema()!=null)
			return this.getPOSchema().getKeyValue(this,genKeyWhenNotExists);
		return this.getKey();
	}

	public BaseData setKeyBySchema(Object keyValue)
	{
		if(this.getPojoSchema()!=null) {
			this.getPojoSchema().setKeyValue(this, keyValue);
			return this;
		}else if(this.getPOSchema()!=null){
			this.getPOSchema().setKeyValue(this, keyValue);
			return this;
		}
		return this.setKey(keyValue);
	}


	@JsonIgnore
	@JSONField(serialize = false)
	public BaseData fillParentKey()
	{
		if(this.getPojoSchema()!=null)
			this.getPojoSchema().fillParentKey(this);
		return this;
	}



	public BaseData fillDefaultValue(boolean newFlag)
	{
		if(this.getPojoSchema()!=null)
			this.getPojoSchema().fillDefaultValue(this,newFlag);
		return this;
	}
}
