/**
 *  Copyright 2005-2015 Red Hat, Inc.
 *
 *  Red Hat licenses this file to you under the Apache License, version
 *  2.0 (the "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 *  implied.  See the License for the specific language governing
 *  permissions and limitations under the License.
 */
package io.fabric8.arquillian.kubernetes.await;

import io.fabric8.arquillian.kubernetes.Configuration;
import io.fabric8.arquillian.kubernetes.Session;
import io.fabric8.kubernetes.api.model.EndpointAddress;
import io.fabric8.kubernetes.api.model.EndpointSubset;
import io.fabric8.kubernetes.api.model.Endpoints;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.ServicePort;
import io.fabric8.kubernetes.api.model.ServiceSpec;
import io.fabric8.kubernetes.client.KubernetesClient;

import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

import static io.fabric8.kubernetes.api.KubernetesHelper.getName;

public class SessionServicesAreReady implements Callable<Boolean> {

    private final Session session;
    private final KubernetesClient kubernetesClient;
    private final Configuration configuration;

    public SessionServicesAreReady(KubernetesClient kubernetesClient, Session session, Configuration configuration) {
        this.session = session;
        this.kubernetesClient = kubernetesClient;
        this.configuration = configuration;
    }

    @Override
    public Boolean call() throws Exception {
        boolean result = true;
        List<Service> services = kubernetesClient.services().inNamespace(session.getNamespace()).list().getItems();

        if (services.isEmpty()) {
            result = false;
            session.getLogger().warn("No services are available yet, waiting...");
        } else if (configuration.isWaitForServiceConnectionEnabled()) {
            for (Service s : filterServices(services, configuration.getWaitForServices())) {
                if (!isEndpointAvailable(s)) {
                    result = false;
                    break;
                }
            }
        }
        return result;
    }

    /**
     * Checks if there is an endpoint for the service available.
     * @param s The target service.
     * @return  Returns true if a connection to at least one of the endpoints is possible.
     */
    private boolean isEndpointAvailable(Service s) {
        String serviceStatus = null;
        boolean result = false;
        String sid = getName(s);
        //String namespace = s.getMetadata().getNamespace();
        String namespace = session.getNamespace();
        Endpoints endpoints = kubernetesClient.endpoints().inNamespace(namespace).withName(sid).get();
        ServiceSpec spec = s.getSpec();
        if (endpoints != null && spec != null) {
            List<EndpointSubset> subsets = endpoints.getSubsets();
            if (subsets != null) {
                for (EndpointSubset subset : subsets) {
                    List<EndpointAddress> addresses = subset.getAddresses();
                    if (addresses != null) {
                        for (EndpointAddress address : addresses) {
                            String ip = address.getIp();
                            String addr = ip;
/*
    TODO v1beta2...
                            String addr = endpoit.substring(0, endpoit.indexOf(":"));
                            Integer port = Integer.parseInt(endpoit.substring(endpoit.indexOf(":") + 1));
*/
                            List<ServicePort> ports = spec.getPorts();
                            for (ServicePort port : ports) {
                                Integer portNumber = port.getPort();
                                if (portNumber != null && portNumber > 0) {
                                    if (configuration.isConnectToServicesEnabled()) {
                                        try (Socket socket = new Socket()) {
                                            socket.connect(new InetSocketAddress(ip, portNumber), configuration.getServiceConnectionTimeout());
                                            serviceStatus = "Service: " + sid + " is ready. Provider:" + addr + ".";
                                            return true;
                                        } catch (Exception e) {
                                            serviceStatus = "Service: " + sid + " is not ready! in namespace " + namespace + ". Error: " + e.getMessage();
                                        } finally {
                                            session.getLogger().warn(serviceStatus);
                                        }
                                    } else {
                                        serviceStatus = "Service: " + sid + " is ready. Not testing connecting to it!. Provider:" + addr + ".";
                                        session.getLogger().warn(serviceStatus);
                                        return true;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return result;
    }


    private List<Service> filterServices(List<Service> services, List<String> selectedIds) {
        if (selectedIds != null && !selectedIds.isEmpty()) {
            List<Service> result = new ArrayList<>();
            for (Service s : services) {
                String sid = getName(s);
                if (selectedIds.contains(sid)) {
                    result.add(s);
                }
            }
            return result;
        } else {
            return services;
        }
    }

}

@@ -2891,69 +2891,8 @@
 s);%0A
-        //String namespace = s.getMetadata().getNamespace();%0A
     
@@ -5462,32 +5462,113 @@
     %7D%0A        %7D%0A
+        session.getLogger().warn(%22Service: %22 + sid + %22 has no valid endpoints%22);%0A
         return r

add more verbose logging for missing service endpoints