/*
 * Copyright 2017-present Open Networking Laboratory
 *
 * Licensed 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 org.opencord.ce.local.channel.client;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.jboss.netty.util.Timeout;
import org.jboss.netty.util.TimerTask;
import org.onlab.packet.IpAddress;
import org.onlab.util.Timer;
import org.opencord.ce.api.models.DomainEndPoint;
import org.slf4j.Logger;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;

import static java.util.concurrent.TimeUnit.SECONDS;
import static org.opencord.ce.api.services.channel.Symbols.BASE_URL;
import static org.opencord.ce.api.services.channel.Symbols.COLON;
import static org.opencord.ce.api.services.channel.Symbols.DOUBLESLASH;
import static org.opencord.ce.api.services.channel.Symbols.HTTP;
import static org.opencord.ce.api.services.channel.Symbols.MASTER;
import static org.opencord.ce.api.services.channel.Symbols.MASTER_IP;
import static org.opencord.ce.api.services.channel.Symbols.OK;
import static org.opencord.ce.api.services.channel.Symbols.RESULT;
import static org.slf4j.LoggerFactory.getLogger;

/**
 * Executed periodically to find the leader node of a domain.
 * Stops when the ip is found
 */
public class DomainMasterIpDiscoveryTask implements TimerTask {

    private final Logger log = getLogger(getClass());

    private Timeout timeout;
    private volatile boolean isStopped;
    private DomainEndPoint endPoint;
    private Client client;
    private String localSiteId;

    private ObjectMapper mapper;

    public DomainMasterIpDiscoveryTask(DomainEndPoint endPoint, Client client,
                                       ObjectMapper mapper, String localSiteId) {
        this.endPoint = endPoint;
        this.client = client;
        this.mapper = mapper;
        this.localSiteId = localSiteId;

        isStopped = true;
        start();

    }

    public synchronized void stop() {
        if (!isStopped) {
            isStopped = true;
            timeout.cancel();
        } else {
            log.warn("IpDiscovery stopped multiple times?");
        }
    }

    public synchronized void start() {
        if (isStopped) {
            isStopped = false;
            timeout = Timer.getTimer().newTimeout(this, 0, SECONDS);
        } else {
            log.warn("IpDiscovery started multiple times?");
        }
    }

    public synchronized boolean isStopped() {
        return isStopped || timeout.isCancelled();
    }

    @Override
    public void run(Timeout t) {
        if (isStopped()) {
            return;
        }
            String url = HTTP + COLON + DOUBLESLASH + endPoint.publicIp() + COLON +
                    endPoint.port() + BASE_URL + "/global" + MASTER + "/" + localSiteId;
            log.info("GET: " + url);
            WebTarget wt = client.target(url);
            Response response = wt.request(MediaType.APPLICATION_JSON)
                    .get();
            log.info("DEBUG response: " + response.toString());
            if (response.getStatus() == Response.Status.OK.getStatusCode()) {
                String stringBody = response.readEntity(String.class);
                try {
                    ObjectNode responseBody = (ObjectNode) mapper.readTree(stringBody);
                    if (responseBody.path(RESULT).asText().equals(OK)) {
                        IpAddress masterIpAdress =  IpAddress.valueOf(responseBody.path(MASTER_IP).asText());
                        this.stop();
                        return;
                    }
                } catch (IOException ex) {
                    log.info("getLocalMasterIp() IOException, try next endpoint ip");
                }
            }
        if (!isStopped()) {
            timeout = Timer.getTimer().newTimeout(this, 3, SECONDS);
        }
    }
}
