package io.cattle.platform.agent.connection.simulator.impl;

import io.cattle.platform.agent.connection.simulator.AgentConnectionSimulator;
import io.cattle.platform.agent.connection.simulator.AgentSimulatorEventProcessor;
import io.cattle.platform.core.constants.InstanceConstants;
import io.cattle.platform.core.model.Agent;
import io.cattle.platform.eventing.model.Event;
import io.cattle.platform.eventing.model.EventVO;
import io.cattle.platform.framework.event.FrameworkEvents;
import io.cattle.platform.framework.event.Ping;
import io.cattle.platform.json.JsonMapper;
import io.cattle.platform.object.ObjectManager;
import io.cattle.platform.object.meta.ObjectMetaDataManager;
import io.cattle.platform.object.util.DataAccessor;
import io.cattle.platform.util.type.CollectionUtils;

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

import javax.inject.Inject;

import org.apache.commons.lang3.StringUtils;

public class SimulatorPingProcessor implements AgentSimulatorEventProcessor {

    JsonMapper jsonMapper;
    ObjectManager objectManager;

    @Override
    public Event handle(AgentConnectionSimulator simulator, Event event) throws Exception {
        if (!FrameworkEvents.PING.equals(event.getName()))
            return null;

        Agent agent = simulator.getAgent();
        Ping ping = jsonMapper.convertValue(event, Ping.class);
        Ping pong = jsonMapper.convertValue(EventVO.reply(event).withData(ping.getData()), Ping.class);

        if (ping.getOption(Ping.RESOURCES) && !agent.getUri().startsWith("delegate://")) {
            addResources(pong, agent);
        }

        if (ping.getOption(Ping.INSTANCES) && !agent.getUri().startsWith("delegate://")) {
            addInstances(simulator, pong, agent);
        }

        return pong;
    }

    protected void addInstances(AgentConnectionSimulator simulator, Ping pong, Agent agent) {
        List<Map<String, Object>> resources = pong.getData().getResources();

        for (String instance : simulator.getInstances()) {
            Map<String, Object> instanceMap = CollectionUtils.asMap(ObjectMetaDataManager.TYPE_FIELD, InstanceConstants.TYPE, ObjectMetaDataManager.UUID_FIELD,
                    instance, ObjectMetaDataManager.STATE_FIELD, InstanceConstants.STATE_RUNNING);
            resources.add(instanceMap);
        }

        String hostUuid = agent.getUuid() + "-" + 0;
        Map<String, Object> hostUuidResource = new HashMap<String, Object>();
        hostUuidResource.put(ObjectMetaDataManager.TYPE_FIELD, "hostUuid");
        hostUuidResource.put(ObjectMetaDataManager.UUID_FIELD, hostUuid);
        resources.add(hostUuidResource);

        pong.setOption(Ping.INSTANCES, true);
    }

    protected void addResources(Ping pong, Agent agent) {
        List<Map<String, Object>> resources = pong.getData().getResources();

        String physicalHostUuid = DataAccessor.fromDataFieldOf(agent).withScope(AgentConnectionSimulator.class).withKey("externalId").as(jsonMapper,
                String.class);

        if (StringUtils.isEmpty(physicalHostUuid)) {
            physicalHostUuid = agent.getUuid() + "-physical-host";
        }

        Map<String, Object> physicalHost = new HashMap<String, Object>();
        physicalHost.put(ObjectMetaDataManager.UUID_FIELD, physicalHostUuid);
        physicalHost.put(ObjectMetaDataManager.KIND_FIELD, "sim");
        physicalHost.put(ObjectMetaDataManager.TYPE_FIELD, "physicalHost");

        Boolean addPhysicalHost = DataAccessor.fromDataFieldOf(agent).withScope(AgentConnectionSimulator.class).withKey("addPhysicalHost").withDefault(true)
                .as(jsonMapper, Boolean.class);

        long hosts = DataAccessor.fromDataFieldOf(agent).withScope(AgentConnectionSimulator.class).withKey("hosts").withDefault(1L).as(jsonMapper, Long.class);

        long poolsPerHost = DataAccessor.fromDataFieldOf(agent).withScope(AgentConnectionSimulator.class).withKey("storagePoolsPerHost").withDefault(1L).as(
                jsonMapper, Long.class);

        for (long i = 0; i < hosts; i++) {
            String hostUuid = agent.getUuid() + "-" + i;

            Map<String, Object> host = new HashMap<String, Object>();
            host.put(ObjectMetaDataManager.UUID_FIELD, hostUuid);
            host.put(ObjectMetaDataManager.KIND_FIELD, "sim");
            host.put(ObjectMetaDataManager.TYPE_FIELD, "host");

            if (addPhysicalHost) {
                host.put("physicalHostUuid", physicalHostUuid);
            }

            for (long j = 0; j < poolsPerHost; j++) {
                String poolUuid = hostUuid + "-" + j;

                Map<String, Object> pool = new HashMap<String, Object>();
                pool.put(ObjectMetaDataManager.UUID_FIELD, poolUuid);
                pool.put(ObjectMetaDataManager.KIND_FIELD, "sim");
                pool.put(ObjectMetaDataManager.TYPE_FIELD, "storagePool");
                pool.put("hostUuid", hostUuid);

                resources.add(pool);
            }

            /*
             * Purposely put host after storagePool so that AgentResourceManager
             * will have to reorder then on insert
             */
            resources.add(host);
        }

        if (addPhysicalHost) {
            /*
             * Purposely put physical host after host so that
             * AgentResourceManager will have to reorder then on insert
             */
            resources.add(physicalHost);
        }
    }

    public JsonMapper getJsonMapper() {
        return jsonMapper;
    }

    @Inject
    public void setJsonMapper(JsonMapper jsonMapper) {
        this.jsonMapper = jsonMapper;
    }

    public ObjectManager getObjectManager() {
        return objectManager;
    }

    @Inject
    public void setObjectManager(ObjectManager objectManager) {
        this.objectManager = objectManager;
    }

}

@@ -5188,24 +5188,688 @@
 s.add(host);
+%0A%0A            String ipAddress = DataAccessor.fromDataFieldOf(agent)%0A                    .withScope(AgentConnectionSimulator.class)%0A                    .withKey(%22ipAddress%22)%0A                    .withDefault(%22192.168.0.21%22).as(String.class);%0A            String ipUuid = agent.getUuid() + %22-%22 + ipAddress;%0A%0A            Map%3CString, Object%3E ip = new HashMap%3C%3E();%0A            ip.put(ObjectMetaDataManager.UUID_FIELD, ipUuid);%0A            ip.put(ObjectMetaDataManager.KIND_FIELD, %22sim%22);%0A            ip.put(ObjectMetaDataManager.TYPE_FIELD, %22ipAddress%22);%0A            ip.put(%22address%22, ipAddress);%0A            ip.put(%22hostUuid%22, hostUuid);%0A%0A            resources.add(ip);
 %0A        %7D%0A%0A
@@ -5860,32 +5860,33 @@
 ip);%0A        %7D%0A%0A
+%0A
         if (addP

Make simulated hosts always have an IP