package com.wx.application.nebula.graph.base;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import com.vesoft.nebula.client.graph.data.ResultSet;
import com.vesoft.nebula.client.graph.net.Session;
import com.wx.application.nebula.graph.bean.NebulaEdge;
import com.wx.application.nebula.graph.bean.NebulaEdgeLine;
import com.wx.application.nebula.graph.bean.NebulaField;
import com.wx.application.nebula.graph.bean.NebulaIndex;
import com.wx.application.nebula.graph.bean.NebulaSpace;
import com.wx.application.nebula.graph.bean.NebulaTag;
import com.wx.application.nebula.graph.bean.NebulaVertex;
import com.wx.application.nebula.graph.enums.DataType;
import com.wx.application.nebula.graph.factory.NebulaGraphClient;
import com.wx.application.nebula.graph.query.NebulaModel;
import com.wx.application.nebula.graph.query.NebulaNode;
import com.wx.application.nebula.graph.query.NebulaRelation;
import com.wx.application.nebula.graph.query.PageRequest;
import com.wx.application.nebula.graph.query.TermQueryBuilder;
import com.wx.application.util.JSONUtils;
import com.wx.application.util.UUIDGenerator;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import lombok.extern.slf4j.Slf4j;

/**
 * 动态语句库
 */
@Slf4j
public class BaseGraphSerice {
	
	/*@Autowired
	Session session;*/
	
	@Value("${nebula.grap}")
	private Boolean logGraph;
	
	@Autowired
	NebulaGraphClient client;
	
	public ResultSet executeGql(String space, String nGql) {
		String us = "";
		if(StringUtils.isNotBlank(space)) {
			us = useSpace(space);
		}
		
		Session session = null;
		ResultSet resultSet = null;
		try {
			if(logGraph) {
				log.info(nGql);
			}
			session= client.getSession();
			resultSet = session.execute(us + nGql);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			client.returnSession(session);
		}
		
		return resultSet;
	}
	
	
	
	/**
	 * 查看所有的图空间
	 */
	public List<JSONObject> showSpace() {
		ResultSet resultSet = executeGql(null, GqlTemplate.SHOWSPACES);
		return ResultSetUtils.printResultObject(resultSet);
	}
	
	
	/**
	 * 在当前图空间内启动一个作业，该作业对当前图空间进行统计
	 * @param space
	 * @return
	 */
	public Integer submitJobStats(final String space) {
		final String nGql = StrUtil.format(GqlTemplate.SUBMITJOBSTATS);
		ResultSet resultSet = executeGql(space, nGql);
		List<JSONObject> rt = ResultSetUtils.printResultObject(resultSet);
		if(rt != null && rt.size() > 0) {
			return rt.get(0).getInt("New Job Id");
		}
		return null;
	}
	
	/**
	 * 在当前图空间内启动一个作业，该作业对当前图空间进行统计
	 * @param space
	 * @return
	 */
	public List<JSONObject> showStats(final String space) {
		final String nGql = StrUtil.format(GqlTemplate.SHOWSTATS);
		ResultSet resultSet = executeGql(space, nGql);
		return ResultSetUtils.printResultObject(resultSet, 3);
	}
	
	
	public void stopJob(final String space, Integer jobId) {
		final String nGql = StrUtil.format(GqlTemplate.STOPJOB, jobId);
		executeGql(space, nGql);
	}
	
	/**
	 * 空间创建语句
	 * @param space
	 * @return
	 */
	public void createSpace(NebulaSpace e) {
		final String nGql = StrUtil.format(GqlTemplate.CREATESPACE, 
				e.getName(), e.getVidType().name(), e.getVidLen(), e.getComment());
		executeGql(null, nGql);
	}
	
	/**
	 * 使用莫个图空间
	 * @param e
	 * @return
	 */
	public String useSpace(String e) {
		return StrUtil.format(GqlTemplate.USESPACE, e);
	}
	
	
	/**
	 * 删除莫个图空间
	 * @param e
	 * @return
	 */
	public void dropSpace(String e) {
		final String nGql = StrUtil.format(GqlTemplate.DROPSPACE, e);
		executeGql(null, nGql);
	}
	
	/**
	 * 显示莫个图空间的详细信息
	 * @param e
	 * @return
	 */
	public JSONObject descSpace(String e) {
		final String nGql = StrUtil.format(GqlTemplate.DESCSPACE, e);
		ResultSet resultSet = executeGql(null,nGql);
		return ResultSetUtils.printResultObject(resultSet,8).get(0);
	}
	
	
	/**
	 * 标签创建语句
	 * @param space
	 * @return
	 */
	public void createTag(final String space, NebulaTag e) {
		final String tag = e.getName();
		final String fields = FieldsUtils.toStringFields(e.getFields());
		final String comment = e.getComment();
		final String nGql = StrUtil.format(GqlTemplate.CREATETAG, tag, fields, comment);
		executeGql(space, nGql);
	}
	
	
	/**
	 * 标签添加字段语句
	 * @param space
	 * @return
	 */
	public void alterAddTag(final String space, NebulaTag e) {
		final String tag = e.getName();
		final String fields = FieldsUtils.toStringFields(e.getFields());
		final String nGql = StrUtil.format(GqlTemplate.ALTERADDTAG, tag, fields);
		executeGql(space, nGql);
	}
	
	
	/**
	 * 标签删除字段语句
	 * @param space
	 * @return
	 */
	public void alterDropTag(final String space, NebulaTag e) {
		final String tag = e.getName();
		final String fields = FieldsUtils.toStringFieldNames(e.getFields());
		final String nGql = StrUtil.format(GqlTemplate.ALTERDROPTAG, tag, fields);
		executeGql(space, nGql);
	}
	
	/**
	 * 标签修改字段语句
	 * @param space
	 * @return
	 */
	public void alterChangeTag(final String space, NebulaTag e) {
		final String tag = e.getName();
		final String fields = FieldsUtils.toStringFields(e.getFields());
		final String nGql = StrUtil.format(GqlTemplate.ALTERCHANGETAG, tag, fields);
		executeGql(space, nGql);
	}
	
	/**
	 * 标签删除
	 * @param e
	 * @return
	 */
	public void dropTag(final String space, String e) {
		final String nGql = StrUtil.format(GqlTemplate.DROPTAG, e);
		executeGql(space, nGql);
	}
	
	
	/**
	 * 查看所有标签
	 * @param e
	 * @return
	 */
	public List<JSONObject> showTag(final String space, Boolean fushComment) {
		
		final String nGql = StrUtil.format(GqlTemplate.SHOWTAGS);
		ResultSet resultSet = executeGql(space, nGql);
		List<JSONObject> rs = ResultSetUtils.printResultObject(resultSet);
		
		if(!fushComment) {
			return rs;
		}
		
		int tn = 20;
		List<List<JSONObject>> lists = ListUtil.split(rs, (rs.size() / tn) + 1);
		ExecutorService executor = Executors.newFixedThreadPool(tn);
		
		for(List<JSONObject> fn : lists) {
        	executor.submit(new Runnable() {
                @Override
                public void run() {
                	fn.forEach(v->{
            			JSONObject a = showCreateTag(space, v.getStr("Name"));
            			String content = a.getStr("create tag");
            			List<String> resultFindAll = ReUtil.findAll("(comment = \")(.+)(\")", 
            					content, 2, new ArrayList<String>());
            			
            			if(resultFindAll == null || resultFindAll.size() == 0){
            				return;
            			}
            			v.set("comment", StringUtils.join(resultFindAll,","));
            		});
                }
    		});
        }
        
        executor.shutdown();
        try {
			if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
			    
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
        return rs;
	}
	
	/**
	 * 标签查看详细信息
	 * @param e
	 * @return
	 */
	public List<JSONObject> descTag(final String space, String e) {
		final String nGql = StrUtil.format(GqlTemplate.DESCRIBETAG, e);
		ResultSet resultSet = executeGql(space, nGql);
		/**
		 * 变量处理结果集
		 */
		return ResultSetUtils.printResultObject(resultSet, 5);
	}
	
	/**
	 * 标签查看详细信息
	 * @param e
	 * @return
	 */
	public JSONObject showCreateTag(final String space, String e) {
		
		final String nGql = StrUtil.format(GqlTemplate.SHOWCREATETAG, e);
		ResultSet resultSet = executeGql(space, nGql);
		/**
		 * 变量处理结果集
		 */
		List<JSONObject> rs = ResultSetUtils.printResultObject(resultSet, 2);
		JSONObject a = rs.get(0);
		
		String content = a.getStr("create tag");
		List<String> resultFindAll = ReUtil.findAll("(comment = \")(.+)(\")", 
				content, 2, new ArrayList<String>());
		
		if(resultFindAll != null && resultFindAll.size() > 0){
			a.set("comment", StringUtils.join(resultFindAll,","));
		}
		
		return a;
	}
	
	/**
	 * 边创建语句
	 * @param space
	 * @return
	 */
	public void createEdge(final String space, NebulaEdge e) {
		final String LABEL = "label";
		final String edge = e.getName();
		/**
		 * 创建edge时 默认补充 一个label标签 显示关系上的名称
		 */
		List<NebulaField> fieldLists = e.getFields();
		if(fieldLists == null) {
			fieldLists = new ArrayList<>();
		}
		List<String> fns = fieldLists.stream().map(NebulaField::getField).collect(Collectors.toList());
		if(!fns.contains(LABEL)) {
			NebulaField field = new NebulaField();
			field.setField(LABEL);
			field.setComment("标签");
			field.setType(DataType.STRING);
			fieldLists.add(field);
		}
		final String fields = FieldsUtils.toStringFields(fieldLists);
		final String comment = e.getComment();
		final String nGql = StrUtil.format(GqlTemplate.CREATEEDGE, edge, fields, comment);
		executeGql(space, nGql);
	}
	
	
	/**
	 * 边添加字段语句
	 * @param space
	 * @return
	 */
	public void alterAddEdge(final String space, NebulaEdge e) {
		final String edge = e.getName();
		final String fields = FieldsUtils.toStringFields(e.getFields());
		final String nGql = StrUtil.format(GqlTemplate.ALTERADDEDGE, edge, fields);
		executeGql(space, nGql);
	}
	
	
	/**
	 * 边删除字段语句
	 * @param space
	 * @return
	 */
	public void alterDropEdge(final String space, NebulaEdge e) {
		final String edge = e.getName();
		final String fields = FieldsUtils.toStringFieldNames(e.getFields());
		final String nGql = StrUtil.format(GqlTemplate.ALTERDROPEDGE, edge, fields);
		executeGql(space, nGql);
	}
	
	/**
	 * 边修改字段语句
	 * @param space
	 * @return
	 */
	public void alterChangeEdge(final String space, NebulaEdge e) {
		final String edge = e.getName();
		final String fields = FieldsUtils.toStringFields(e.getFields());
		final String nGql = StrUtil.format(GqlTemplate.ALTERCHANGEEDGE, edge, fields);
		executeGql(space, nGql);
	}
	
	/**
	 * 边删除
	 * @param e
	 * @return
	 */
	public void dropEdge(final String space, String e) {
		final String nGql = StrUtil.format(GqlTemplate.DROPEDGE, e);
		executeGql(space, nGql);
	}
	
	
	/**
	 * 查看所有边
	 * @param e
	 * @return
	 */
	public List<JSONObject> showEdge(final String space, Boolean fushComment) {
		
		final String nGql = StrUtil.format(GqlTemplate.SHOWEDGES);
		ResultSet resultSet = executeGql(space, nGql);
		List<JSONObject> rs = ResultSetUtils.printResultObject(resultSet);
		
		if(!fushComment) {
			return rs;
		}
		
		int tn = 20;
		
		List<List<JSONObject>> lists = ListUtil.split(rs, (rs.size() / tn) + 1);
		ExecutorService executor = Executors.newFixedThreadPool(tn);
		
		for(List<JSONObject> fn : lists) {
        	executor.submit(new Runnable() {
                @Override
                public void run() {
                	fn.forEach(v->{
                		JSONObject a = showCreateEdge(space, v.getStr("Name"));
            			String content = a.getStr("create edge");
            			List<String> resultFindAll = ReUtil.findAll("(comment = \")(.+)(\")", 
            					content, 2, new ArrayList<String>());
            			
            			if(resultFindAll == null || resultFindAll.size() == 0){
            				return;
            			}
            			v.set("comment", StringUtils.join(resultFindAll,","));
            		});
                }
    		});
        }
        
        executor.shutdown();
        try {
			if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
			    
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		return rs;
	}
	
	
	/**
	 * 标签查看详细信息
	 * @param e
	 * @return
	 */
	public JSONObject showCreateEdge(final String space, String e) {
		final String nGql = StrUtil.format(GqlTemplate.SHOWCREATEEDGE, e);
		ResultSet resultSet = executeGql(space, nGql);
		/**
		 * 变量处理结果集
		 */
		List<JSONObject> rs = ResultSetUtils.printResultObject(resultSet, 2);
		JSONObject a = rs.get(0);
		
		String content = a.getStr("create edge");
		List<String> resultFindAll = ReUtil.findAll("(comment = \")(.+)(\")", 
				content, 2, new ArrayList<String>());
		
		if(resultFindAll != null && resultFindAll.size() > 0){
			a.set("comment", StringUtils.join(resultFindAll,","));
		}
		
		return a;
	}
	
	/**
	 * 边查看详细信息
	 * @param e
	 * @return
	 */
	public List<JSONObject> descEdge(final String space, String e) {
		final String nGql = StrUtil.format(GqlTemplate.DESCRIBEEDGE, e);
		ResultSet resultSet = executeGql(space, nGql);
		/**
		 * 变量处理结果集
		 */
		return ResultSetUtils.printResultObject(resultSet,5);
	}
	
	/**
	 * 索引创建语句
	 * @param e
	 * @return
	 */
	public void createIndex(final String space, NebulaIndex e) {
		final String type = e.getType().name();
		final String name = e.getName();
		final String onname = e.getOnName();
		final String fields = FieldsUtils.toIndexFields(e.getFields());
		final String comment = e.getComment();
		final String nGql = StrUtil.format(GqlTemplate.CREATEINDEX, type, name, onname, fields, comment);
		executeGql(space, nGql);
	}
	
	/**
	 * 查看边或者标签的索引
	 * @param e
	 * @return
	 */
	public List<JSONObject> showIndex(final String space, String e) {
		final String nGql = StrUtil.format(GqlTemplate.SHOWINDEX, e);
		ResultSet resultSet = executeGql(space, nGql);
		return ResultSetUtils.printResultObject(resultSet);
	}
	
	/**
	 * 删除边或者标签的索引
	 * @param e
	 * @return
	 */
	public void dropIndex(final String space, NebulaIndex e) {
		final String type = e.getType().name();
		final String name = e.getName();
		final String nGql = StrUtil.format(GqlTemplate.DROPINDEX, type, name);
		executeGql(space, nGql);
	}
	
	
	/**
	 * 删除点语句
	 */
	public void deleteVertex(final String space, String vid) {
		if(StringUtils.isBlank(vid)) {
			return;
		}
		final String nGql = StrUtil.format(GqlTemplate.DELETEVERTEX, vid);
		executeGql(space, nGql);
	}
	
	/**
	 * 删除点语句
	 */
	public void deleteVertexs(final String space, final String tag, List<String> vids) {
		Set<String> stIds = new HashSet<>();
		vids.forEach(v->{
			if(StringUtils.isBlank(v)) {
				return;
			}
			final String fmtVid = StrUtil.format("\"{}\"", v);
			stIds.add(fmtVid);
		});
		
		if(stIds.size() > 0) {
			final String nGql = StrUtil.format(GqlTemplate.DELETEVERTEXBYVIDS, tag, StringUtils.join(stIds, ","));
			executeGql(space, nGql);
		}
	}
	
	/**
	 * 根据条件删除点
	 */
	public List<NebulaNode> deleteVertexConduit(final String space,
			final String tag, 
			TermQueryBuilder builder) {
		String nGql = GqlTemplate.DELETEVERTEXCONDUIT;
		String query = null;
		if(builder != null && StringUtils.isNotBlank(query = builder.of(tag))) {
			nGql = nGql.replaceFirst("YIELD", " {} YIELD");
			nGql = StrUtil.format(nGql, tag, query);
		}
		
		ResultSet resultSet = executeGql(space, nGql);
    	return ResultSetUtils.printResultVertex(resultSet);
	}
	
	/**
	 * 添加点语句
	 */
	public void insertVertex(final String space,final String tag, NebulaVertex e) {
		
		String vid = StringUtils.isBlank(e.getVid())?UUIDGenerator.getUUID():e.getVid();
		e.setVid(vid);
		final String fmtVid =  StrUtil.format("\"{}\"", vid);
		
		JSONObject ob = e.getOb();
		List<String> columns = new ArrayList<>();
		List<String> values = new ArrayList<>();
		for(String key : ob.keySet()) {
			columns.add(key);
			Object value = ob.get(key);
			if(value == null) {
				values.add(null);
			}
			if(value instanceof String) {
				values.add(JSONUtils.c(ob.getStr(key)));
			} else {
				values.add(StrUtil.format("{}", ob.get(key)));
			}
		}
		
		final String ifeilds = StringUtils.join(columns, ",");
		final String strval = StringUtils.join(values, ",");
		final String strInsert =  StrUtil.format("{}:({})", fmtVid, strval);
		
		final String nGql = StrUtil.format(GqlTemplate.INSERTVERTEX, tag, ifeilds, strInsert);
		executeGql(space, nGql);
	}
	
	
	
	/**
	 * 边数据删除语句
	 * @param space
	 * @return
	 */
	public void deleteEdgeLine(final String space, final String edge, NebulaEdgeLine e) {
		if(StringUtils.isBlank(e.getSrcId())
				|| StringUtils.isBlank(e.getDstId())) {
			return;
		}
		final String srcId = StrUtil.format("\"{}\"", e.getSrcId());
		final String dstId = StrUtil.format("\"{}\"", e.getDstId());
		final String nGql = StrUtil.format(GqlTemplate.DELETEEDGEDATA, edge, srcId, dstId);
		executeGql(space, nGql);
	}
	
	/**
	 * 插入边数据
	 * @param e
	 * @return
	 */
	public void insertEdgeLine(final String space, final String edge, NebulaEdgeLine e) {
		
		if(StringUtils.isBlank(e.getSrcId())
				|| StringUtils.isBlank(e.getDstId())) {
			return;
		}
		
		final String srcId = StrUtil.format("\"{}\"", e.getSrcId());
		final String dstId = StrUtil.format("\"{}\"", e.getDstId());
		
		JSONObject ob = e.getOb();
		List<String> columns = new ArrayList<>();
		List<String> values = new ArrayList<>();
		
		if(ob != null) {
			for(String key : ob.keySet()) {
				columns.add(key);
				Object value = ob.get(key);
				if(value == null) {
					values.add(null);
				}
				if(value instanceof String) {
					values.add(JSONUtils.c(ob.getStr(key)));
				} else {
					values.add(StrUtil.format("{}", ob.get(key)));
				}
			}
		}
		
		Integer edgeNo = e.getEdgeNo();
		edgeNo = edgeNo == null?0:edgeNo;
		final String ifeilds = StringUtils.join(columns, ",");
		final String strval = StringUtils.join(values, ",");
		final String strInsert =  StrUtil.format("{}->{} @{}:({})", srcId, dstId, edgeNo, strval);
		
		final String nGql = StrUtil.format(GqlTemplate.INSERTDGEDATA, edge, ifeilds, strInsert);
		executeGql(space, nGql);
	}
	
	
	/**
	 * 根据id查找节点
	 */
	public NebulaNode findNodeById(final String space,final String vid) {
		final String fmtVid = StrUtil.format("\"{}\"", vid);
		final String nGql = StrUtil.format(GqlTemplate.NODESBYVID, fmtVid);
		ResultSet resultSet = executeGql(space, nGql);
		List<NebulaNode> records = ResultSetUtils.printResultVertex(resultSet);
		return records.get(0);
	}
	
	/**
	 * 根据id查找节点
	 */
	public NebulaNode findNodeById(final String space,final String tag,final String vid) {
		final String fmtVid = StrUtil.format("\"{}\"", vid);
		final String nGql = StrUtil.format(GqlTemplate.NODESBYVIDS, tag, fmtVid);
		ResultSet resultSet = executeGql(space, nGql);
		List<NebulaNode> records = ResultSetUtils.printResultVertex(resultSet);
		if(records.size() > 0) {
			return records.get(0);
		}
		return null;
	}
	
	/**
	 * 根据ids查找节点
	 */
	public List<NebulaNode> findNodeByIds(final String space,final String tag,final List<String> vids) {
		Set<String> stIds = new HashSet<>();
		vids.forEach(v->{
			final String fmtVid = StrUtil.format("\"{}\"", v);
			stIds.add(fmtVid);
		});
		final String nGql = StrUtil.format(GqlTemplate.NODESBYVIDS, tag, StringUtils.join(stIds, ","));
		ResultSet resultSet = executeGql(space, nGql);
		return ResultSetUtils.printResultVertex(resultSet);
	}
	
	
	/**
	 * 根据id查找关系
	 */
	public NebulaRelation findRelationById(final String space,final String edge,
			final String srcVid,final String dstVid) {
		final String fmt = StrUtil.format("\"{}\" -> \"{}\"", srcVid, dstVid);
		final String nGql = StrUtil.format(GqlTemplate.RELATIONSBYVIDS, edge, fmt);
		ResultSet resultSet = executeGql(space, nGql);
		List<NebulaRelation> records = ResultSetUtils.printResultRelation(resultSet);
		return records.get(0);
	}
	
	
	/**
	 * 查询一个节点的周边一层节点关系
	 * @param nQ
	 * @return
	 */
	public NebulaModel findOnePathById(final String space,final String vid) {
		final String fmtVid = StrUtil.format("\"{}\"", vid);
		final String nGql = StrUtil.format(GqlTemplate.ONERELATIONBYID, fmtVid);
		ResultSet resultSet = executeGql(space, nGql);
		return ResultSetUtils.printResultPath(resultSet);
	}
	
	
	/**
	 * 查询一个头节点和尾结点的关系
	 * @param nQ
	 * @return
	 */
	public NebulaModel findOnePathBySrcIdAndDctId(final String space,final String srcId,final String dctId) {
		final String fmtSrcId = StrUtil.format("\"{}\"", srcId);
		final String fmtDctId = StrUtil.format("\"{}\"", dctId);
		final String nGql = StrUtil.format(GqlTemplate.ONERELATIONBYSRCIDANDDCTID, fmtSrcId, fmtDctId);
		ResultSet resultSet = executeGql(space, nGql);
		return ResultSetUtils.printResultPath(resultSet);
	}
	
	/**
	 * 三元组查询
	 */
	public List<NebulaRelation> findRelations(final String space,
			final String edge) {
		return findRelations(space, edge, null, null);
	}
	
	public List<NebulaRelation> findRelations(final String space,
			final String edge, 
			TermQueryBuilder builder) {
		return findRelations(space, edge, builder, null);
	}
	
	public List<NebulaRelation> findRelations(final String space,
			final String edge, 
			TermQueryBuilder builder,PageRequest pageRequest) {
		String nGql = GqlTemplate.LOOKUPEDGESNGQL;
		nGql = StrUtil.format(nGql, edge);
		String query = null;
		if(builder != null && StringUtils.isNotBlank(query = builder.of(edge))) {
			nGql = nGql.replaceFirst("YIELD", " {} YIELD");
			nGql = StrUtil.format(nGql, query);
		}
		if(pageRequest != null) {
			nGql = nGql + GqlTemplate.PAGING;
			nGql = StrUtil.format(nGql, pageRequest.skip(), pageRequest.getPageSize());
		}
		ResultSet resultSet = executeGql(space, nGql);
    	return ResultSetUtils.printResultRelation(resultSet);
	}
	
	
	/**
	 * 已知tag 查询节点集合
	 * 节点查询
	 */
	public List<NebulaNode> findNodes(final String space,
			final String tag) {
		return findNodes(space, tag, null, null);
	}
	
	public List<NebulaNode> findNodes(final String space,
			final String tag, 
			TermQueryBuilder builder) {
		return findNodes(space, tag, builder, null);
	}
	
	public List<NebulaNode> findNodes(final String space,
			final String tag, 
			TermQueryBuilder builder,PageRequest pageRequest) {
		String nGql = GqlTemplate.LOOKUPVERTEXSNGQL;
		nGql = StrUtil.format(nGql, tag);
		String query = null;
		if(builder != null && StringUtils.isNotBlank(query = builder.of(tag))) {
			nGql = nGql.replaceFirst("YIELD", " {} YIELD");
			nGql = StrUtil.format(nGql, query);
		}
		if(pageRequest != null) {
			nGql = nGql + GqlTemplate.PAGING;
			nGql = StrUtil.format(nGql, pageRequest.skip(), pageRequest.getPageSize());
		}
		ResultSet resultSet = executeGql(space, nGql);
    	return ResultSetUtils.printResultVertex(resultSet);
	}

	/**
	 * 未知tag查询节点集合，不能加入条件查询
	 * @param space
	 * @param builder
	 * @param pageRequest
	 * @return
	 */
	public List<NebulaNode> findNodes(final String space,PageRequest pageRequest) {
		String nGql = GqlTemplate.MATCHVERTEXSNGQL;
		if(pageRequest != null) {
			nGql = StrUtil.format(nGql, pageRequest.skip(), pageRequest.getPageSize());
		}
		ResultSet resultSet = executeGql(space, nGql);
    	return ResultSetUtils.printResultVertex(resultSet);
	}
	
	
	/**
	 * StartsWith 的模糊查询
	 * @param space
	 * @param tag
	 * @param builder
	 * @param pageRequest
	 */
	public List<NebulaNode> findNodesByWhere(final String space,
			final String tag, 
			TermQueryBuilder builder,PageRequest pageRequest) {
		final String qz = "v.";
		String nGql = GqlTemplate.MATCHVERTEXBYWHERESNGQL;
		nGql = StrUtil.format(nGql, tag);
		String query = null;
		if(builder != null && StringUtils.isNotBlank(query = builder.of(qz + tag))) {
			nGql = StrUtil.format(nGql, query);
		}
		if(pageRequest != null) {
			nGql = StrUtil.format(nGql, pageRequest.skip(), pageRequest.getPageSize());
		}
		ResultSet resultSet = executeGql(space, nGql);
    	return ResultSetUtils.printResultVertex(resultSet);
	}
	
	
	/**
	 * 批量插入
	 * @param space
	 * @return
	 */
	public void insertTagAll(String space, String tag, List<NebulaVertex> tes) {
		/**
		 * 获得tag的所有字段
		 */
		List<JSONObject> jts = descTag(space, tag);
		
		List<String> columns = new ArrayList<>();
		List<String> comments = new ArrayList<>();
		
		for(JSONObject jt : jts) {
			columns.add(jt.getStr("field"));
			comments.add(jt.getStr("comment"));
		}
		insertTagAll(space, tag, columns, comments, tes);
	}
	
	public void insertTagAll(String space, 
			String tag, List<String> columns, List<String> comments, List<NebulaVertex> tes) {
		
		List<String> allValues = new ArrayList<>();
		
		tes.stream().forEach(vtx->{
		
			try {
				
				JSONObject ob = vtx.getOb();
				
				if(ob == null && StringUtils.isBlank(vtx.getVid())) {
					return;
				}
				
				String vid = StringUtils.isBlank(vtx.getVid()) ? UUIDGenerator.getUUID() : vtx.getVid();
				final String fmtVid =  StrUtil.format("\"{}\"", vid);
				
				List<String> values = new ArrayList<>();
				
				int i = 0;
				for(String key : columns) {
					
					try {
						Object value = null;
						
						if(comments != null && comments.size() == columns.size()) {
							value = (ob.get(key)==null ? ob.get(comments.get(i)) : ob.get(key));
						} else {
							value = ob.get(key);
						}
						
						if(value == null) {
							values.add("null");
							continue;
						}
						
						if(value instanceof String) {
							values.add(JSONUtils.c(value));
						} else {
							values.add(StrUtil.format("{}", value));
						}
						
					} catch (Exception e) {
						log.info("{}", e);
					} finally {
						i++;
					}
					
				}
				
				final String strval = StringUtils.join(values, ",");
				final String fmtstrval = StrUtil.format("{}:({})", fmtVid, strval);
				allValues.add(fmtstrval);
				
			} catch (Exception e) {
				log.info("{}",e);
			}
		});
		
		final String ifeilds = StringUtils.join(columns, ",");
		final String strInsert = StringUtils.join(allValues, ",");
		
		final String nGql = StrUtil.format(GqlTemplate.INSERTVERTEX, tag, ifeilds, strInsert);
		executeGql(space, nGql);
	}
	
	
	/**
	 * 边的批量插入
	 * @param space
	 * @param edge
	 * @param tes
	 */
	public void insertEdgeLineAll(String space, String edge, List<NebulaEdgeLine> tes) {
		
		List<JSONObject> jts = descEdge(space, edge);
		List<String> columns = new ArrayList<>();
		List<String> comments = new ArrayList<>();
		for(JSONObject jt : jts) {
			columns.add(jt.getStr("field"));
			comments.add(jt.getStr("comment"));
		}
		insertEdgeLineAll(space, edge, columns, comments, tes);
	}
	
	public void insertEdgeLineAll(final String space, final String edge, 
			List<String> columns, List<String> comments, List<NebulaEdgeLine> tes) {
		
		List<String> allValues = new ArrayList<>();
		
		tes.stream().forEach(e->{
			try {
				final String srcId = StrUtil.format("\"{}\"", e.getSrcId());
				final String dstId = StrUtil.format("\"{}\"", e.getDstId());
				JSONObject ob = e.getOb();
				List<String> values = new ArrayList<>();
				
				if(ob != null) {
					
					int i = 0;
					
					for(String key : columns) {
						try {
							Object value = null;
							
							if(comments != null && comments.size() == columns.size()) {
								value = (ob.get(key)==null ? ob.get(comments.get(i)) : ob.get(key));
							} else {
								value = ob.get(key);
							}
							if(value == null) {
								values.add("null");
								continue;
							}
							if(value instanceof String) {
								values.add(JSONUtils.c(value));
							} else {
								values.add(StrUtil.format("{}", value));
							}
						} catch (Exception e1) {
							log.info("{}", e1);
						} finally {
							i++;
						}
					}
				}
				
				final String strval = StringUtils.join(values, ",");
				final String strInsert =  StrUtil.format("{}->{}:({})", srcId, dstId, strval);
				
				allValues.add(strInsert);
			} catch (Exception e1) {
				log.info("{}",e1);
			}
		});
		
		
		final String ifeilds = StringUtils.join(columns, ",");
		final String strInsert = StringUtils.join(allValues, ",");
		
		final String nGql = StrUtil.format(GqlTemplate.INSERTDGEDATA, edge, ifeilds, strInsert);
		executeGql(space, nGql);
	}
	
	
	/**
	 * 根据条件统计点
	 */
	public Long countVertexs(final String space,
			final String tag, 
			TermQueryBuilder builder) {
		String nGql = GqlTemplate.COUNTVERTEXS;
		String query = null;
		if(builder != null && StringUtils.isNotBlank(query = builder.of(tag))) {
			nGql = nGql.replaceFirst("YIELD", " {} YIELD");
			nGql = StrUtil.format(nGql, tag, query);
		}
		ResultSet resultSet = executeGql(space, nGql);
		List<JSONObject> rs = ResultSetUtils.printResultObject(resultSet);
		if(rs != null && rs.size() > 0) {
			return rs.get(0).getLong("ct");
		}
		return 0L;
	}
	
	/**
	 * 根据条件统计三元组数量
	 */
	public Long countEdges(final String space,
			final String edge, 
			TermQueryBuilder builder) {
		String nGql = GqlTemplate.COUNTEDGES;
		String query = null;
		if(builder != null && StringUtils.isNotBlank(query = builder.of(edge))) {
			nGql = nGql.replaceFirst("YIELD", " {} YIELD");
			nGql = StrUtil.format(nGql, edge, query);
		}
		ResultSet resultSet = executeGql(space, nGql);
		List<JSONObject> rs = ResultSetUtils.printResultObject(resultSet);
		if(rs != null && rs.size() > 0) {
			return rs.get(0).getLong("ct");
		}
		return 0L;
	}
	
	
}
