package com.nicusa.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.nicusa.util.ApiKey;
import com.nicusa.util.HttpRestClient;
import com.nicusa.util.NormalizeStateCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.util.UriComponentsBuilder;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@RestController
public class FeedController {
private static final Logger log = LoggerFactory.getLogger(FeedController.class);
@Autowired
ApiKey apiKey;
@Autowired
@Value("${rss.fda.recalls.url:http://www.fda.gov/AboutFDA/ContactFDA/StayInformed/RSSFeeds/Recalls/rss.xml}")
private String fdaRecallsRSSurl;
@Autowired
@Value("${gl.api.xml2json.url:http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=10&q=}")
private String xml2JsonCnvrtrUrl;
@Autowired
@Value("${api.fda.drug.enfrcmnt.url:https://api.fda.gov/drug/enforcement.json?}")
private String searchDrugEnfrcmntUrl;
@Autowired
@Value("${drug.most.recent.recalls.total.limit:50}")
private int mostRecentRecallsLimit;
@Autowired
@Value("${drug.recalls.unii.total.limit:99}")
private int uniiRecallsLimit;
private HttpRestClient rest = new HttpRestClient();
@RequestMapping("/recalls")
@ResponseBody
public JsonNode getFDARecalls() throws IOException {
JsonNode node = null;
ObjectMapper mapper = new ObjectMapper();
node = mapper.readTree(rest.getForObject(xml2JsonCnvrtrUrl + fdaRecallsRSSurl, String.class));
return node;
}
@RequestMapping("/drug/recalls")
@ResponseBody
public JsonNode getDrugRecalls(@RequestParam(value = "limit", defaultValue = "5") int limit,
@RequestParam(value = "fromDt", defaultValue = "") String fromDt,
@RequestParam(value = "toDt", defaultValue = "") String toDt) throws Exception {
JsonNode node;
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(searchDrugEnfrcmntUrl)
.queryParam("search", getDefaultReportDateQuery(fromDt, toDt))
.queryParam("limit", mostRecentRecallsLimit);
this.apiKey.addToUriComponentsBuilder( builder );
ObjectMapper mapper = new ObjectMapper();
String json = rest.getForObject(builder.build().toUri(), String.class);
node = mapper.readTree(json);
((ObjectNode)node).set("results", getSortedResults(node.get("results"), limit));
return node;
}
@RequestMapping("/drug/enforcements")
@ResponseBody
public JsonNode getDrugRecallsForUnii(
@RequestParam(value = "unii", defaultValue = "") String unii,
@RequestParam(value = "limit", defaultValue = "0") int limit) throws Exception {
JsonNode node;
HttpHeaders headers = new HttpHeaders();
ObjectMapper mapper = new ObjectMapper();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(searchDrugEnfrcmntUrl)
.queryParam("limit", uniiRecallsLimit);
this.apiKey.addToUriComponentsBuilder( builder );
if (unii != null && unii.trim().length() > 0) {
builder.queryParam("search", "openfda.unii:" + unii);
try {
node = mapper.readTree(rest.getForObject(builder.build().toUri(), String.class));
((ObjectNode)node).set("results", getSortedResults(node.get("results"), limit) );
} catch (HttpClientErrorException ex) {
if (ex.getStatusCode().value() == 404) {
node = new ObjectMapper().readTree("{\"error\":{\"code\":\"NOT_FOUND\", \"message\":\"No matches found!\"}}");
} else {
throw ex;
}
}
} else {
node = getDrugRecalls(limit == 0 ? 10 : limit, null, null);
}
return node;
}
private static ArrayNode getSortedResults(JsonNode results, int objectLimit) throws Exception {
JsonNodeFactory factory = JsonNodeFactory.instance;
ArrayNode sortedArray = new ArrayNode(factory);
Field innerArrayNode = ArrayNode.class.getDeclaredField("_children");
innerArrayNode.setAccessible(true);
List<JsonNode> recallsList = (List<JsonNode>) innerArrayNode.get(results);
Collections.sort(recallsList, new EnforcementReportDateComparator());
for (JsonNode obj : recallsList) {
String jsonDistPattern = NormalizeStateCode.parseToJson(obj.get("distribution_pattern").asText());
((ObjectNode) obj).replace("distribution_pattern", new ObjectMapper().readTree(jsonDistPattern));
}
sortedArray.addAll(recallsList.subList(0, (objectLimit == 0 || objectLimit > recallsList.size()) ? recallsList.size() : objectLimit));
return sortedArray;
}
private static String getDefaultFromDate() {
Calendar now = Calendar.getInstance();
StringBuilder fromDt = new StringBuilder().append(now.get(now.YEAR))
.append((String.valueOf(now.get(now.MONTH) - 1).length() == 1) ? "0" + String.valueOf(now.get(now.MONTH) - 1) : String.valueOf(now.get(now.MONTH) - 1))
.append(getCurrentDay());
return fromDt.toString();
}
private static String getDefaultToDate() {
Calendar now = Calendar.getInstance();
StringBuilder toDt = new StringBuilder().append(now.get(now.YEAR))
.append((String.valueOf(now.get(now.MONTH) + 1).length() == 1) ? "0" + String.valueOf(now.get(now.MONTH) + 1) : String.valueOf(now.get(now.MONTH) + 1))
.append(getCurrentDay());
return toDt.toString();
}
private static String getCurrentDay() {
Calendar now = Calendar.getInstance();
return (String.valueOf(now.get(now.DAY_OF_MONTH)).length() == 1 ? "0" + String.valueOf(now.get(now.DAY_OF_MONTH)) : String.valueOf(now.get(now.DAY_OF_MONTH)));
}
private String getDefaultReportDateQuery(String fromDt, String toDt) {
Calendar now = Calendar.getInstance();
StringBuilder reportDtquery = new StringBuilder()
.append("report_date:[")
.append((fromDt != null && fromDt.trim().length() == 8) ? fromDt : getDefaultFromDate())
.append("+TO+")
.append((toDt != null && toDt.trim().length() == 8) ? toDt : getDefaultToDate())
.append("]");
return reportDtquery.toString();
}
}
class EnforcementReportDateComparator implements Comparator<JsonNode> {
@Override
public int compare(JsonNode o1, JsonNode o2) {
return (o2.get("report_date").asInt() - o1.get("report_date").asInt());
}
}