/**
 * <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 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.host.HostGetRequest;
import com.zabbix4j.host.HostGetResponse;
import com.zabbix4j.hostinteface.HostInterfaceObject;
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 MapCreateFromHostsUpdate {

    /**
     * 单个节点高度
     */
    public static final int HEIGHT_PER_NODE = 100;

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

    /**
     * 主机分组，key为IP地址前三段
     */
    protected Map<String, HostGroup> groups = new HashMap<String, HostGroup>();

    /**
     * 拓扑图id
     */
    protected Integer mapId;

    /**
     * 创建拓扑图
     *
     * @param name
     *            拓扑图名称
     *
     * @param gatewayIPs
     *            网关节点列表
     * @param layout
     *            布局方式
     * @return 拓扑图id
     * @throws Exception
     *             异常对象
     */
    public int update(Integer mapId, List<String> gatewayIPs) throws Exception {
        this.groupHosts(gatewayIPs);

        Map<Integer, HostGetResponse.Result> newHosts = addNewHost(mapId, gatewayIPs);
        System.out.println("新发现主机：" + JSON.toJson(newHosts));
        if (newHosts.size() == 0) {
            return mapId;
        }

        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<Integer, MapElementObject> map = new HashMap<Integer, MapElementObject>();
        //            List<MapElementObject> list = response.getResult().get(0).getSelements();
        for (MapElementObject obj : response.getResult().get(0).getSelements()) {
            map.put(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<Integer, MapElementObject> elementsMap = new HashMap<Integer, MapElementObject>();

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

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

        //添加新的连接
        for (String ip : gatewayIPs) {
            int index = ip.lastIndexOf('.');
            if (index == -1) {
                throw new RuntimeException("网关IP地址无效：" + gatewayIPs);
            }
            String ipPrefix = ip.substring(0, index);
            //        for (String ipPrefix : groups.keySet()) {
            HostGroup group = groups.get(ipPrefix);
            Host gateway = group.getGateway();
            MapElementObject from = null;
            if (gateway != null) {
                from = elementsMap.get(gateway.getHostObject().getHostid());
                //                from.setY(y + group.getHosts().size() / 2 * HEIGHT_PER_NODE);
                gateway.setMapElementObject(from);
            }
            for (Host host : group.getHosts()) {
                if (newHosts.containsKey(gateway.getHostObject().getHostid())
                    || newHosts.containsKey(host.getHostObject().getHostid())) {
                    MapElementObject to = elementsMap.get(host.getHostObject().getHostid());
                    if (from != null) {
                        links.add(this.newLink(from, to));
                    }
                }
            }
        }

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

        return mapId;
    }

    /**
     * 创建连接对象
     *
     * @param from
     *            源
     * @param to
     *            目标
     * @return 连接对象
     */
    protected MapLinkObject newLink(MapElementObject from, MapElementObject to) {
        MapLinkObject link = new MapLinkObject();
        link.setSelementid1(from.getSelementid());
        link.setSelementid2(to.getSelementid());
        return link;
    }

    /**
     * 对所有主机根据网关ip地址进行分组
     *
     * @param gatewayIPs
     *            网关ip地址
     * @throws Exception
     *             异常对象
     */
    public void groupHosts(List<String> gatewayIPs) throws Exception {
        if (gatewayIPs == null || gatewayIPs.size() == 0) {
            //groupHosts();
            throw new RuntimeException("无网关");
        }
        groups.clear();
        for (String ip : gatewayIPs) {
            int index = ip.lastIndexOf('.');
            if (index == -1) {
                throw new RuntimeException("网关IP地址无效：" + gatewayIPs);
            }
            String prefixIP = ip.substring(0, index);
            HostGroup group = new HostGroup();
            group.setGatewayIP(ip);
            groups.put(prefixIP, group);
        }
        HostGetRequest request = new HostGetRequest();
        HostGetRequest.Params params = request.getParams();
        params.setSelectInterfaces(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;
                }
                int index = hi.getIp().lastIndexOf('.');
                String prefixIP = hi.getIp().substring(0, index);
                HostGroup group = groups.get(prefixIP);
                if (group == null) {
                    continue;
                }

                Host host = new Host();
                host.setHostObject(hostObject);

                if (hi.getIp().equals(group.getGatewayIP())) {
                    group.setGateway(host);
                } else {
                    //group.getHosts().add(host);
                    group.addHost(host);
                }
            }
        }
        for (HostGroup group : groups.values()) {
            if (group.getGateway() == null) {
                throw new RuntimeException("网关：" + group.getGatewayIP() + "无对应的主机。");
            }
        }
    }

    private Map<Integer, HostGetResponse.Result> addNewHost(Integer mapId, List<String> gatewayIPs) throws Exception {
        Map<Integer, HostGetResponse.Result> newHosts = new HashMap<Integer, HostGetResponse.Result>();
        ZabbixApi zabbixApi = Util.getLoginUser().getZabbixApi();
        Map<Integer, MapElementObject> mapExistElement = new HashMap<Integer, 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.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 (MapElementObject obj : list) {
            selements.add(obj);
        }
        //查找新增加主机
        int x = 0;
        int y = 50;
        int n = 0;
        for (String ip : gatewayIPs) {
            int index = ip.lastIndexOf('.');
            if (index == -1) {
                throw new RuntimeException("网关IP地址无效：" + gatewayIPs);
            }
            String prefixIP = ip.substring(0, index);
            HostGroup group = groups.get(prefixIP);
            Host gateway = group.getGateway();
            if (!mapExistElement.containsKey(gateway.getHostObject().getHostid())) {
                MapElementObject mapChild = new MapElementObject();
                mapChild.setLabel("{HOST.NAME}");
                mapChild.setElementid(gateway.getHostObject().getHostid());
                mapChild.setElementtype(MapElementObject.ELEMENT_TYPE.HOST.value);
                x = 50 * ++n;
                if (x - 100 > response.getResult().get(0).getWidth()) {
                    n = 0;
                    x = 50 * ++n;
                    y += 100;
                }

                mapChild.setX(50 * (newHosts.size() + 1));
                mapChild.setY(y);
                mapChild.setIconid_off(155);
                selements.add(mapChild);
                newHosts.put(gateway.getHostObject().getHostid(), gateway.getHostObject());
            }
            for (Host h : group.getHosts()) {
                if (!mapExistElement.containsKey(h.getHostObject().getHostid())) {
                    MapElementObject mapChild = new MapElementObject();
                    mapChild.setLabel("{HOST.NAME}");
                    mapChild.setElementid(h.getHostObject().getHostid());
                    mapChild.setElementtype(MapElementObject.ELEMENT_TYPE.HOST.value);
                    x = 50 * ++n;
                    if (x - 100 > response.getResult().get(0).getWidth()) {
                        n = 0;
                        x = 50 * ++n;
                        y += 100;
                    }

                    mapChild.setX(50 * (newHosts.size() + 1));
                    mapChild.setY(y);
                    mapChild.setIconid_off(155);
                    selements.add(mapChild);
                    newHosts.put(h.getHostObject().getHostid(), h.getHostObject());
                }
            }
        }
        updateParams.setSelements(selements);
        zabbixApi.map().update(updateRequest);
        return newHosts;
    }

    /**
     * 自动对所有主机根据默认网关*.*.*.254进行分组
     *
     * @throws Exception
     *             异常对象
     */
    public void groupHosts() throws Exception {
        groups.clear();
        HostGetRequest request = new HostGetRequest();
        HostGetRequest.Params params = request.getParams();
        params.setSelectInterfaces(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;
                }
                int index = hi.getIp().lastIndexOf('.');
                String prefixIP = hi.getIp().substring(0, index);
                HostGroup group = groups.get(prefixIP);
                if (group == null) {
                    group = new HostGroup();
                    groups.put(prefixIP, group);
                }

                Host host = new Host();
                host.setHostObject(hostObject);

                if (hi.getIp().endsWith(".254")) {
                    group.setGateway(host);
                } else {
                    group.getHosts().add(host);
                }
            }
        }
    }

}
