/*
* [PrepKansas.java]
*
* Summary: One shot program to process tax data for Kansas. Generates code for AmericanTax.java table.
*
* Copyright: (c) 2010-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 2010-12-13 initial version
*/
package com.mindprod.americantax;
import com.mindprod.common18.ST;
import com.mindprod.csv.CSVReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.lang.System.*;
/**
* One shot program to process tax data for Kansas. Generates code for AmericanTax.java table.
*
* Generates code for AmericanTax.java table.
*
* @author Roedy Green, Canadian Mind Products
* @version 1.0 2010-12-13 initial version
* @since 2010-12-13
*/
public final class PrepKansas extends PrepStateBase
{
/**
* find out what county a city is in
*/
private final HashMap lookupCityToCounty = new HashMap<>( 1000 );
private final Pattern FIND_COUNTY = Pattern.compile( "(?i)\\(([\\p{Alpha}]+) county\\)", Pattern.CASE_INSENSITIVE );
private final String[] countiesByCountyNumber = new String[ 100 ];
private final double[] lookupCountyTax = new double[ 100 ];
/**
* enclosing county for this city records for lookup
*/
private String enclosingCounty;
/**
* Constructor
*/
private PrepKansas()
{
super( "KS",
"kansas",
6.3,
true /* hast kansascounties.csv */,
true /* has kansascities.csv */,
true /* files include state rate */,
false /* convert to book case */,
1000 /* est # cites */ );
}
/**
* abbreviate the city so we can look it up.
*
* @param city long city name
*
* @return short city name
*/
private String getShortCity( final String city )
{
String shortCity;
if ( city.startsWith( "St. " ) )
{
final int place = city.indexOf( '(' );
if ( place < 0 )
{
shortCity = city;
}
else
{
shortCity = city.substring( 0, place ).trim();
}
}
else
{
shortCity = ST.firstWord( city );
}
return shortCity;
}
/*
* home: http://www.ksrevenue.org/salesratechanges.html
* download http://www.ksrevenue.org/pdf/pub1700413.xls kansas.xls
* // name will change
* counties and cities interleaved in Excel format.
* and save as E:\com\mindprod\americantax\kansascities.csv
* # city/county rate
* "Abbyville", 7.300
* "Abilene", 8.150
* "Admire", 7.800
* "Agenda", 8.300
* "Willard (Shawnee county)", 8.200
* "Willard (Wabaunsee county)", 8.550
*
* counties in kansas: http://www.kansascounties.org/index.aspx?NID=7
* list of cities in Kanas with county http://en.wikipedia.org/wiki/List_of_cities_in_Kansas as table. (complete?)
* http://www.ksrevenue.org/pdf/StateLocalSalesRates.pdf (city rate without country assoc)
* download http://www.ksrevenue.org/pdf/110localratios.pdf kansaslookup.pdf lets you figure out which county
* each city is in
* save as kansascounties.csv
* Allen county
* Bassett
* Elsmore
* Gas
* Humboldt
* Iola
* La Harpe
* Mildred
* Moran
* Savonburg
* Anderson county
* Colony
* Manually create entries for
* Coffey,LeRoy,0.000
* Reno, "Salt Mine Museum-1",1.750
* Reno,"Salt Mine Museum-2",1.000
* Wabaunsee,"Maple Hill Travel Store CID",3.500
*/
/**
* Default method to read and prepare one county record.
* You must read, and add SalesTaxItem to salesTaxItems, and skipToNewLine
*
* @param c open CSV reader.
*
* @throws java.io.IOException if cannot read file
*/
void prepareCity( final CSVReader c ) throws IOException
{
final String item = c.get();
if ( item.endsWith( " county" ) )
{
// was a country record
final String county = ST.chopTrailingString( item, " county" );
final double percent = c.getDouble() - stateTax; // strip state tax
salesTaxItems.add( new SalesTaxItem( county, "", percent ) );
}
else
{
// was a city record
String city = item;
final double percent = c.getDouble() - stateTax; // strip state tax, includes county tax
// the county may already be encoded as (iiii county)
String county;
final Matcher m = FIND_COUNTY.matcher( city ); // Matchers are used both for matching and finding.
if ( m.find() )
{
county = m.group( 1 );
// prune off the county from the city.
int place = city.indexOf( '(' );
city = city.substring( 0, place );
}
else
{
county = lookupCityToCounty.get( getShortCity( city ) );
if ( county == null )
{
// can't find county for city.
county = "unknown";
err.println( "can't find county for city: " + city );
}
}
salesTaxItems.add( new SalesTaxItem( county, city, percent ) );
}
c.skipToNextLine();
}
/**
* files don't have mechanism to get county from city, so you must build an aux table
* Default method to read and prepare one county record.
* You must read, and add SalesTaxItem to salesTaxItems, and skipToNewLine
* This fix contains no tax info, just city to county association.
*
* @param c open CSV reader.
*
* @throws IOException if cannot read file
*/
void prepareCounty( final CSVReader c ) throws IOException
{
String item = c.get();
if ( item.endsWith( "county" ) )
{
enclosingCounty = ST.chopTrailingString( item, " county" ).intern();
}
else
{
lookupCityToCounty.put( getShortCity( item ), enclosingCounty );
}
c.skipToNextLine();
}
public static void main( String[] args ) throws IOException
{
new PrepKansas().prepare();
}
}