/* * [PrepAlabama.java] * * Summary: One shot program to process tax data for Alabama. Generates code for AmericanTax.java table. * * Copyright: (c) 1999-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.0 2007-06-08 * 1.1 2010-12-10 update to produce CSV file without state tax included. */ package com.mindprod.americantax; import com.mindprod.common18.ST; import com.mindprod.csv.CSVReader; import java.io.IOException; import java.util.regex.Matcher; import java.util.regex.Pattern; import static java.lang.System.*; /** * One shot program to process tax data for Alabama. Generates code for AmericanTax.java table. * * @author Roedy Green, Canadian Mind Products * @version 1.1 2010-12-10 update to produce CSV file without state tax included. * @since 2007-06-08 */ public final class PrepAlabama extends PrepStateBase { private static final boolean DEBUGGING = false; private static final Pattern CITY_FINDER = Pattern.compile( "(Unabated )?([ \\d\\p{Alpha}/\\-\\&\\%\\[\\]\\.]+)", Pattern.CASE_INSENSITIVE ); private static final Pattern COUNTY_FINDER = Pattern.compile( "(Unabated )?([ \\d\\p{Alpha}/\\-]+)County([ \\d\\p{Alpha}/\\-]*)", Pattern.CASE_INSENSITIVE ); private static final Pattern SPLIT_ON_SLASH = Pattern.compile( "/" ); /** * Merge alabamabacities.csv and alabamacounties.csv to produce * alabamadistricts.csv * use PrepAlamama.btm to download and create alabamacities.csv * Convert string CO to COUNTY * Manually sort out dups. * This file will have a mixture of county and city tax rates. * Alabama no longer posts list of county codes. You must deduce them from how they are used in conjunction with * locality codes on cities. Manually verify alabamacounties.csv by looking to see if any new county codes used * on cities, * e.g. 91+ * Then run PrepAlabama.java * also http://www.ador.state.al.us/salestax/sales/index.cfm?Action=City has lookup of cities. * also http://www.ador.state.al.us/salestax/rates.pdf for county rates. *

*/ private final String[] lookupCounty = new String[ 100 ]; // 0..99 /** * Constructor */ private PrepAlabama() { super( "AL", "alabama", 4.0, true /* counties */, true /* cities */, false /* files include state rate */, true /* convert to book case */, 700 ); } /** * Default method to read and prepare one county record. * You must read, and add SalesTaxItem to salesTaxItems, and skipToNewLine * * @param c open CSV reader to alabamacities.csv * * @throws IOException if cannot read file */ void prepareCity( final CSVReader c ) throws IOException { // records are a mixture of cities, counties, and county/city. final String location = ST.toBookTitleCase( c.get() ); final double percent = c.getDouble(); final int countyNumber = c.getInt(); c.skipToNextLine(); String county = lookupCounty[ countyNumber ]; if ( county == null ) { err.println( "location: " + location + " countyNumber:" + countyNumber + " has no matching county record" ); county = "unknown"; } String city; Matcher m = COUNTY_FINDER.matcher( location ); if ( m.matches() ) { final String unabated = m.group( 1 ) /* Unabated */; if ( !county.equals( m.group( 2 ).trim() /* county */ ) ) { out.println( "Stated county does not match number county stated:[" + m.group( 2 ).trim() + "] " + "lookup:[" + county + "] loc:[" + location + "]" ); } if ( unabated != null && unabated.length() > 0 ) { county = county + " Unabated"; } city = m.group( 3 ).trim()/* city */; if ( DEBUGGING ) { for ( int i = 0; i <= m.groupCount(); i++ ) { out.println( i + " [" + m.group( i ) + "]" ); } } } else { m = CITY_FINDER.matcher( location ); if ( m.matches() ) { final String unabated = m.group( 1 ) /* Unabated */; city = m.group( 2 ).trim(); if ( unabated != null && unabated.length() > 0 ) { city = city + " Unabated"; } } else { out.println( "non match " + location ); city = location; } } if ( DEBUGGING ) { out.println( "parse: loc:[" + location + "] county:[" + county + "] city:[" + city + "]" ); } if ( city.startsWith( "Cl " ) ) { city = ST.chopLeadingString( city, "Cl " ) + " Cl"; } city = ST.trimLeading( city, '-' ); final int place = county.indexOf( '/' ); if ( place < 0 ) { salesTaxItems.add( new SalesTaxItem( ST.condense( county ), ST.condense( city ), percent ) ); } else { // two or counties mentioned. String[] counties = SPLIT_ON_SLASH.split( county ); for ( String acounty : counties ) { salesTaxItems.add( new SalesTaxItem( ST.condense( acounty ), ST.condense( city ), percent ) ); } } } /** * Default method to read and prepare one county record. * You must read, and add SalesTaxItem to salesTaxItems, and skipToNewLine * * @param c open CSV reader to alabamacounties.csv * * @throws IOException if cannot read file */ void prepareCounty( final CSVReader c ) throws IOException { // just count and county number, no tax rates., No "County". final String countyName = ST.toBookTitleCase( c.get() ); final int countyLocalityNumber = c.getInt(); lookupCounty[ countyLocalityNumber ] = countyName; c.skipToNextLine(); } public static void main( String[] args ) throws IOException { new PrepAlabama().prepare(); } }