/**
 * <p>Copyright:Copyright(c) 2016</p>
 * <p>Company:上海中信信息发展股份有限公司</p>
 * <p>类更新历史信息</p>
 * @author 张二伟
 * @date 2017-03-19 14:58
 */

package com.cesgroup.cesmonitor.service.map;

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

import com.cesgroup.cesmonitor.common.JSON;
import com.cesgroup.cesmonitor.common.Util;
import com.zabbix4j.ZabbixApi;
import com.zabbix4j.ZabbixApiParamter;
import com.zabbix4j.host.HostGetRequest;
import com.zabbix4j.host.HostGetResponse;
import com.zabbix4j.hostinteface.HostInterfaceObject;
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;

/**
 * 根据主机创建拓扑图
 *
 *
 * @author zhang.erwei
 * @version 1.0.0 2017年5月22日
 */
public class MapAutoCreate {

    private Map<String, HostGetResponse.Result> hosts = new HashMap<String, HostGetResponse.Result>();

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

    public static final Integer MRAGIN = 200;

    /**
     * 自动创建
     *
     * @param name
     *            拓扑图名称
     * @param coreDeviceIP
     *            核心交换机IP地址
     * @return
     */
    public void create(String name, String coreDeviceIP, String community) {
        try {
            getHost();
            Device device = new Device();
            device.setIp(coreDeviceIP);
            device.setCommunity(community);
            //            device.setSnmpPort(snmpPort);
            new MapAutoCreatePrepareRalation().getLink(device);
            System.out.println(JSON.toJson(device));

            int x = 100;
            MapCreateRequest request = new MapCreateRequest();
            MapCreateRequest.Params params = request.getParams();
            params.setMap_type(1);
            params.setName(name);
            params.setWidth(100);
            params.setHeight(100);
            params.setLabel_type(0);
            params.setLabel_type_image(0);
            params.setLabel_type_trigger(0);

            HostGetResponse.Result root = this.hosts.get(device.getIp());
            if (root == null) {
                throw new RuntimeException("没有发现交换机:" + device.getIp());
            }

            MapElementObject mapRoot = new MapElementObject();
            mapRoot.setLabel("{HOST.NAME}");
            mapRoot.setElementid(root.getHostid());
            mapRoot.setElementtype(MapElementObject.ELEMENT_TYPE.HOST.value);
            mapRoot.setX(x);
            mapRoot.setY(root.getHostid());
            mapRoot.setIconid_off(155);
            params.addMapElement(mapRoot);
            device.setHostid(root.getHostid());

            for (String key : device.getLink().keySet()) {
                Device d = device.getLink().get(key);
                HostGetResponse.Result child = this.hosts.get(d.getIp());
                if (child == null) {
                    continue;
                }

                boolean exist = false;
                for (MapElementObject o : params.getSelements()) {
                    if (o.getElementid().intValue() == child.getHostid().intValue()) {
                        exist = true;
                        break;
                    }
                }
                if (exist) {
                    continue;
                }

                MapElementObject mapChild = new MapElementObject();
                mapChild.setLabel("{HOST.NAME}");
                mapChild.setElementid(child.getHostid());
                mapChild.setElementtype(MapElementObject.ELEMENT_TYPE.HOST.value);
                mapChild.setX(x + 200);
                mapChild.setY(child.getHostid());
                mapChild.setIconid_off(155);
                params.addMapElement(mapChild);
                if (params.getWidth() < x + 200 + MRAGIN) {
                    params.setWidth(x + 200 + MRAGIN);
                }
                d.setHostid(child.getHostid());
                this.createChildren(d, params, x + 400);

                params.addMapElement(mapChild);

            }

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

            //创建连接
            createLink(device, mapId);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    private void createChildren(Device device, MapCreateRequest.Params mapCreateRequest, int x) {
        for (String key : device.getLink().keySet()) {
            Device d = device.getLink().get(key);
            HostGetResponse.Result child = this.hosts.get(d.getIp());
            if (child == null) {
                continue;
            }
            boolean exist = false;
            for (MapElementObject o : mapCreateRequest.getSelements()) {
                if (o.getElementid().intValue() == child.getHostid().intValue()) {
                    exist = true;
                    break;
                }
            }
            if (exist) {
                continue;
            }

            MapElementObject mapChild = new MapElementObject();
            mapChild.setLabel("{HOST.NAME}");
            mapChild.setElementid(child.getHostid());
            mapChild.setElementtype(MapElementObject.ELEMENT_TYPE.HOST.value);
            mapChild.setX(x);
            mapChild.setY(child.getHostid());
            mapChild.setIconid_off(155);
            mapCreateRequest.addMapElement(mapChild);

            if (mapCreateRequest.getWidth() < x + MRAGIN) {
                mapCreateRequest.setWidth(x + MRAGIN);
            }
            d.setHostid(child.getHostid());

            this.createChildren(d, mapCreateRequest, x + 200);

        }
    }

    /**
     * 创建节点连接
     *
     * @param itservices
     *            IT服务列表
     * @param rootServiceId
     *            根服务节点ID
     * @param mapId
     *            拓扑图ID
     * @throws Exception
     *             异常对象
     */
    private void createLink(Device device, 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(device, mapId, params);
        zabbixApi.map().update(request);

    }

    /**
     * 准备节点连接
     *
     * @param itservices
     *            IT服务列表
     * @param rootServiceId
     *            根服务节点ID
     * @param mapId
     *            拓扑图ID
     * @param mapUpdateRequest
     *            拓扑图更新参数
     * @throws Exception
     *             异常对象
     */
    private void prepare(Device device, Integer mapId, 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);
        }
        MapElementObject from = map.get(device.getHostid());
        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 (String key : device.getLink().keySet()) {
            Device d = device.getLink().get(key);
            if (d.getHostid() == null) {
                continue;
            }
            MapElementObject to = map.get(d.getHostid());
            selements.add(to);
            //String label = key + ":{" + hosts.get(device.getIp()).getHost() + ":ifOutOctets[" + key + "].last(0)}";
            String label = "进口：{" + hosts.get(device.getIp()).getHost() + ":ifHCInOctets[" + key + "].last(0)}";
            label += "\n出口：{" + hosts.get(device.getIp()).getHost() + ":ifHCOutOctets[" + key + "].last(0)}";
            links.add(this.prepareLink(from, to, label));

            this.prepareChildren(d, mapUpdateRequest, selements, links, map, layer + 1);
        }
        mapUpdateRequest.setLinks(links);
        mapUpdateRequest.setSelements(selements);
    }

    private void prepareChildren(Device device, MapUpdateRequest.Params mapUpdateRequest,
        List<MapElementObject> selements, List<MapLinkObject> links, Map<Integer, MapElementObject> map, int layer) {
        if (positionY.get(layer) == null) {
            positionY.put(layer, 20);
        }
        MapElementObject from = map.get(device.getHostid());
        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 (Device d : device.getLink().values()) {
        for (String key : device.getLink().keySet()) {
            Device d = device.getLink().get(key);
            if (d.getHostid() == null) {
                continue;
            }
            int childLayer = layer + 1;
            MapElementObject to = map.get(d.getHostid());
            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);
            //G1/0/1：{10.250.200.6:ifOutOctets[GigabitEthernet1/0/1].last(0)}
            //            String label = key + ":{" + hosts.get(device.getIp()).getHost() + ":ifOutOctets[" + key + "].last(0)}";
            String label = "进口：{" + hosts.get(device.getIp()).getHost() + ":ifHCInOctets[" + key + "].last(0)}";
            label += "\n出口：{" + hosts.get(device.getIp()).getHost() + ":ifHCOutOctets[" + key + "].last(0)}";
            links.add(this.prepareLink(from, to, label));
            this.prepareChildren(d, mapUpdateRequest, selements, links, map, childLayer + 1);
        }

    }

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

    /**
     * 查询主机
     *
     * @throws Exception
     *             异常对象
     */
    private void getHost() throws Exception {
        HostGetRequest request = new HostGetRequest();
        HostGetRequest.Params params = request.getParams();
        params.setSelectInterfaces(ZabbixApiParamter.QUERY.extend.name());
        params.setSelectMacros(ZabbixApiParamter.QUERY.extend.name());
        ZabbixApi zabbixApi = Util.getLoginUser().getZabbixApi();
        HostGetResponse response = zabbixApi.host().get(request);
        for (HostGetResponse.Result hostObject : response.getResult()) {
            for (HostInterfaceObject hi : hostObject.getInterfaces()) {
                if (hi.getInterfaceid() == null) {
                    continue;
                }
                hosts.put(hi.getIp(), hostObject);
            }
        }
    }
}
