package com.cesgroup.cesmonitor.service.map;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cesgroup.cesmonitor.common.JSON;
import com.cesgroup.cesmonitor.common.Util;
import com.zabbix4j.ZabbixApi;
import com.zabbix4j.ZabbixApiParamter;
import com.zabbix4j.itservice.ITServiceGetRequest;
import com.zabbix4j.itservice.ITServiceGetResponse;
import com.zabbix4j.map.MapElementObject;
import com.zabbix4j.map.MapGetRequest;
import com.zabbix4j.map.MapGetResponse;
import com.zabbix4j.map.MapLinkObject;
import com.zabbix4j.map.MapUpdateRequest;

/**
 * 根据IT服务创建拓扑图
 *
 * @author zhang.erwei
 * @version 1.0.0 2017年5月24日
 */
public class MapCreateFromITServiceUpdate {

    public static final Integer MRAGIN = 100;

    /**
     * 触发器拓扑图节点图标ID
     */
    public static final Integer ICON_TIGGER = 145;

    /**
     * 其他拓扑图节点图标ID
     */
    public static final Integer ICON_NODE = 130;

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

    Map<Integer, Integer> positionY = new HashMap<Integer, Integer>();

    /**
     * 根据ITservice层级结构创建拓扑图
     *
     * @param serviceId
     *            IT服务节点ID
     * @throws Exception
     *             异常对象
     */
    public void update(Integer mapId, Integer serviceId) throws Exception {

        List<ITServiceGetResponse.Result> itservices = this.getITServices();
        Map<String, ITServiceGetResponse.Result> newNodes = this.addNewNode(mapId, itservices, serviceId);
        System.out.println("新发现节点：" + JSON.toJson(newNodes));
        if (newNodes.size() == 0) {
            return;
        }
        List<MapLinkObject> links = new ArrayList<MapLinkObject>();

        ZabbixApi zabbixApi = Util.getLoginUser().getZabbixApi();

        MapGetRequest request = new MapGetRequest();
        MapGetRequest.Params params = request.getParams();
        params.addSysMapId(mapId);
        //        params.setSelectIconMap(ZabbixApiParamter.QUERY.extend.name());
        params.setSelectLinks(ZabbixApiParamter.QUERY.extend.name());
        params.setSelectSelements(ZabbixApiParamter.QUERY.extend.name());
        //        params.setSelectUrls(ZabbixApiParamter.QUERY.extend.name());

        MapGetResponse response = zabbixApi.map().get(request);
        Map<String, MapElementObject> map = new HashMap<String, MapElementObject>();
        //            List<MapElementObject> list = response.getResult().get(0).getSelements();
        for (MapElementObject obj : response.getResult().get(0).getSelements()) {
            map.put(obj.getLabel() + obj.getElementid(), obj);
        }
        //            //准备元素
        //            for (MapElementObject obj : response.getResult().get(0).getSelements()) {
        //                selements.add(obj);
        //            }
        //准备连接
        for (MapLinkObject obj : response.getResult().get(0).getLinks()) {
            links.add(obj);
        }

        /**
         * 拓扑图节点Map，key为对于主机的id
         */
        Map<String, MapElementObject> elementsMap = new HashMap<String, MapElementObject>();

        for (MapElementObject obj : response.getResult().get(0).getSelements()) {
            elementsMap.put(obj.getLabel() + obj.getElementid(), obj);
        }

        MapUpdateRequest updateRequest = new MapUpdateRequest();
        MapUpdateRequest.Params updateParams = updateRequest.getParams();
        updateParams.setSysmapid(mapId);

        //添加新的连接
        for (ITServiceGetResponse.Result root : this.getRoot(itservices, serviceId)) {
            MapElementObject from = map.get(root.getName() + root.getTriggerid());
            if (from == null) {
                continue;
            }
            for (ITServiceGetResponse.Result child : this.getChildren(itservices, root.getServiceid())) {
                MapElementObject to = map.get(child.getName() + child.getTriggerid());
                if (newNodes.containsKey(from.getLabel() + from.getElementid())
                    || newNodes.containsKey(to.getLabel() + to.getElementid())) {
                    links.add(this.prepareLink(from, to));
                }
                this.prepareChildrenLink(links, itservices, map, child, newNodes);
            }

        }
        updateParams.setLinks(links);
        zabbixApi.map().update(updateRequest);
    }

    private Map<String, ITServiceGetResponse.Result> addNewNode(Integer mapId,
        List<ITServiceGetResponse.Result> itservices, Integer serviceId) throws Exception {
        Map<String, ITServiceGetResponse.Result> newNodes = new HashMap<String, ITServiceGetResponse.Result>();
        ZabbixApi zabbixApi = Util.getLoginUser().getZabbixApi();
        Map<String, MapElementObject> mapExistElement = new HashMap<String, MapElementObject>();

        MapGetRequest request = new MapGetRequest();
        MapGetRequest.Params params = request.getParams();
        params.addSysMapId(mapId);
        //        params.setSelectIconMap(ZabbixApiParamter.QUERY.extend.name());
        params.setSelectLinks(ZabbixApiParamter.QUERY.extend.name());
        params.setSelectSelements(ZabbixApiParamter.QUERY.extend.name());
        //        params.setSelectUrls(ZabbixApiParamter.QUERY.extend.name());

        MapGetResponse response = zabbixApi.map().get(request);
        List<MapElementObject> list = response.getResult().get(0).getSelements();

        for (MapElementObject obj : list) {
            mapExistElement.put(obj.getLabel() + obj.getElementid(), obj);
        }

        MapUpdateRequest updateRequest = new MapUpdateRequest();
        MapUpdateRequest.Params updateParams = updateRequest.getParams();
        updateParams.setSysmapid(mapId);

        //List<MapLinkObject> links = new ArrayList<MapLinkObject>();
        List<MapElementObject> selements = new ArrayList<MapElementObject>();

        //查找新增加节点
        for (ITServiceGetResponse.Result s : this.getRoot(itservices, serviceId)) {
            //            if (serviceId != null) {
            //                //                params.setName(s.getName() + "-" + Util.toStr(new Date(), Util.DF_TIME));
            //                updateParams.setName(s.getName());
            //            }{
            String key = s.getName() + s.getTriggerid();

            if (!mapExistElement.containsKey(key)) {
                MapElementObject obj = new MapElementObject();
                obj.setLabel(s.getName());
                if (s.getTriggerid() == 0) {
                    obj.setElementtype(MapElementObject.ELEMENT_TYPE.IMAGE.value);
                    obj.setElementid(0);
                    obj.setIconid_off(ICON_NODE);
                } else {
                    obj.setElementtype(MapElementObject.ELEMENT_TYPE.TRIGGER.value);
                    obj.setElementid(s.getTriggerid());
                    obj.setIconid_off(ICON_TIGGER);
                }

                obj.setX(50);
                obj.setY(50);
                obj.setIconid_off(155);
                selements.add(obj);
                newNodes.put(key, s);
            }

            this.createChildren(itservices, selements, s.getServiceid(), mapExistElement, newNodes);

        }
        int x = 0;
        int y = 50;
        int n = 0;
        for (MapElementObject obj : selements) {
            x = 50 * ++n;
            if (x - 100 > response.getResult().get(0).getWidth()) {
                n = 0;
                x = 50 * ++n;
                y += 100;
            }
            obj.setX(x);
            obj.setY(y);
        }
        //准备元素
        for (MapElementObject obj : list) {
            selements.add(obj);
        }
        updateParams.setSelements(selements);
        zabbixApi.map().update(updateRequest);
        return newNodes;
    }

    /**
     * 获取ITService
     *
     * @return IT服务列表
     * @throws Exception
     *             异常对象
     */
    public List<ITServiceGetResponse.Result> getITServices() throws Exception {

        ITServiceGetRequest request = new ITServiceGetRequest();
        ITServiceGetRequest.Params params = request.getParams();
        params.setSelectDependencies(ZabbixApiParamter.QUERY.extend.name());
        params.setSelectParent(ZabbixApiParamter.QUERY.refer.name());
        ZabbixApi zabbixApi = Util.getLoginUser().getZabbixApi();
        ITServiceGetResponse response = zabbixApi.itservice().get(request);
        return response.getResult();
    }

    /**
     * 获取服务根节点
     *
     * @param itservices
     *            IT服务列表
     * @return 服务根节点
     */
    private List<ITServiceGetResponse.Result> getRoot(List<ITServiceGetResponse.Result> itservices,
        Integer rootServiceId) {

        List<ITServiceGetResponse.Result> list = new ArrayList<ITServiceGetResponse.Result>();
        if (rootServiceId == null) {
            for (ITServiceGetResponse.Result s : itservices) {
                if (s.getParent() == null) {
                    list.add(s);
                }
            }
        } else {
            list.add(this.get(itservices, rootServiceId));
        }

        return list;
    }

    /**
     * 获取服务子节点
     *
     * @param itservices
     *            IT服务列表
     * @param parentServcieId
     *            上级IT服务ID
     * @return 服务子节点列表
     */
    private List<ITServiceGetResponse.Result> getChildren(List<ITServiceGetResponse.Result> itservices,
        int parentServcieId) {
        List<ITServiceGetResponse.Result> list = new ArrayList<ITServiceGetResponse.Result>();
        for (ITServiceGetResponse.Result s : itservices) {
            if (s.getParent() != null && s.getParent().getServiceid().intValue() == parentServcieId) {
                list.add(s);
            }
        }
        return list;
    }

    /**
     * 获取IT服务
     *
     * @param itservices
     *            IT服务列表
     * @param serviceId
     *            IT服务节点ID
     * @return IT服务节点
     */
    private ITServiceGetResponse.Result get(List<ITServiceGetResponse.Result> itservices, int serviceId) {
        for (ITServiceGetResponse.Result s : itservices) {
            if (s.getServiceid().intValue() == serviceId) {
                return s;
            }
        }
        return null;
    }

    /**
     * 创建拓扑图子节点
     *
     * @param itservices
     *            IT服务列表
     * @param mapCreateRequest
     *            创建拓扑图参数对象
     * @param parentServiceId
     *            上级IT服务ID
     * @param x
     *            x坐标
     */
    public void createChildren(List<ITServiceGetResponse.Result> itservices, List<MapElementObject> selements,
        int parentServiceId, Map<String, MapElementObject> mapExistElement,
        Map<String, ITServiceGetResponse.Result> newNodes) {
        for (ITServiceGetResponse.Result s : getChildren(itservices, parentServiceId)) {
            String key = s.getName() + s.getTriggerid();

            if (!mapExistElement.containsKey(key)) {
                MapElementObject obj = new MapElementObject();
                obj.setLabel(s.getName());
                if (s.getTriggerid() == 0) {
                    obj.setElementtype(MapElementObject.ELEMENT_TYPE.IMAGE.value);
                    obj.setElementid(0);
                    obj.setIconid_off(ICON_NODE);
                } else {
                    obj.setElementtype(MapElementObject.ELEMENT_TYPE.TRIGGER.value);
                    obj.setElementid(s.getTriggerid());
                    obj.setIconid_off(ICON_TIGGER);
                }
                obj.setX(50);
                obj.setY(50);
                newNodes.put(key, s);
                selements.add(obj);
            }

            this.createChildren(itservices, selements, s.getServiceid(), mapExistElement, newNodes);
        }
    }

    private void prepareChildrenLink(List<MapLinkObject> links, List<ITServiceGetResponse.Result> itservices,
        Map<String, MapElementObject> map, ITServiceGetResponse.Result parent,
        Map<String, ITServiceGetResponse.Result> newNodes) {

        MapElementObject from = map.get(parent.getName() + parent.getTriggerid());
        if (from == null) {
            return;
        }

        for (ITServiceGetResponse.Result child : this.getChildren(itservices, parent.getServiceid())) {

            MapElementObject to = map.get(child.getName() + child.getTriggerid());

            if (newNodes.containsKey(parent.getName() + parent.getTriggerid())
                || newNodes.containsKey(child.getName() + child.getTriggerid())) {
                links.add(this.prepareLink(from, to));
            }
            this.prepareChildrenLink(links, itservices, map, child, newNodes);
        }

    }

    private MapLinkObject prepareLink(MapElementObject from, MapElementObject to) {
        MapLinkObject link = new MapLinkObject();
        link.setSelementid1(from.getSelementid());
        link.setSelementid2(to.getSelementid());
        return link;
    }

}
