package com.cesgroup.cesmonitor.service.map;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
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.Util;
import com.zabbix4j.ZabbixApi;
import com.zabbix4j.ZabbixApiParamter;
import com.zabbix4j.itservice.ITServiceGetRequest;
import com.zabbix4j.itservice.ITServiceGetResponse;
import com.zabbix4j.map.MapCreateRequest;
import com.zabbix4j.map.MapCreateResponse;
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 MapCreateFromITService {

    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 createMap(final Integer serviceId) throws Exception {
        int x = 100;
        MapCreateRequest request = new MapCreateRequest();
        MapCreateRequest.Params params = request.getParams();
        params.setMap_type(2);
        //params.setName("IT服务" + Util.toStr(new Date(), Util.DF_TIME));
        params.setName("IT服务" + Util.toStr(new Date(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")));
        params.setWidth(100);
        params.setHeight(100);
        params.setLabel_type(0);
        params.setLabel_type_image(0);
        params.setLabel_type_trigger(0);
        List<ITServiceGetResponse.Result> itservices = this.getITServices();
        for (ITServiceGetResponse.Result s : this.getRoot(itservices, serviceId)) {
            if (serviceId != null) {
                //                params.setName(s.getName() + "-" + Util.toStr(new Date(), Util.DF_TIME));
                params.setName(s.getName());
            }
            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(x);
            obj.setY(s.getServiceid());
            if (params.getWidth() < x + MRAGIN) {
                params.setWidth(x + MRAGIN);
            }
            this.createChildren(itservices, params, s.getServiceid(), x + 200);

            params.addMapElement(obj);

        }

        //创建map
        ZabbixApi zabbixApi = Util.getLoginUser().getZabbixApi();
        MapCreateResponse response = zabbixApi.map().create(request);
        int mapId = response.getResult().getSysmapids().get(0);

        //创建连接
        createLink(itservices, serviceId, mapId);
    }

    //    /**
    //     * 根据ITservice节点创建拓扑图
    //     *
    //     * @param servcieId
    //     *            IT服务节点ID
    //     * @throws Exception
    //     */
    //    public void createMap(Integer servcieId) throws Exception {
    //        if (servcieId == null) {
    //            createMap();
    //            return;
    //        }
    //        int x = 100;
    //        MapCreateRequest request = new MapCreateRequest();
    //        MapCreateRequest.Params params = request.getParams();
    //
    //        params.setWidth(1000);
    //        params.setHeight(1000);
    //        params.setLabel_type(0);
    //        params.setLabel_type_image(0);
    //        params.setLabel_type_trigger(0);
    //        List<ITServiceGetResponse.Result> itservices = this.getITServices();
    //        ITServiceGetResponse.Result s = this.get(itservices, servcieId);
    //        params.setName("IT服务拓扑图-" + s.getName() + Util.toStr(new Date(), Util.DF_TIME));
    //        if (s != null) {
    //            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(x);
    //            obj.setY(s.getServiceid());
    //            this.createChildren(itservices, params, s.getServiceid(), x + 200);
    //
    //            params.addMapElement(obj);
    //
    //        }
    //
    //        //创建map
    //        ZabbixApi zabbixApi = Util.getLoginUser().getZabbixApi();
    //        MapCreateResponse response = zabbixApi.map().create(request);
    //        int mapId = response.getResult().getSysmapids().get(0);
    //
    //        //创建连接
    //        createLink(itservices, mapId);
    //    }

    /**
     * 获取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(final List<ITServiceGetResponse.Result> itservices,
        final 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(final List<ITServiceGetResponse.Result> itservices,
        final 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(final List<ITServiceGetResponse.Result> itservices, final 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(final List<ITServiceGetResponse.Result> itservices, final MapCreateRequest.Params mapCreateRequest,
        final int parentServiceId, final int x) {
        for (ITServiceGetResponse.Result s : getChildren(itservices, parentServiceId)) {
            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(x);
            obj.setY(s.getServiceid());
            if (mapCreateRequest.getWidth() < x + MRAGIN) {
                mapCreateRequest.setWidth(x + MRAGIN);
            }

            mapCreateRequest.addMapElement(obj);
            this.createChildren(itservices, mapCreateRequest, s.getServiceid(), x + 200);
        }
    }

    /**
     * 准备节点连接
     *
     * @param itservices
     *            IT服务列表
     * @param rootServiceId
     *            根服务节点ID
     * @param mapId
     *            拓扑图ID
     * @param mapUpdateRequest
     *            拓扑图更新参数
     * @throws Exception
     *             异常对象
     */
    public void prepare(final List<ITServiceGetResponse.Result> itservices, final Integer rootServiceId, final Integer mapId,
        final MapUpdateRequest.Params mapUpdateRequest) throws Exception {
        ZabbixApi zabbixApi = Util.getLoginUser().getZabbixApi();
        List<MapLinkObject> links = new ArrayList<MapLinkObject>();
        List<MapElementObject> selements = new ArrayList<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();
        Map<Integer, MapElementObject> map = new HashMap<Integer, MapElementObject>();
        for (MapElementObject obj : list) {
            map.put(obj.getY(), obj);
        }

        int layer = 1;
        if (positionY.get(layer) == null) {
            positionY.put(layer, 20);
        }
        for (ITServiceGetResponse.Result root : this.getRoot(itservices, rootServiceId)) {
            MapElementObject from = map.get(root.getServiceid());
            positionY.put(layer, positionY.get(layer) + 100);
            from.setY(positionY.get(layer));
            if (mapUpdateRequest.getHeight() < from.getY() + MRAGIN) {
                mapUpdateRequest.setHeight(from.getY() + MRAGIN);
            }
            selements.add(from);

            for (ITServiceGetResponse.Result child : this.getChildren(itservices, root.getServiceid())) {
                MapElementObject to = map.get(child.getServiceid());
                selements.add(to);
                links.add(this.prepareLink(from, to));

                this.prepareChildren(mapUpdateRequest, selements, links, itservices, map, child, layer + 1);
            }

        }
        mapUpdateRequest.setLinks(links);
        mapUpdateRequest.setSelements(selements);
    }

    private void prepareChildren(final MapUpdateRequest.Params mapUpdateRequest, final List<MapElementObject> selements,
        final List<MapLinkObject> links, final List<ITServiceGetResponse.Result> itservices, final Map<Integer, MapElementObject> map,
        final ITServiceGetResponse.Result parent, final int layer) {
        if (positionY.get(layer) == null) {
            positionY.put(layer, 20);
        }
        MapElementObject from = map.get(parent.getServiceid());
        positionY.put(layer, positionY.get(layer) + 100);
        from.setY(positionY.get(layer));
        if (mapUpdateRequest.getHeight() < from.getY() + MRAGIN) {
            mapUpdateRequest.setHeight(from.getY() + MRAGIN);
        }
        selements.add(from);
        for (ITServiceGetResponse.Result child : this.getChildren(itservices, parent.getServiceid())) {
            int childLayer = layer + 1;
            MapElementObject to = map.get(child.getServiceid());
            if (positionY.get(childLayer) == null) {
                positionY.put(childLayer, 100);
            }
            positionY.put(childLayer, positionY.get(layer) + 100);
            to.setY(positionY.get(childLayer));
            if (mapUpdateRequest.getHeight() < to.getY() + MRAGIN) {
                mapUpdateRequest.setHeight(to.getY() + MRAGIN);
            }
            selements.add(to);
            links.add(this.prepareLink(from, to));
            this.prepareChildren(mapUpdateRequest, selements, links, itservices, map, child, childLayer + 1);
        }

    }

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

    /**
     * 创建节点连接
     *
     * @param itservices
     *            IT服务列表
     * @param rootServiceId
     *            根服务节点ID
     * @param mapId
     *            拓扑图ID
     * @throws Exception
     *             异常对象
     */
    public void createLink(final List<ITServiceGetResponse.Result> itservices, final Integer rootServiceId, final Integer mapId)
        throws Exception {
        ZabbixApi zabbixApi = Util.getLoginUser().getZabbixApi();
        MapUpdateRequest request = new MapUpdateRequest();
        MapUpdateRequest.Params params = request.getParams();
        params.setSysmapid(mapId);
        params.setHeight(100);

        prepare(itservices, rootServiceId, mapId, params);
        zabbixApi.map().update(request);

    }
}
