package gov.nysenate.openleg.processor.bill;
import gov.nysenate.openleg.model.bill.BillAction;
import gov.nysenate.openleg.model.bill.BillId;
import gov.nysenate.openleg.model.entity.Chamber;
import gov.nysenate.openleg.processor.base.ParseError;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Parses a bill actions list string into a list of BillAction objects.
*/
public class BillActionParser
{
private static final Logger logger = LoggerFactory.getLogger(BillActionParser.class);
/** --- Patterns --- */
/** Date format found in SobiBlock[4] bill event blocks. e.g. 02/04/13 */
protected static final DateTimeFormatter eventDateFormat = DateTimeFormatter.ofPattern("MM/dd/yy");
/** The expected format for actions recorded in the bill events [4] block. e.g. 02/04/13 Event Text Here */
protected static final Pattern billEventPattern = Pattern.compile("([0-9]{2}/[0-9]{2}/[0-9]{2}) (.*)");
/** --- Methods --- */
public static List<BillAction> parseActionsList(BillId billId, String data) throws ParseError {
List<BillAction> billActions = new ArrayList<>();
// Impose a strict order to the actions.
int sequenceNo = 0;
// Each action should be on its own line
for (String line : data.split("\n")) {
Matcher billEvent = billEventPattern.matcher(line);
if (billEvent.find()) {
LocalDate eventDate;
try {
eventDate = LocalDate.from(eventDateFormat.parse(billEvent.group(1)));
}
// Fail fast otherwise
catch (DateTimeParseException ex) {
throw new ParseError("eventDateFormat parse failure: " + billEvent.group(1));
}
String eventText = billEvent.group(2).trim();
// Each action is designated to a specific chamber. The actions belonging to the assembly will be
// all lowercase and the senate will be all uppercase.
Chamber eventChamber = StringUtils.isAllUpperCase(eventText.replaceAll("[^a-zA-Z]+", ""))
? Chamber.SENATE : Chamber.ASSEMBLY;
// Uppercase the action text to aid with regex matching
eventText = eventText.toUpperCase();
// Construct and append bill action to list.
BillAction action = new BillAction(eventDate, eventText, eventChamber, ++sequenceNo, billId);
billActions.add(action);
}
else {
throw new ParseError("Bill Action Pattern not matched: " + line);
}
}
return billActions;
}
}