package gov.nysenate.openleg.processor.bill; import gov.nysenate.openleg.model.base.SessionYear; import gov.nysenate.openleg.model.base.Version; import gov.nysenate.openleg.model.bill.ApprovalId; import gov.nysenate.openleg.model.bill.ApprovalMessage; import gov.nysenate.openleg.model.bill.BillId; import gov.nysenate.openleg.model.bill.BillTextType; import gov.nysenate.openleg.model.entity.Chamber; import gov.nysenate.openleg.processor.base.ParseError; import java.time.LocalDateTime; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ApprovalMessageParser extends BillTextParser { /** --- Regex Patterns --- */ private static final Pattern approvalHeaderPattern = Pattern.compile("00000\\.SO DOC APPR(\\d+)\\s+APPROVAL\\s+(\\d{4})"); private static final Pattern approvalTitlePattern = Pattern.compile("\\d{5}\\s+APPROVAL MEMORANDUM\\s+-\\s+No\\.\\s+\\d+\\s+Chapter\\s+(\\d+)"); private static final Pattern approvalBillIdPattern = Pattern.compile("(?i)\\d{5}\\s+MEMORANDUM filed with (Senate|Assembly) Bill Number (\\d+)\\-?([A-Z])?, entitled:"); private static final Pattern approvalSignerPattern = Pattern.compile("\\d{5}\\s+(?:(?:The|This) bill is|These bills are) approved\\.\\s*\\(signed\\)\\s*([a-zA-Z.'\\- ]*[a-zA-Z.])"); /** An approval message object that is constructed while parsing the memo*/ private ApprovalMessage approvalMessage; /** --- Constructors --- */ public ApprovalMessageParser(String data, LocalDateTime dateTime) { super(data, BillTextType.VETO_APPROVAL, dateTime); approvalMessage = new ApprovalMessage(); } /** --- Functional getters/setters --- */ /** * Verifies the approval message before returning it * @return * @throws ParseError */ public ApprovalMessage getApprovalMessage() throws ParseError{ if (isDeleted()) { return null; } verifyApprovalMessage(); return approvalMessage; } public ApprovalId getApprovalId() { if (approvalMessage != null) { return approvalMessage.getApprovalId(); } else { return null; } } /** --- Overrides --- */ /** * {@inheritDoc} * Sets the approval message text to the memo text * @return * @throws ParseError */ @Override public String extractText() throws ParseError { String memoText = super.extractText(); approvalMessage.setMemoText(memoText); return memoText; } /** * {@inheritDoc} * Performs additional approval message parsing to extract meta data * @param line * @param text * @param fullText * @return * @throws ParseError */ @Override protected String parseLine(String line, StringBuilder text, String fullText) throws ParseError { int lineNum = Integer.parseInt(line.substring(0,5)); if(lineNum == 0) { Matcher headerMatcher = approvalHeaderPattern.matcher(line); if(headerMatcher.matches()){ approvalMessage.setApprovalNumber(Integer.parseInt(headerMatcher.group(1))); approvalMessage.setYear(Integer.parseInt(headerMatcher.group(2))); approvalMessage.setSession(new SessionYear(approvalMessage.getYear())); } } else if (lineNum == 2) { Matcher titleMatcher = approvalTitlePattern.matcher(line); if(titleMatcher.matches()){ approvalMessage.setChapter(Integer.parseInt(titleMatcher.group(1))); } } else if (lineNum > 11 && approvalMessage.getSigner()==null){ Matcher signerMatcher = approvalSignerPattern.matcher(line); if(signerMatcher.matches()) { approvalMessage.setSigner(signerMatcher.group(1)); } } return super.parseLine(line, text, fullText); } /** --- Internal Methods --- */ /** * Checks that all necessary fields are present for the approval message * @throws ParseError if fields are missing */ private void verifyApprovalMessage() throws ParseError { boolean completeApprovalMessage = approvalMessage.getApprovalNumber()!=0 && approvalMessage.getYear()!=0 && approvalMessage.getSession()!=null && approvalMessage.getChapter()!=0; if (!completeApprovalMessage) { throw new ParseError("Incomplete approval message"); } } }