# Open CSV Demo

This is a Gradle Project that contains the demo for Open CSV.

When importing the project into IntelliJ, be sure to import as
a Gradle project.

Each package contains the files that should be updated and also
a `complete` package that contains the completed java files.

The structure of the demo is as follows:
- simpleParser: Just parse the csv using arrays for basic usage
- parseWithModel: parse the same data with a Java class that acts
as a model to create an Object for each record
- parseInteresting: parse 80,000+ records and collect interesting
information about the data

## Why use a csv parser and not just a Scanner

Let's consider the following data:
```
name,email
Kevin Zatloukal,kevinz@cs.uw.edu
Hal Perkins,perkins@cs.uw.edu
Mike Ernst,mernst@cs.uw.edu
Zachary Tatlock,ztatlock@cs.uw.edu
```

Currently it is very easy to split on a "," but now imagine if this
data was re-written as:

```
name,email
Zatloukal, Kevin,kevinz@cs.uw.edu
Perkins, Hal,perkins@cs.uw.edu
Ernst, Mike,mernst@cs.uw.edu
Tatlock, Zachary,ztatlock@cs.uw.edu
```

Would a simple split on "," work the same way or would it make it a
little more work? A CSV parser can take care of such cases so you
don't need to worry about it.

## simpleParser

Steps to complete:
- Get an input stream from the file and construct a BufferedReader with it.
- When using this code elsewhere, don't forget to replace "SimpleParser.class" with whatever
class you're currently inside.
```
InputStream stream = SimpleParser.class.getResourceAsStream("/data/" + SAMPLE_CSV_FILENAME);
if(stream == null) {
    System.err.println("File not found: " + CSV_FILENAME);
    System.exit(1);
}
Reader reader = new BufferedReader(new InputStreamReader(stream));
```

This looks for a file in `src/resources/data/SAMPLE_CSV_FILENAME` - we will always store runtime
data in these "resources/" folders because gradle understands how to keep files correctly updated
in these folders.

- Create a new CSV Reader from the provided Reader
```
CSVReader csvReader = new CSVReader(reader);
```

- Create a String array that stores the next record and read the next record
```
String[] nextRecord = csvReader.readNext();
```

- Print the nextRecord until all records have been printed
```
while (nextRecord != null) {
    System.out.println("Name : " + nextRecord[0]);
    System.out.println("Email : " + nextRecord[1]);
    System.out.println("==========================");
    nextRecord = csvReader.readNext();
}
```

You can run the given example with the `runSimpleParser` and
`runSimpleParserDemo` tasks for your implementation and the
provided code respectively.

## parseWithModel

Steps to complete:
- Add the following fields to `UserModel.java` 
    * name
    * email

- Create a getter and setter for all the fields in `UserModel.java`

- Get an input stream from the file and construct a BufferedReader with it.
- When using this code elsewhere, don't forget to replace "ModelDataParser.class" with whatever
class you're currently inside.
```
InputStream stream = ModelDataParser.class.getResourceAsStream("/data/" + SAMPLE_CSV_FILENAME);
if(stream == null) {
    System.err.println("File not found: " + CSV_FILENAME);
    System.exit(1);
}
Reader reader = new BufferedReader(new InputStreamReader(stream));
```

This looks for a file in `src/resources/data/SAMPLE_CSV_FILENAME` - we will always store runtime
data in these "resources/" folders because gradle understands how to keep files correctly updated
in these folders.

- Create a CsvToBean using the reader, type and ignoring leading white space
```
CsvToBean<UserModel> csvToBean = new CsvToBeanBuilder<UserModel>(reader)
                    .withType(UserModel.class)
                    .withIgnoreLeadingWhiteSpace(true)
                    .build();
```


- Create iterator over the bean
```
Iterator<UserModel> csvUserIterator = csvToBean.iterator();
```

- Run a loop over the iterator
```
while (csvUserIterator.hasNext()) {
    UserModel csvUser = csvUserIterator.next();
    System.out.println("Name : " + csvUser.getName());
    System.out.println("Email : " + csvUser.getEmail());
    System.out.println("==========================");
}
```

You can run the given example with the `runParseWithModel` and
`runParseWithModelDemo` tasks for your implementation and the
provided code respectively.

## parseInteresting

Steps to complete:
- Add the following fields to `UfoSightingModel.java` 
    * state
    * country
    * shape
    * comments
    
- Create a getter and setter for all the fields in `UfoSightingModel.java`

- Perform aggregatations on the collected data. Below is an
example for code that prints the states in reverse order of
the number of sightings:

```
Map<String, Integer> stateUfoObservations = new HashMap<>();

while (csvUserIterator.hasNext()) {
    UfoSightingModel ufoSightingRecord = csvUserIterator.next();
    String country = ufoSightingRecord.getCountry();
    if(!country.equals("us")) {
        continue;
    }

    String state = ufoSightingRecord.getState();
    if(!stateUfoObservations.containsKey(state)) {
        stateUfoObservations.put(state, 0);
    }
    stateUfoObservations.put(state, stateUfoObservations.get(state) + 1);
}

Map<Integer, Set<String>> observationsToStateReverseOrdered = new TreeMap<>(Collections.reverseOrder());

for(String state : stateUfoObservations.keySet()) {
    int observations = stateUfoObservations.get(state);
    if(!observationsToStateReverseOrdered.containsKey(observations)) {
        observationsToStateReverseOrdered.put(observations, new HashSet<>());
    }
    observationsToStateReverseOrdered.get(observations).add(state);
}

System.out.println(observationsToStateReverseOrdered);
```

You can run the given example with the `runParseInteresting` and
`runParseInterestingDemo` tasks for your implementation and the
provided code respectively.