package org.ovirt.engine.core.vdsbroker.gluster;

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

import org.ovirt.engine.core.common.businessentities.gluster.GeoRepCrawlStatus;
import org.ovirt.engine.core.common.businessentities.gluster.GeoRepSessionStatus;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterBrickEntity;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterGeoRepSession;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterGeoRepSessionDetails;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterServer;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dao.gluster.GlusterDBUtils;
import org.ovirt.engine.core.vdsbroker.irsbroker.StatusReturnForXmlRpc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class GlusterVolumeGeoRepStatusForXmlRpc extends StatusReturnForXmlRpc {

    protected static final Logger log = LoggerFactory.getLogger(GlusterVolumeGeoRepStatusForXmlRpc.class);

    protected static final String VOLUME_NAME = "volumeName";
    protected static final String BRICKS = "bricks";
    private static final String SESSIONS = "sessions";
    private static final String SESSION_KEY = "sessionKey";
    private static final String HOST_UUID = "hostUuid";
    private static final String BRICK_NAME = "brickName";
    private static final String REMOTE_HOST = "remoteHost";
    private static final String STATUS = "status";
    private static final String CHECK_POINT_STATUS = "checkpointStatus";
    private static final String CRAWL_STATUS = "crawlStatus";
    private static final String REMOTE_VOL_NAME = "remoteVolumeName";

    protected final List<GlusterGeoRepSession> geoRepSessions = new ArrayList<GlusterGeoRepSession>();

    protected GlusterGeoRepSessionDetails getSessionDetails(Map<String, Object> innerMap) {
        GlusterGeoRepSessionDetails details = new GlusterGeoRepSessionDetails();
        Guid masterNodeGlusterId;
        if (innerMap.containsKey(HOST_UUID)) {
            masterNodeGlusterId = new Guid(innerMap.get(HOST_UUID).toString());
        } else {
            log.error("Master node uuid is not available");
            return null;
        }
        String masterBrickDir = (innerMap.containsKey(BRICK_NAME)) ? innerMap.get(BRICK_NAME).toString() : null;
        GlusterServer glusterServer = getDbUtils().getServerByUuid(masterNodeGlusterId);
        if (glusterServer != null) {
            GlusterBrickEntity brick =
                    getDbUtils().getGlusterBrickByServerUuidAndBrickDir(glusterServer.getId(), masterBrickDir);
            if (brick != null) {
                details.setMasterBrickId(brick.getId());
            }
        }
        if (details.getMasterBrickId() == null) {
            log.error("Brick information could not be retrieved for gluster host id {} and brick dir {}",
                    masterNodeGlusterId,
                    masterBrickDir);
        }

        String slave = innerMap.containsKey(REMOTE_HOST) ? innerMap.get(REMOTE_HOST).toString() : null;
        details.setSlaveHostName(slave);
        details.setStatus(GeoRepSessionStatus.from((String) innerMap.get(STATUS)));
        details.setCrawlStatus(GeoRepCrawlStatus.from((String) innerMap.get(CRAWL_STATUS)));
        details.setCheckPointStatus((String) innerMap.get(CHECK_POINT_STATUS));
        return details;
    }

    protected GlusterGeoRepSession getSession(String masterVolumeName, Map<String, Object> innerMap) {
        GlusterGeoRepSession geoRepSession = new GlusterGeoRepSession();
        // sessionKey in the form - the uuid is the gluster server uuid on master
        // <sessionKey>11ae7a03-e793-4270-8fc4-b42def8b3051:ssh://192.168.122.14::slave2</sessionKey>
        String sessionKey = (String) innerMap.get(SESSION_KEY);
        String sessSplit[] = sessionKey.split("([://]+)");
        String slaveNode = sessSplit[sessSplit.length - 2];
        if(slaveNode.contains("@")) {
            String[] hostComponents = slaveNode.split("@");
            slaveNode = hostComponents[hostComponents.length - 1];
            geoRepSession.setUserName(hostComponents[0]);
        }
        String slaveVolume = (String) innerMap.get(REMOTE_VOL_NAME);
        geoRepSession.setSlaveHostName(slaveNode);
        geoRepSession.setSlaveVolumeName(slaveVolume);
        geoRepSession.setSessionKey(sessionKey);
        geoRepSession.setMasterVolumeName(masterVolumeName);
        return geoRepSession;
    }

    private GlusterDBUtils getDbUtils() {
        return GlusterDBUtils.getInstance();
    }

    @SuppressWarnings("unchecked")
    protected void populateSessions(Map<String, Object> geoRepVolSessions) {
        for (Entry<String, Object> entry : geoRepVolSessions.entrySet()) {
            log.debug("received session information for volume '{}'", entry.getKey());
            String masterVolName = entry.getKey();

            Map<String, Object> sessionsMap = (Map<String, Object>) entry.getValue();

            if (sessionsMap.containsKey(SESSIONS)) {
                for (Object session : (Object[]) sessionsMap.get(SESSIONS)) {
                    geoRepSessions.add(populateSession(masterVolName, (Map<String, Object>) session));
                }
            }
        }

    }

    private GlusterGeoRepSession populateSession(String volumeName, Map<String, Object> innerMap) {
        GlusterGeoRepSession geoRepSession = getSession(volumeName, innerMap);
        ArrayList<GlusterGeoRepSessionDetails> geoRepSessionDetails = new ArrayList<GlusterGeoRepSessionDetails>();
        if (innerMap.containsKey(BRICKS)) {
            for (Object brickSession : (Object[]) innerMap.get(BRICKS)) {
                geoRepSessionDetails.add(getSessionDetails((Map<String, Object>) brickSession));
            }
        }
        geoRepSession.setSessionDetails(geoRepSessionDetails);
        return geoRepSession;
    }

    public GlusterVolumeGeoRepStatusForXmlRpc(Map<String, Object> innerMap) {
        this(innerMap, true);
    }

    public GlusterVolumeGeoRepStatusForXmlRpc(Map<String, Object> innerMap, boolean includeSessions) {
        super(innerMap);
        if (includeSessions && innerMap.containsKey(SESSIONS)) {
            populateSessions((Map<String, Object>) innerMap.get(SESSIONS));
        }
    }

    public List<GlusterGeoRepSession> getGeoRepSessions() {
        return geoRepSessions;
    }

}

@@ -3794,16 +3794,53 @@
 ::slave2
+:bd52ddf1-9659-4168-8197-c62e9f3e855c
 %3C/sessio
@@ -3845,16 +3845,16 @@
 ionKey%3E%0A
-
         
@@ -3964,24 +3964,138 @@
 (%5B://%5D+)%22);%0A
+        // Older gluster versions doesn't have slave volume ID in the sessionKey, it is added in Glusterfs 3.7.12%0A
         Stri
@@ -4123,27 +4123,8 @@
 lit%5B
-sessSplit.length - 
 2%5D;%0A

fix geo rep session key parsing issue