Subversion Repositories SmartDukaan

Rev

Blame | Last modification | View Log | RSS feed

package com.smartdukaan.cron.offercircular;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * Resolves the "Credit cards" / "Debit Cards" cells to bank ids.
 *
 * The alias map must be supplied by the caller (built from offers.bank +
 * offers.bank_alias) because the circular spells the same bank several ways across
 * pages: IDFC / IDFC BANK / IDFC FIRST BANK, Indusind / Indusland (a typo in the
 * source), AU / AU Bank / Au Small Finance Bank. Without aliasing, ingest creates
 * four IDFCs.
 *
 * Note that UPI appears in these columns but is a payment mode, not an issuer, so it
 * is reported as a flag rather than resolved as a bank.
 */
public final class BankTextParser {

    /** Card-type and qualifier words that are not bank names. J and K are the halves
     *  of "J&K" left behind by splitting on '&'; J&K is deliberately out of scope. */
    private static final Pattern NOISE = Pattern.compile(
            "^(CC|DC|EMI|CARD|CARDS|BANK|ONLY|LFR|FINANCIAL|CREDIT|DEBIT|REG|FULL"
            + "|SWIPE|AND|OR|THE|SELECTED|SELECTIVE|CARDLESS|CARDLESS EMI|CARDLES S"
            + "|CARDLES|J|K|K BANK)$");

    private static final Pattern ALL_BANKS = Pattern.compile("ALL\\s*BANKS?");
    private static final Pattern ALL_BANKS_CLAUSE = Pattern.compile("ALL\\s*BANKS?\\s*(EXCEPT)?");
    private static final Pattern UPI = Pattern.compile("\\bUPI\\b");
    private static final Pattern PARENTHETICAL = Pattern.compile("\\(.*?\\)");
    private static final Pattern SEPARATOR = Pattern.compile("[,/&]| AND ");
    private static final Pattern WHITESPACE = Pattern.compile("\\s+");

    public static final class Result {
        private final List<Integer> bankIds = new ArrayList<>();
        private final List<String> unresolved = new ArrayList<>();
        private boolean allBanks;
        private boolean upi;
        public List<Integer> getBankIds() { return bankIds; }
        public List<String> getUnresolved() { return unresolved; }
        public boolean isAllBanks() { return allBanks; }
        public boolean isUpi() { return upi; }
    }

    private BankTextParser() { }

    public static Result parse(String cell, Map<String, Integer> aliasToBankId) {
        Result result = new Result();
        if (cell == null) {
            return result;
        }
        String text = cell.trim();
        if (text.isEmpty() || "-".equals(text) || "NA".equals(text) || "N/A".equals(text)) {
            return result;
        }
        String upper = text.toUpperCase();
        result.allBanks = ALL_BANKS.matcher(upper).find();
        result.upi = UPI.matcher(upper).find();

        // parentheticals are qualifiers ("(DC & CC)", "(LFR Only)"), not bank names
        String body = PARENTHETICAL.matcher(upper).replaceAll(" ");
        body = ALL_BANKS_CLAUSE.matcher(body).replaceAll(" ");

        for (String token : SEPARATOR.split(body)) {
            String name = strip(WHITESPACE.matcher(token).replaceAll(" "), " .-");
            if (name.isEmpty() || NOISE.matcher(name).matches() || "UPI".equals(name)) {
                continue;
            }
            Integer bankId = aliasToBankId.get(name);
            if (bankId == null) {
                // progressively shorter prefixes: "HDFC DEBIT" -> "HDFC"
                for (int cut = name.length(); cut > 2; cut--) {
                    bankId = aliasToBankId.get(name.substring(0, cut).trim());
                    if (bankId != null) {
                        break;
                    }
                }
            }
            if (bankId != null) {
                if (!result.bankIds.contains(bankId)) {
                    result.bankIds.add(bankId);
                }
            } else {
                result.unresolved.add(name);
            }
        }
        return result;
    }

    private static String strip(String s, String chars) {
        int from = 0;
        int to = s.length();
        while (from < to && chars.indexOf(s.charAt(from)) >= 0) { from++; }
        while (to > from && chars.indexOf(s.charAt(to - 1)) >= 0) { to--; }
        return s.substring(from, to);
    }
}