<commit_before>package uml_alerts.uml_alerts;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarActivity;
import android.telephony.SmsManager;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;

import com.opencsv.CSVReader;
import com.opencsv.CSVWriter;

import java.io.FileReader;
import java.io.FileWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 *      Known bugs:
 *
 *      1. onCreate is causing duplicate contacts in the "AddAlert" screen.
 *      2. There is also duplicates in the previous alerts section... wtf.
 *
 */


public class MainActivity extends ActionBarActivity
        implements NavigationDrawerFragment.NavigationDrawerCallbacks {

    // Used to store the last screen title. For use in {@link #restoreActionBar()}.
    private CharSequence mTitle;

    // Google Maps base URL
    private static final String maps_URL = "http://maps.google.com/maps?z=1&h=m&q=loc:";

    // Const file name for the CSV file.
    private static final String CSV_FILE = "alerts.csv";
    private static final String MAPS_FILE = "maps.csv";

    // App Log Tag.
    private static final String APP_TAG = "UML ALERTS";

    // Map for the Alerts.
    // Key: Phone Number (in String form) - separated by newlines for multiple numbers.
    // Value: Message
    Map<String, String> alerts_list = new HashMap<>();

    // Map for the contacts
    // Key: Name
    // Value: Phone Number
    ArrayList<HashMap<String, String>> contactData;

    // Map for the previous alerts
    // Key: date
    // Value: location
    ArrayList<HashMap<String, String>> alerts_map;

    // ListView to display the alerts.
    ListView alert_list;

    // ListView to display the contacts
    ListView contacts_list;

    // ListView to display the previous alerts.
    ListView previous_list;

    // Adapter for the ListView.
    SimpleAdapter list_adapter;

    // ArrayList for the ListView
    List<Map<String, String>> list;

    // Add Alert button
    Button addAlertButton;

    // User input variables from the dialog for entering a phone number / message
    String mMessage = "";
    String mPhone = "";

    // Location Manager.
    GPSTracker gps;


    /**
     *      Android related methods are at the top.
     *      Other app related methods are below the Android stuff.
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Logcat, one for every function / method.
        Log.v(APP_TAG, "Starting onCreate()...");

        // Fragment managing the behaviors, interactions and presentation of the navigation drawer.
        NavigationDrawerFragment mNavigationDrawerFragment = (NavigationDrawerFragment)
                getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
        mTitle = getTitle();

        // Set up the drawer.
        mNavigationDrawerFragment.setUp(
                R.id.navigation_drawer,
                (DrawerLayout) findViewById(R.id.drawer_layout));

        // Loads the ListView up with alerts.
        createAlerts();

        // ********************************
        //  Below this is the button code.
        // ********************************
        addAlertButton = (Button) findViewById(R.id.AddAlertButton);
        addAlertButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                AddAlert();
            }
        });

        // Setup the alerts_map list.
        alerts_map = new ArrayList<>();

        try {
            // Try and open / read from the CSV file.
            OpenCSV();
        } catch (Exception e) {
            // Do stuff with the exception.
            Log.v(APP_TAG, "Couldn't open CSV file!", e);
        }

        // Setup the location stuff.
        gps = new GPSTracker(this);
        if(gps.canGetLocation()) {
            double latitude = gps.getLatitude();
            double longitude = gps.getLongitude();

            // Show location to logcat.
            Log.v("onCreate()", "Your Location is - \nLat: " + latitude + "\nLong: " + longitude);

        }else{
            // Can't get location
            // GPS or Network is not enabled
            // Ask user to enable GPS/network in settings
            gps.showSettingsAlert();
        }

        // Get the contact data into the ArrayList.
        getContacts();
    }


    @Override
    public void onPause() {
        super.onPause();  // Always call the superclass method first

        Log.v(APP_TAG, "Starting onPause()...");

        // Call the SaveCSV function to save the map data to a CSV file.
        try {
            SaveCSV();
        } catch (Exception e) {
            // Write exception to logcat.
            Log.v(APP_TAG, "Error! Couldn't save file to CSV!", e);
        }

        // Stop listening to the location.
        gps.stopUsingGPS();
    }


    @Override
    public void onResume() {
        super.onResume();  // Always call the superclass method first
        Log.v(APP_TAG, "Starting onResume()...");

        getContacts();

        try {
            // Try and open / read from the CSV file.
            OpenCSV();
        } catch (Exception e) {
            // Do stuff with the exception.
            Log.v(APP_TAG, "Couldn't open CSV file!", e);
        }

        // Update the location.
        if(gps.canGetLocation()) {
            double latitude = gps.getLatitude();
            double longitude = gps.getLongitude();

            // Show location to logcat.
//            Toast.makeText(getApplicationContext(), "Your Location is - \nLat: " + latitude + "\nLong: " + longitude, Toast.LENGTH_LONG).show();
            Log.v("onCreate()", "Your Location is - \nLat: " + latitude + "\nLong: " + longitude);

        }else{
            // can't get location
            // GPS or Network is not enabled
            // Ask user to enable GPS/network in settings
            gps.showSettingsAlert();
        }

        // Setup the alerts_map list.
        //alerts_map = new ArrayList<>();
    }


    // This is for the sidebar drawer
    @Override
    public void onNavigationDrawerItemSelected(int position) {
        // update the main content by replacing fragments
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction()
                .replace(R.id.container, PlaceholderFragment.newInstance(position + 1))
                .commit();
    }


    // This is for the sidebar drawer
    public void onSectionAttached(int number) {
        switch (number) {
            case 1:
                // This sets up the alerts view.
                mTitle = getString(R.string.title_section1);
                createAlerts();
                break;
            case 2:
                // This sets up the contacts view.
                mTitle = getString(R.string.title_section2);
                createContacts();
                break;
            case 3:
                // This sets up the previous alerts view
                mTitle = getString(R.string.title_section3);
                createPreviousAlerts();
                break;
            case 4:
                // This sets up the google maps view.
                mTitle = getString(R.string.title_section4);
                launchMaps();
                break;
            case 5:
                // This loads the about page.
                mTitle = getString(R.string.title_section5);
                viewAbout();
                break;
        }
    }


    public void launchMaps() {
        Log.v(APP_TAG, "Starting Google Maps View...");

        // Launches a new activity.
        Intent myIntent = new Intent(MainActivity.this, GoogleMaps.class);
        startActivity(myIntent);
    }


    // Launches the About activity
    public void viewAbout() {
        Log.v(APP_TAG, "Starting viewAbout()...");

        // Launches a new activity.
        Intent myIntent = new Intent(MainActivity.this, About.class);
        MainActivity.this.startActivity(myIntent);
    }


    // Open data from a CSV file, save to the map.
    public void OpenCSV() throws Exception {
        // Opening CSV file log.
        Log.v(APP_TAG, "Starting OpenCSV()...");

        // The first part opens the alerts data from a CSV file called "alerts.csv"
        // Get path for storing / accessing the CSV file.
        String csv_path = android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + CSV_FILE;

        // Open data from the CSV file
        String line[];

        // Build an instance of the CSVReader class. Give it the CSV file's name.
        CSVReader reader = new CSVReader(new FileReader(csv_path));

        // Read all the data off the CSV file.
        line = reader.readNext();

        while (line != null) {
            // This gets the line and splits it based on the comma.
            List<String> container = Arrays.asList(line);

            // This gets the key / value from the List container.
            String key = container.get(0);
            String value = container.get(1);

            // Add to the map.
            alerts_list.put(key, value);

            // Get the next line.
            line = reader.readNext();
        }

        // This second part opens the map data from a CSV file called "maps.csv"
        // Get path for storing / accessing the CSV file.
        csv_path = android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + MAPS_FILE;

        // Open data from the CSV file
        String lines[];

        // Build an instance of the CSVReader class. Give it the CSV file's name.
        reader = new CSVReader(new FileReader(csv_path));

        // Read all the data off the CSV file.
        lines = reader.readNext();

        while (lines != null) {
            // This gets the line and splits it based on the comma.
            List<String> container = Arrays.asList(lines);

            // This gets the key / value from the List container.
            String key = container.get(0);
            String value = container.get(1);

            // Debugging
            Log.v("Key is: ", key);
            Log.v("Value is: ", value);

            HashMap<String, String> map = new HashMap<>();
            map.put("date", key);
            map.put("location", value);
            alerts_map.add(map);

            // Get the next line.
            lines = reader.readNext();
        }

        // Remove duplicates from the ArrayList by adding it to a Set.
        Set<HashMap<String, String>> tmp = new HashSet<>();

        // THIS WILL REMOVE ALL DUPLICATES FROM THE ARRAYLIST.
        tmp.addAll(alerts_map);
        alerts_map.clear();
        alerts_map.addAll(tmp);

        // Now update the alerts view.
        updateListView();
    }


    // Read from CSV file into local map variable.
    public void SaveCSV() throws Exception {
        // Opening CSV file log.
        Log.v(APP_TAG, "Starting SaveCSV()...");

        // The first part saves the alerts data to a CSV file called "alerts.csv"
        // Get path for storing / accessing the CSV file.
        String csv_path = android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + CSV_FILE;

        // Create an instance of the CSVWriter class. Give it the CSV file's name.
        CSVWriter writer = new CSVWriter(new FileWriter(csv_path));

        // While we've got a valid thing in the map.
        for (Map.Entry<String, String> entry : alerts_list.entrySet()) {
            // Now pair will have a key / value that we can save.
            String key = entry.getKey();
            String value = entry.getValue();
            String next = key + "," + value;

            String[] cur_alert = next.split(",");
            writer.writeNext(cur_alert);
        }

        // Close the writer.
        writer.close();

        // This second part saves the map data to a CSV file called "maps.csv"
        // Get path for storing / accessing the CSV file.
        csv_path = android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + MAPS_FILE;

        // Create an instance of the CSVWriter class. Give it the CSV file's name.
        writer = new CSVWriter(new FileWriter(csv_path));

        String date, location;

        for (int a = 0; a < alerts_map.size(); a++) {
            HashMap<String, String> tmpData = alerts_map.get(a);

            date = tmpData.get("date");
            location = tmpData.get("location");
            String next = date + "," + location;

            Log.v("Testing current pair: ", next);

            String[] cur_alert = next.split(",");
            writer.writeNext(cur_alert);
        }

        /*
        HashMap<String, String> map = new HashMap<>();
        map.put("date", key);
        map.put("location", value);
        alerts_map.add(map);

        // While we've got a valid thing in the map.
        for (Map.Entry<String, String> entry : alerts_map.entrySet()) {
            // Now pair will have a key / value that we can save.
            String key = entry.getKey();
            String value = entry.getValue();
            String next = key + "," + value;

            String[] cur_alert = next.split(",");
            writer.writeNext(cur_alert);
        }*/

        // Close the writer.
        writer.close();
    }


    // This builds up the alerts ArrayList
    private ArrayList<Map<String, String>> buildData() {
        // This will at some point pull from the alerts_list map!
        // For now it is hard coded for testing purposes.
        Log.v(APP_TAG, "Starting buildData()...");

        ArrayList<Map<String, String>> tmp_list = new ArrayList<>();

        for (Map.Entry<String, String> entry : alerts_list.entrySet()) {
            tmp_list.add(putData(entry.getKey(), entry.getValue()));
        }

        return tmp_list;
    }


    // This is used by the above buildData as a helper method to generate the ArrayList
    // from the alerts map.
    private HashMap<String, String> putData(String phone_number, String alert) {
        Log.v(APP_TAG, "Starting putData()...");

        HashMap<String, String> item = new HashMap<>();
        item.put("phone_number", phone_number);
        item.put("alert", alert);
        return item;
    }


    // Technically this just redoes the list view stuff.
    // Don't really need this method if we're going to do it the lazy way.
    public void updateListView() {
        Log.v(APP_TAG, "Starting updateListView()...");
        createAlerts();
    }


    // Adds all the alerts to the list view.
    private void createAlerts() {
        Log.v("createListView", "Starting createListView()...");

        // Get the list view from the XML file.
        alert_list = (ListView) findViewById(R.id.listView);

        // Onclick listener for the alerts.
        alert_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                // Get the phone number(s) and the alert from the ListView
                Object obj = (alert_list.getItemAtPosition(position));
                HashMap<String, String> item = (HashMap<String, String>) obj;
                String phoneNumber = item.get("phone_number");
                String alert = item.get("alert");

                sendSMSMessage(phoneNumber, alert);
            }
        });

        // Long click listener for deleting alerts
        alert_list.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {

                // Make a popup to confirm if the user actually wants to delete this alert.
                AlertDialog.Builder deleteAlert = new AlertDialog.Builder(MainActivity.this);

                deleteAlert.setMessage("Remove this alert?");
                deleteAlert.setPositiveButton("DELETE", new AlertDialog.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        // Get the phone number(s) from the ListView
                        Object obj = (alert_list.getItemAtPosition(position));
                        HashMap<String, String> item = (HashMap<String, String>) obj;
                        String phoneNumber = item.get("phone_number");

                        Log.v("Deleting phone number: ", phoneNumber);

                        // Delete the alert from the map.
                        for(Iterator<Map.Entry<String, String>> it = alerts_list.entrySet().iterator(); it.hasNext(); ) {
                            Map.Entry<String, String> entry = it.next();

                            // Only remove the alert with the matching phone number!
                            if (entry.getValue().equals(phoneNumber)) {
                                it.remove();
                            }
                        }

                        // Now refresh the ListView's adapter.
                        alerts_list.remove(phoneNumber);
                        list_adapter.notifyDataSetChanged();
                        createAlerts();
                    }

                }).setNegativeButton("CANCEL", new AlertDialog.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        // Does nothing but cancel the delete alert.
                    }
                });

                // Display the dialog.
                deleteAlert.show();

                return false;
            }
        });

        // Setup the Add alerts button.
        addAlertButton = (Button) findViewById(R.id.AddAlertButton);
        addAlertButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                AddAlert();
            }
        });

        // Sort the alerts.
        alerts_list = sortByKeys(alerts_list);

        // Create a list of two items.
        // One is the user's phone number.
        // The other is the alert message.
        list = buildData();

        // From is a list of Key's.
        // to is an array of IDs for the strings.
        String[] from = {"phone_number", "alert"};
        int[] to = {android.R.id.text1, android.R.id.text2};

        // Simple adapter is all we need for this.
        list_adapter = new SimpleAdapter(this, list, android.R.layout.simple_list_item_2, from, to);
        alert_list.setAdapter(list_adapter);
    }


    // This alerts an alert to the map, and onPause saves the map data to a csv file.
    // Makes a simple alert dialog with its own view stuff.
    public void AddAlert() {
        Log.i(APP_TAG, "Starting AddAlert()...");

        // Text entry dialog.
        AlertDialog.Builder text_entry = new AlertDialog.Builder(this);
<commit_msg>I think the app is done. Yay.<commit_after>package uml_alerts.uml_alerts;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarActivity;
import android.telephony.SmsManager;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;

import com.opencsv.CSVReader;
import com.opencsv.CSVWriter;

import java.io.FileReader;
import java.io.FileWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 *      Known bugs:
 *
 *      1. onCreate is causing duplicate contacts in the "AddAlert" screen.
 *      2. There is also duplicates in the previous alerts section... wtf.
 *
 */


public class MainActivity extends ActionBarActivity
        implements NavigationDrawerFragment.NavigationDrawerCallbacks {

    // Used to store the last screen title. For use in {@link #restoreActionBar()}.
    private CharSequence mTitle;

    // Google Maps base URL
    private static final String maps_URL = "http://maps.google.com/maps?z=1&h=m&q=loc:";

    // Const file name for the CSV file.
    private static final String CSV_FILE = "alerts.csv";
    private static final String MAPS_FILE = "maps.csv";

    // App Log Tag.
    private static final String APP_TAG = "UML ALERTS";

    // Map for the Alerts.
    // Key: Phone Number (in String form) - separated by newlines for multiple numbers.
    // Value: Message
    Map<String, String> alerts_list = new HashMap<>();

    // Map for the contacts
    // Key: Name
    // Value: Phone Number
    ArrayList<HashMap<String, String>> contactData;

    // Map for the previous alerts
    // Key: date
    // Value: location
    ArrayList<HashMap<String, String>> alerts_map;

    // ListView to display the alerts.
    ListView alert_list;

    // ListView to display the contacts
    ListView contacts_list;

    // ListView to display the previous alerts.
    ListView previous_list;

    // Adapter for the ListView.
    SimpleAdapter list_adapter;

    // ArrayList for the ListView
    List<Map<String, String>> list;

    // Add Alert button
    Button addAlertButton;

    // User input variables from the dialog for entering a phone number / message
    String mMessage = "";
    String mPhone = "";

    // Location Manager.
    GPSTracker gps;


    /**
     *      Android related methods are at the top.
     *      Other app related methods are below the Android stuff.
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Logcat, one for every function / method.
        Log.v(APP_TAG, "Starting onCreate()...");

        // Fragment managing the behaviors, interactions and presentation of the navigation drawer.
        NavigationDrawerFragment mNavigationDrawerFragment = (NavigationDrawerFragment)
                getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
        mTitle = getTitle();

        // Set up the drawer.
        mNavigationDrawerFragment.setUp(
                R.id.navigation_drawer,
                (DrawerLayout) findViewById(R.id.drawer_layout));

        // Loads the ListView up with alerts.
        createAlerts();

        // ********************************
        //  Below this is the button code.
        // ********************************
        addAlertButton = (Button) findViewById(R.id.AddAlertButton);
        addAlertButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                AddAlert();
            }
        });

        // Setup the alerts_map list.
        alerts_map = new ArrayList<>();

        try {
            // Try and open / read from the CSV file.
            OpenCSV();
        } catch (Exception e) {
            // Do stuff with the exception.
            Log.v(APP_TAG, "Couldn't open CSV file!", e);
        }

        // Setup the location stuff.
        gps = new GPSTracker(this);
        if(gps.canGetLocation()) {
            double latitude = gps.getLatitude();
            double longitude = gps.getLongitude();

            // Show location to logcat.
            Log.v("onCreate()", "Your Location is - \nLat: " + latitude + "\nLong: " + longitude);

        }else{
            // Can't get location
            // GPS or Network is not enabled
            // Ask user to enable GPS/network in settings
            gps.showSettingsAlert();
        }

        // Get the contact data into the ArrayList.
        getContacts();
    }


    @Override
    public void onPause() {
        super.onPause();  // Always call the superclass method first

        Log.v(APP_TAG, "Starting onPause()...");

        // Call the SaveCSV function to save the map data to a CSV file.
        try {
            SaveCSV();
        } catch (Exception e) {
            // Write exception to logcat.
            Log.v(APP_TAG, "Error! Couldn't save file to CSV!", e);
        }

        // Stop listening to the location.
        gps.stopUsingGPS();
    }


    @Override
    public void onResume() {
        super.onResume();  // Always call the superclass method first
        Log.v(APP_TAG, "Starting onResume()...");

        getContacts();

        try {
            // Try and open / read from the CSV file.
            OpenCSV();
        } catch (Exception e) {
            // Do stuff with the exception.
            Log.v(APP_TAG, "Couldn't open CSV file!", e);
        }

        // Update the location.
        if(gps.canGetLocation()) {
            double latitude = gps.getLatitude();
            double longitude = gps.getLongitude();

            // Show location to logcat.
//            Toast.makeText(getApplicationContext(), "Your Location is - \nLat: " + latitude + "\nLong: " + longitude, Toast.LENGTH_LONG).show();
            Log.v("onCreate()", "Your Location is - \nLat: " + latitude + "\nLong: " + longitude);

        }else{
            // can't get location
            // GPS or Network is not enabled
            // Ask user to enable GPS/network in settings
            gps.showSettingsAlert();
        }

        // Setup the alerts_map list.
        //alerts_map = new ArrayList<>();
    }


    // This is for the sidebar drawer
    @Override
    public void onNavigationDrawerItemSelected(int position) {
        // update the main content by replacing fragments
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction()
                .replace(R.id.container, PlaceholderFragment.newInstance(position + 1))
                .commit();
    }


    // This is for the sidebar drawer
    public void onSectionAttached(int number) {
        switch (number) {
            case 1:
                // This sets up the alerts view.
                mTitle = getString(R.string.title_section1);
                createAlerts();
                break;
            case 2:
                // This sets up the contacts view.
                mTitle = getString(R.string.title_section2);
                createContacts();
                break;
            case 3:
                // This sets up the previous alerts view
                mTitle = getString(R.string.title_section3);
                createPreviousAlerts();
                break;
            case 4:
                // This sets up the google maps view.
                mTitle = getString(R.string.title_section4);
                launchMaps();
                break;
            case 5:
                // This loads the about page.
                mTitle = getString(R.string.title_section5);
                viewAbout();
                break;
        }
    }


    public void launchMaps() {
        Log.v(APP_TAG, "Starting Google Maps View...");

        // Launches a new activity.
        Intent myIntent = new Intent(MainActivity.this, GoogleMaps.class);
        startActivity(myIntent);
    }


    // Launches the About activity
    public void viewAbout() {
        Log.v(APP_TAG, "Starting viewAbout()...");

        // Launches a new activity.
        Intent myIntent = new Intent(MainActivity.this, About.class);
        MainActivity.this.startActivity(myIntent);
    }


    // Open data from a CSV file, save to the map.
    public void OpenCSV() throws Exception {
        // Opening CSV file log.
        Log.v(APP_TAG, "Starting OpenCSV()...");

        // The first part opens the alerts data from a CSV file called "alerts.csv"
        // Get path for storing / accessing the CSV file.
        String csv_path = android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + CSV_FILE;

        // Open data from the CSV file
        String line[];

        // Build an instance of the CSVReader class. Give it the CSV file's name.
        CSVReader reader = new CSVReader(new FileReader(csv_path));

        // Read all the data off the CSV file.
        line = reader.readNext();

        while (line != null) {
            // This gets the line and splits it based on the comma.
            List<String> container = Arrays.asList(line);

            // This gets the key / value from the List container.
            String key = container.get(0);
            String value = container.get(1);

            // Add to the map.
            alerts_list.put(key, value);

            // Get the next line.
            line = reader.readNext();
        }

        // This second part opens the map data from a CSV file called "maps.csv"
        // Get path for storing / accessing the CSV file.
        csv_path = android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + MAPS_FILE;

        // Open data from the CSV file
        String lines[];

        // Build an instance of the CSVReader class. Give it the CSV file's name.
        reader = new CSVReader(new FileReader(csv_path));

        // Read all the data off the CSV file.
        lines = reader.readNext();

        while (lines != null) {
            // This gets the line and splits it based on the comma.
            List<String> container = Arrays.asList(lines);

            // This gets the key / value from the List container.
            String key = container.get(0);
            String value = container.get(1);

            // Debugging
            Log.v("Key is: ", key);
            Log.v("Value is: ", value);

            HashMap<String, String> map = new HashMap<>();
            map.put("date", key);
            map.put("location", value);
            alerts_map.add(map);

            // Get the next line.
            lines = reader.readNext();
        }

        // Remove duplicates from the ArrayList by adding it to a Set.
        Set<HashMap<String, String>> tmp = new HashSet<>();

        // THIS WILL REMOVE ALL DUPLICATES FROM THE ARRAYLIST.
        tmp.addAll(alerts_map);
        alerts_map.clear();
        alerts_map.addAll(tmp);

        // Now update the alerts view.
        updateListView();
    }


    // Read from CSV file into local map variable.
    public void SaveCSV() throws Exception {
        // Opening CSV file log.
        Log.v(APP_TAG, "Starting SaveCSV()...");

        // The first part saves the alerts data to a CSV file called "alerts.csv"
        // Get path for storing / accessing the CSV file.
        String csv_path = android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + CSV_FILE;

        // Create an instance of the CSVWriter class. Give it the CSV file's name.
        CSVWriter writer = new CSVWriter(new FileWriter(csv_path));

        // While we've got a valid thing in the map.
        for (Map.Entry<String, String> entry : alerts_list.entrySet()) {
            // Now pair will have a key / value that we can save.
            String key = entry.getKey();
            String value = entry.getValue();
            String next = key + "," + value;

            String[] cur_alert = next.split(",");
            writer.writeNext(cur_alert);
        }

        // Close the writer.
        writer.close();

        // This second part saves the map data to a CSV file called "maps.csv"
        // Get path for storing / accessing the CSV file.
        csv_path = android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + MAPS_FILE;

        // Create an instance of the CSVWriter class. Give it the CSV file's name.
        writer = new CSVWriter(new FileWriter(csv_path));

        String date, location;

        for (int a = 0; a < alerts_map.size(); a++) {
            HashMap<String, String> tmpData = alerts_map.get(a);

            date = tmpData.get("date");
            location = tmpData.get("location");
            String next = date + "," + location;

            Log.v("Testing current pair: ", next);

            String[] cur_alert = next.split(",");
            writer.writeNext(cur_alert);
        }

        // Close the writer.
        writer.close();
    }


    // This builds up the alerts ArrayList
    private ArrayList<Map<String, String>> buildData() {
        // This will at some point pull from the alerts_list map!
        // For now it is hard coded for testing purposes.
        Log.v(APP_TAG, "Starting buildData()...");

        ArrayList<Map<String, String>> tmp_list = new ArrayList<>();

        for (Map.Entry<String, String> entry : alerts_list.entrySet()) {
            tmp_list.add(putData(entry.getKey(), entry.getValue()));
        }

        return tmp_list;
    }


    // This is used by the above buildData as a helper method to generate the ArrayList
    // from the alerts map.
    private HashMap<String, String> putData(String phone_number, String alert) {
        Log.v(APP_TAG, "Starting putData()...");

        HashMap<String, String> item = new HashMap<>();
        item.put("phone_number", phone_number);
        item.put("alert", alert);
        return item;
    }


    // Technically this just redoes the list view stuff.
    // Don't really need this method if we're going to do it the lazy way.
    public void updateListView() {
        Log.v(APP_TAG, "Starting updateListView()...");
        createAlerts();
    }


    // Adds all the alerts to the list view.
    private void createAlerts() {
        Log.v("createListView", "Starting createListView()...");

        // Get the list view from the XML file.
        alert_list = (ListView) findViewById(R.id.listView);

        // Onclick listener for the alerts.
        alert_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                // Get the phone number(s) and the alert from the ListView
                Object obj = (alert_list.getItemAtPosition(position));
                HashMap<String, String> item = (HashMap<String, String>) obj;
                String phoneNumber = item.get("phone_number");
                String alert = item.get("alert");

                sendSMSMessage(phoneNumber, alert);
            }
        });

        // Long click listener for deleting alerts
        alert_list.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {

                // Make a popup to confirm if the user actually wants to delete this alert.
                AlertDialog.Builder deleteAlert = new AlertDialog.Builder(MainActivity.this);

                deleteAlert.setMessage("Remove this alert?");
                deleteAlert.setPositiveButton("DELETE", new AlertDialog.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        // Get the phone number(s) from the ListView
                        Object obj = (alert_list.getItemAtPosition(position));
                        HashMap<String, String> item = (HashMap<String, String>) obj;
                        String phoneNumber = item.get("phone_number");

                        Log.v("Deleting phone number: ", phoneNumber);

                        // Delete the alert from the map.
                        for(Iterator<Map.Entry<String, String>> it = alerts_list.entrySet().iterator(); it.hasNext(); ) {
                            Map.Entry<String, String> entry = it.next();

                            // Only remove the alert with the matching phone number!
                            if (entry.getValue().equals(phoneNumber)) {
                                it.remove();
                            }
                        }

                        // Now refresh the ListView's adapter.
                        alerts_list.remove(phoneNumber);
                        list_adapter.notifyDataSetChanged();
                        createAlerts();
                    }

                }).setNegativeButton("CANCEL", new AlertDialog.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        // Does nothing but cancel the delete alert.
                    }
                });

                // Display the dialog.
                deleteAlert.show();

                return false;
            }
        });

        // Setup the Add alerts button.
        addAlertButton = (Button) findViewById(R.id.AddAlertButton);
        addAlertButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                AddAlert();
            }
        });

        // Sort the alerts.
        alerts_list = sortByKeys(alerts_list);

        // Create a list of two items.
        // One is the user's phone number.
        // The other is the alert message.
        list = buildData();

        // From is a list of Key's.
        // to is an array of IDs for the strings.
        String[] from = {"phone_number", "alert"};
        int[] to = {android.R.id.text1, android.R.id.text2};

        // Simple adapter is all we need for this.
        list_adapter = new SimpleAdapter(this, list, android.R.layout.simple_list_item_2, from, to);
        alert_list.setAdapter(list_adapter);
    }


    // This alerts an alert to the map, and onPause saves the map data to a csv file.
    // Makes a simple alert dialog with its own view stuff.
    public void AddAlert() {
        Log.i(APP_TAG, "Starting AddAlert()...");

        // Remove duplicates from the contactsData ArrayList by adding it to a Set.
        Set<HashMap<String, String>> tmp = new HashSet<>();

        // THIS WILL REMOVE ALL DUPLICATES FROM THE ARRAY LIST.
        tmp.addAll(contactData);
        contactData.clear();
        contactData.addAll(tmp);

        // Text entry dialog.
        AlertDialog.Builder text_entry = new AlertDialog.Builder(this);

{'fraction_non_alphanumeric': 0.10375049940071913, 'fraction_numerical': 0.0012984418697562924, 'mean_word_length': 1.952812799528128, 'pattern_counts': {'":': 0, '<': 85, '<?xml version=': 0, '>': 83, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1116389', 'n_tokens_mistral': 10901, 'n_tokens_neox': 10195, 'n_words': 3322}