
// NewsUtils.java
// Andrew Davison, ad@coe.psu.ac.th, July 2023

/* Functions for using the News API
   (https://newsapi.org/docs/get-started)

  Usage:
    > compile NewsUtils.java
*/

import java.awt.Desktop;
import java.io.*;
import java.util.*;
import java.net.*;
import java.net.http.*;
import java.time.*;
import java.time.format.*;

import com.google.gson.Gson;


public class NewsUtils
{
  private static final String API_KEY = "XXXXXX";
   /* Get your own key from the News API site at:
      https://newsapi.org/docs/get-started
   */

  private static final int MAX_ARTICLES = 20;
      // maximum number of articles that are listed


  private static String[] COUNTRIES = {
     "ae", "ar", "at", "au", "be", "bg", "br", "ca", "ch", "cn", 
     "co", "cu", "cz", "de", "eg", "fr", "gb", "gr", "hk", "hu", "id", 
     "ie", "il", "in", "it", "jp", "kr", "lt", "lv", "ma", "mx", "my", 
     "ng", "ml", "no", "nz", "ph", "pl", "pt", "ro", "rs", "ru", "sa", 
     "se", "sg", "si", "sk", "th", "tr", "tw", "ua", "us", "ve", "za"
   };
      /* copied from the country field at
         https://newsapi.org/docs/endpoints/top-headlines
      */


  public static void listCountries()
  {  
    System.out.println("Country codes:");
    System.out.println(Arrays.toString(COUNTRIES));
    System.out.println();
  }

  public static boolean isCountry(String s)
  {  
    String sl = s.toLowerCase();
    for(String country : COUNTRIES)
      if (country.equals(sl))
        return true;
    return false;
  }  // end of isCountry()



  public static int getInt(String s)
  { 
    int num = 1;
    try {
      num = Integer.parseInt(s);
    }
    catch (NumberFormatException ex){ 
      System.out.println("Incorrect integer format: " + s); 
    }
    return num;
  }  // end of getInt()


  public static String encode(String s)
  {
    try {
      return URLEncoder.encode(s, "UTF-8");
    }
    catch (Exception e) {
      System.out.println("Encoding error: " + e); 
      return s;
    }
  }  // end of encode()


  public static News getNews(String request)
  /* return a News object or report an error for the
     given News API request string 
  */
  {
    String response = getNewsResponse(request);
    News news = new Gson().fromJson(response, News.class);
    if (news.status.equals("error")) {
      NewsError err = new Gson().fromJson(response, NewsError.class);
      System.out.println("Error: " + err.message);
      return null;
    }
    else
      return news;
  }  // end of getNews()



  public static String getNewsResponse(String request)
  /* return a response string for the
     given News API request string 
  */
  {
    HttpClient client = HttpClient.newHttpClient();
    HttpRequest httpRequest = HttpRequest.newBuilder()
           .uri(URI.create(request + "&apiKey=" + API_KEY))
           .GET().build();
    try {
      HttpResponse<String> response = client.send(httpRequest,
                HttpResponse.BodyHandlers.ofString());
      return response.body();
    }
    catch(Exception e) {
      System.out.println("HTTP request error: " + e);
      return null;
    }
  }  // end of getNewsResponse()



  public static void showArticle(News news, int newsItem)
  // display a news article in a browser
  {
    int numArticles = news.articles.size();
    if ((newsItem  <= 0) || (newsItem > numArticles)) {
      System.out.println("News item out of range; getting article 1");
      newsItem = 1;
    }
     
    Article art = news.articles.get(newsItem-1);
    System.out.println("Retrieving article:\n  " + art.title + 
                   "\n  (" + getDate(art.publishedAt) + ")\n");
    showLink(art.url);
  }  // end of showArticle()



  public static String getDate(String s)
  // return a nicely formatted date and time string
  {
    ZonedDateTime dateTime = ZonedDateTime.parse(s);
    return dateTime.format(DateTimeFormatter.RFC_1123_DATE_TIME);
  }



  public static void showLink(String url)
  // display the supplied URL in a browser
  /* JRE sometimes crashes due to a problematic frame:
     C  [ANSI64.dll+0x2887] in
     OpenJDK 64-Bit Server VM (build 19-panama+1-13, mixed mode, sharing)
  */
  {
    try {
      if (!Desktop.isDesktopSupported()) {
        System.out.println("Desktop access not supported");
        return;
      }
      Desktop desktop = Desktop.getDesktop();
      if (desktop == null)
        System.out.println("Could not access the desktop");
      else {
        if (desktop.isSupported(Desktop.Action.BROWSE))
          desktop.browse(new URI(url));
        else
          System.out.println("Could not access the browser");
      }
    }
    catch(Exception e) {
      System.out.println("Desktop error: " + e);
    }
  }  // end of showLink()



  public static void listNews(News news)
  // List the titles and dates for up to MAX_ARTICLES articles
  {
    int numArticles = news.articles.size();
    System.out.print("Found " + numArticles +  " articles");
    if (numArticles > MAX_ARTICLES) {
      numArticles = MAX_ARTICLES;
      System.out.println(" (listing " + MAX_ARTICLES + "):\n");
    }
    else
      System.out.println(":\n");

    for (int i = 0 ; i < numArticles; i++) {
      Article art = news.articles.get(i);
      System.out.println((i+1) + ". " + art.title + "\n   (" +
                      getDate(art.publishedAt) + ")\n");
    }
  }  // end of listNews()


}  // end of NewsUtils class
