/*
 * JORAM: Java(TM) Open Reliable Asynchronous Messaging
 * Copyright (C) 2018 - 2019 ScalAgent Distributed Technologies
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA.
 *
 * Initial developer(s): ScalAgent Distributed Technologies
 * Contributor(s): 
 */
package rest;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.core.Form;
import jakarta.ws.rs.client.Invocation.Builder;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.Link;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriBuilder;

import org.glassfish.jersey.client.ClientConfig;
import org.objectweb.util.monolog.api.BasicLevel;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class RestConsumer {
  Client client = null;

  URI uriCloseCons = null;
  URI uriReceiveNextMsg = null;
  URI uriAcknowledgeMsg = null;
  
  boolean debug = false;
  
  RestConsumer(String uri, String dest) {
    URI base = UriBuilder.fromUri(uri).build();
    client = ClientBuilder.newClient(new ClientConfig());
    
    WebTarget target = client.target(base);
    System.out.println("Use Rest/JMS interface: " + target.getUri());

    // lookup the destination
    Builder builder = target.path("jndi").path(dest).request();
    Response response = builder.accept(MediaType.TEXT_PLAIN).head();
    
    System.out.println("Lookup \"" + dest + "\" -> " + response.getStatus());
    if (debug) print(response.getLinks());

    URI uriCreateCons = client.target(response.getLink("create-consumer"))
//      .queryParam("name", "cons1")
        .queryParam("idle-timeout", "120")
        .getUri();
    
    try {
//      // TODO (AF): to remove (use FormParam alternate URI)
//      uriCreateCons = new URI(uriCreateCons.toString() + "-fp");
    uriCreateCons = new URI("http://localhost:8989/joram/jndi/queue/create-consumer-fp?session-mode=2");
    } catch (URISyntaxException exc) {
      exc.printStackTrace();
      uriCreateCons = null;
    }
    
    Form form = new Form();
    form.param("user", "anonymous")
        .param("password", "anonymous");

    response = client.target(uriCreateCons)
        .request()
//        .accept(MediaType.TEXT_PLAIN).post(null);
        .accept(MediaType.TEXT_PLAIN).post(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED));

    System.out.println("Create consumer -> " + response.getStatus());
    if (debug) print(response.getLinks());

    uriCloseCons = response.getLink("close-context").getUri();
    uriReceiveNextMsg = response.getLink("receive-next-message").getUri();
  }
  
  String receiveStringMsg() {
    if (debug) System.out.println("== receive-next-message -> " + uriReceiveNextMsg);
    Response response = client.target(uriReceiveNextMsg)
        .queryParam("timeout", "30000")
        .request()
        .accept(MediaType.TEXT_PLAIN)
        .get();

    String msg = response.readEntity(String.class);
    if (response.getStatus() == Response.Status.OK.getStatusCode() && msg != null) {
      if (debug) System.out.println("== receive-next-message = " + response.getStatus() + ", msg = " + msg);
      uriReceiveNextMsg = response.getLink("receive-next-message").getUri();
      uriAcknowledgeMsg = response.getLink("acknowledge-message").getUri();
    } else {
      System.out.println("ERROR consume msg = " + msg + ", response = " + response);
    }
    
    return msg;
  }
  
  public static final String BytesMessage = "BytesMessage";
  public static final String MapMessage = "MapMessage";
  public static final String TextMessage = "TextMessage";

  HashMap<String, Object> receiveJSonMsg() {
    if (debug) System.out.println("== receive-next-message -> " + uriReceiveNextMsg);
    Response response = client.target(uriReceiveNextMsg)
        .queryParam("timeout", "30000")
        .request()
        .accept(MediaType.APPLICATION_JSON)
        .get();
    
    String json = response.readEntity(String.class);
    if (debug) System.out.println("Receive json = " + json);
    
    HashMap<String, Object> msg = null;
    if (response.getStatus() == Response.Status.OK.getStatusCode() && json != null) {
      Gson gson = new GsonBuilder().create();
      msg = gson.fromJson(json, HashMap.class);

      if (debug) {
        Map header = (Map) msg.get("header");
        Map props = (Map) msg.get("properties");

        System.out.println("*** header " + header);
        System.out.println("*** properties " + props);
        System.out.println("== receive-next-message = " + response.getStatus() + ", msg = " + msg);

        print(response.getLinks());
      }
      uriReceiveNextMsg = response.getLink("receive-next-message").getUri();
      uriAcknowledgeMsg = response.getLink("acknowledge-message").getUri();
    } else {
      System.out.println("ERROR receive-next-message = " + response.getStatus() + ", msg = " + json);
    }
    
    acknowledgeMessage();
    
    return msg;
  }
  
  void acknowledgeMessage() {
    if (debug) System.out.println("== acknowledge-message -> " + uriAcknowledgeMsg);
    Response response = client.target(uriAcknowledgeMsg)
        .request()
        .accept(MediaType.TEXT_PLAIN)
        .delete();
    if (debug) System.out.println("== acknowledge-message = " + response.getStatus());
  }
  
  void close() {
    Response response = client.target(uriCloseCons).request().accept(MediaType.TEXT_PLAIN).delete();

    System.out.println("Close consumer -> " + response.getStatus());
    if (debug) print(response.getLinks());
  }

  private static void print(Set<Link> links) {
    System.out.println("  link :");
    for (Link link : links)
      System.out.println("\t" + link.getRel() + " : " + link.getUri());
  }
}
