package edu.asu.diging.gilesecosystem.web.zookeeper.impl;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

import javax.annotation.PostConstruct;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryNTimes;
import org.apache.curator.utils.ZKPaths;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import edu.asu.diging.gilesecosystem.septemberutil.properties.MessageType;
import edu.asu.diging.gilesecosystem.septemberutil.service.ISystemMessageHandler;
import edu.asu.diging.gilesecosystem.util.properties.IPropertiesManager;
import edu.asu.diging.gilesecosystem.web.exceptions.NoNepomukFoundException;
import edu.asu.diging.gilesecosystem.web.service.properties.Properties;
import edu.asu.diging.gilesecosystem.web.zookeeper.INepomukServiceDiscoverer;

@Service
public class NepomukServiceDiscoverer implements INepomukServiceDiscoverer {
    
    private final Logger logger = LoggerFactory.getLogger(getClass());

    private String znode;

    private CuratorFramework curatorFramework;
    
    @Autowired
    private IPropertiesManager propertiesManager;
    
    @Autowired
    private ISystemMessageHandler msgHandler;

    @PostConstruct
    public void init() throws Exception {
        curatorFramework = CuratorFrameworkFactory
                .newClient(propertiesManager.getProperty(Properties.ZOOKEEPER_HOST) 
                        + ":" 
                        + propertiesManager.getProperty(Properties.ZOOKEEPER_PORT) , new RetryNTimes(5, 1000));
        curatorFramework.start();
        
        znode = "/services/" + propertiesManager.getProperty(Properties.ZOOKEEPER_NEPOMUK_SERVICE_NAME);
        checkServices();
    }
    
    private void checkServices() throws Exception {
        List<String> uris = curatorFramework.getChildren().forPath(znode);
        for (String uri : uris) {
            logger.debug("Found: " + uri);
            byte[] url = curatorFramework.getData().forPath(ZKPaths.makePath(znode, uri));
            if (url != null) {
                logger.debug("with URL: " + new String(url));
                msgHandler.handleMessage("Nepomuk instance found.", "Giles found a Nepomuk instance at ZNode " + uri + " with URL " + new String(url), MessageType.INFO);
            } else {
                msgHandler.handleMessage("No Nepomuk URL configured.", "There was no Nepomuk instance found at " + new String(uri), MessageType.WARNING);
                logger.debug("There was no URL registered with the ZNode.");
            }          
        }      
    }
    
    @Override
    public String getRandomNepomukInstance() throws NoNepomukFoundException {
        // throws Exception
        List<String> uris;
        try {
            uris = curatorFramework.getChildren().forPath(znode);
        } catch (Exception e) {
            throw new NoNepomukFoundException(e);
        }
        int randomInstance = ThreadLocalRandom.current().nextInt(0, uris.size());
        for (int i = 0; i < uris.size(); i++) {
            // get random Nepomuk instance
            byte[] urlBytes;
            try {
                urlBytes = curatorFramework.getData().forPath(ZKPaths.makePath(znode, uris.get(randomInstance)));
            } catch (Exception e) {
                throw new NoNepomukFoundException(e);
            }
            if (urlBytes != null) {
                String url = new String(urlBytes);
                try {
                    if (validateUrl(url)) {
                        // if Nepomuk instance url specified and nepomuk responds with ok
                        // return url
                        return url;
                    }
                } catch (IOException e) {
                    msgHandler.handleMessage("Nepomuk URL could not be validated.", e, MessageType.WARNING);
                }
            }
            
            // if there is no URL or URL is not valid, let's take the next instance
            randomInstance++;
            // if we're at the end of the list, start from its beginning
            if (randomInstance >= uris.size()) {
                randomInstance -= uris.size();
            }
        }
        
        return null;
    }
    
    private boolean validateUrl(String url) throws IOException {
        URL myURL = new URL(url);
        HttpURLConnection myConnection = (HttpURLConnection) myURL.openConnection();
        
        try {
            if (myConnection.getResponseCode()==HttpStatus.OK.value()) {
                return true;
            } else {
                return false;
            }
        } finally {
            myConnection.disconnect();
        }
    }
}

@@ -1533,33 +1533,16 @@
 d init()
- throws Exception
  %7B%0A     
@@ -2031,33 +2031,16 @@
 rvices()
- throws Exception
  %7B%0A     
@@ -2050,24 +2050,56 @@
 List%3CString%3E
+ uris;%0A        try %7B%0A           
  uris = cura
@@ -2133,32 +2133,254 @@
 forPath(znode);%0A
+        %7D catch (Exception e) %7B%0A            // this is actually throwing Exception%0A            msgHandler.handleMessage(%22Could not get Nepomuk entries in Zookeeper.%22, e, MessageType.WARNING);%0A            return;%0A        %7D%0A
         for (Str
@@ -2454,24 +2454,63 @@
       byte%5B%5D
+ url;%0A            try %7B%0A               
  url = curat
@@ -2566,24 +2566,264 @@
 ode, uri));%0A
+            %7D catch (Exception e) %7B%0A                // method is actually throwing exception%0A                msgHandler.handleMessage(%22Could not get Nepomuk URL from Zookeeper.%22, e, MessageType.ERROR);%0A                return;%0A            %7D%0A
             

Handle exception if no Nepomuk is running