package gov.nysenate.openleg.service.spotcheck.senatesite.calendar;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import gov.nysenate.openleg.client.view.bill.BillIdView;
import gov.nysenate.openleg.client.view.calendar.CalendarIdView;
import gov.nysenate.openleg.model.base.SessionYear;
import gov.nysenate.openleg.model.base.Version;
import gov.nysenate.openleg.model.bill.BillId;
import gov.nysenate.openleg.model.calendar.CalendarId;
import gov.nysenate.openleg.model.calendar.CalendarType;
import gov.nysenate.openleg.model.spotcheck.senatesite.SenateSiteDump;
import gov.nysenate.openleg.model.spotcheck.senatesite.SenateSiteDumpFragment;
import gov.nysenate.openleg.model.spotcheck.senatesite.bill.SenateSiteBill;
import gov.nysenate.openleg.model.spotcheck.senatesite.calendar.SenateSiteCalendar;
import gov.nysenate.openleg.processor.base.ParseError;
import gov.nysenate.openleg.service.spotcheck.senatesite.base.JsonParser;
import gov.nysenate.openleg.util.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
/**
* Created by PKS on 2/25/16.
*/
@Service
public class CalendarJsonParser extends JsonParser {
@Autowired
ObjectMapper objectMapper;
public List<SenateSiteCalendar> parseCalendars(SenateSiteDump calendarDump) throws ParseError {
return calendarDump.getDumpFragments().stream()
.flatMap(fragment -> extractCalendarsFromFragment(fragment).stream())
.collect(Collectors.toList());
}
private List<SenateSiteCalendar> extractCalendarsFromFragment(SenateSiteDumpFragment fragment) throws ParseError{
try {
JsonNode calendarMap = objectMapper.readTree(fragment.getFragmentFile())
.path("calendars");
if (calendarMap.isMissingNode()) {
throw new ParseError("Could not locate \"calendars\" node in senate site calendar dump fragment file: " +
fragment.getFragmentFile().getAbsolutePath());
}
List<SenateSiteCalendar> calendars = new LinkedList<>();
for (JsonNode calendarNode : calendarMap) {
calendars.add(extractSenSiteCalendar(calendarNode, fragment));
}
return calendars;
} catch (IOException | NoSuchElementException ex) {
throw new ParseError("error while reading senate site calendar dump fragment file: " +
fragment.getFragmentFile().getAbsolutePath(),
ex);
}
}
private SenateSiteCalendar extractSenSiteCalendar(JsonNode calendarNode, SenateSiteDumpFragment fragment) throws IOException {
SenateSiteCalendar calendar = new SenateSiteCalendar(DateUtils.endOfDateTimeRange(fragment.getDumpId().getRange()));
calendar.setBillCalNumbers(getIntListValue(calendarNode, "field_ol_bill_cal_number"));
calendar.setCalendarType(getCalendarType(getValue(calendarNode,"field_ol_type")));
calendar.setSequenceNo(getIntValue(calendarNode,"field_ol_sequence_no"));
calendar.setVersion(getVersion(getValue(calendarNode,"field_ol_version")));
calendar.setCalendarId(getCalendarId(calendarNode,"calendar_id"));
TypeReference<List<String>> listTypeReference = new TypeReference<List<String>>() {};
Optional<List<String>> value = deserializeValue(calendarNode,"field_ol_bill",listTypeReference);
calendar.setBill(getBillId(value.orElse(Collections.emptyList()), calendar.getCalendarId().getYear()));
return calendar;
}
private CalendarType getCalendarType(String calendarType)
{
return CalendarType.valueOf(StringUtils.upperCase(calendarType));
}
private Version getVersion(String version)
{
return Version.of(version);
}
private List<BillId> getBillId(List<String> billNos, int year){
List<BillId> billId = billNos.stream().map(billNo -> new BillId(billNo, SessionYear.of(year))).collect(Collectors.toList());
return billId;
}
private CalendarId getCalendarId(JsonNode calendarNode, String fieldName){
TypeReference<CalendarIdView> calendarIdType = new TypeReference<CalendarIdView>() {};
Optional<CalendarIdView> calendarIdViews = deserializeValue(calendarNode, fieldName, calendarIdType);
return calendarIdViews.map(CalendarIdView::toCalendarId).orElseThrow(() -> new ParseError("no calendarID"));
}
}