<commit_before>package org.mitre.synthea.export;

import static org.mitre.synthea.export.ExportHelper.dateFromTimestamp;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Path;
import java.util.UUID;

import org.mitre.synthea.world.agents.Person;
import org.mitre.synthea.world.concepts.HealthRecord;
import org.mitre.synthea.world.concepts.HealthRecord.CarePlan;
import org.mitre.synthea.world.concepts.HealthRecord.Code;
import org.mitre.synthea.world.concepts.HealthRecord.Encounter;
import org.mitre.synthea.world.concepts.HealthRecord.Entry;
import org.mitre.synthea.world.concepts.HealthRecord.Medication;
import org.mitre.synthea.world.concepts.HealthRecord.Observation;
import org.mitre.synthea.world.concepts.HealthRecord.Procedure;

/**
 * Researchers have requested a simple table-based format 
 * that could easily be imported into any database for analysis. 
 * Unlike other formats which export a single record per patient, 
 * this format generates 9 total files, 
 * and adds lines to each based on the clinical events for each patient. 
 * These files are intended to be analogous to database tables, 
 * with the patient UUID being a foreign key. 
 * Files include: 
 * patients.csv, encounters.csv, allergies.csv, 
 * medications.csv, conditions.csv, careplans.csv, 
 * observations.csv, procedures.csv, and immunizations.csv .
 * 
 * Sample:  
 * - patients.csv <pre>
 * ID,BIRTHDATE,DEATHDATE,SSN,DRIVERS,PASSPORT,PREFIX,FIRST,LAST,SUFFIX,MAIDEN,MARITAL,RACE,ETHNICITY,GENDER,BIRTHPLACE,ADDRESS
 * 5e0d195e-1cd9-494d-8f9a-757c15da2aed,1946-12-14,2015-10-03,999-12-2377,S99962866,false,Mrs.,Miracle267,Ledner332,,Raynor597,M,white,irish,F,Millbury MA,2502 Fisher Manor Boston MA 02132
 * 52082709-06ce-4fde-9c93-cfb4e6542ae1,1968-05-23,,999-17-1808,S99941406,X41451685X,Mrs.,Alda869,Gorczany848,,Funk527,M,white,italian,F,Gardner MA,46973 Velda Gateway Franklin Town MA 02038
 * 8b4c62c8-b116-4b58-9259-466485b0345c,1967-06-22,1985-07-04,999-11-1173,S99955795,,Ms.,Moshe832,Zulauf396,,,,white,english,F,Boston MA,250 Reba Park Carver MA 02330
 * 965c5539-598b-4a9b-a670-e0259667deb8,1934-11-04,2015-06-19,999-63-2195,S99931866,X71888970X,Mr.,Verla554,Roberts329,,,S,white,irish,M,Fall River MA,321 Abdullah Bridge Needham MA 02492
 * 2b28d6c3-9e0c-48d4-99f9-292488133101,1964-08-13,,999-55-5054,S99990374,X68574707X,Ms.,Henderson277,Labadie810,,,S,black,dominican,F,North Attleborough MA,55825 Barrows Prairie Suite 144 Boston MA 02134
 * </pre>
 * 
 * - conditions.csv <pre>
 * START,STOP,PATIENT,ENCOUNTER,CODE,DESCRIPTION
 * 1965-10-10,,5e0d195e-1cd9-494d-8f9a-757c15da2aed,918b17f4-e815-44ef-9eeb-41953bbcf7e9,38341003,Hypertension
 * 1966-09-09,,5e0d195e-1cd9-494d-8f9a-757c15da2aed,918b17f4-e815-44ef-9eeb-41953bbcf7e9,15777000,Prediabetes
 * 1988-09-25,,5e0d195e-1cd9-494d-8f9a-757c15da2aed,918b17f4-e815-44ef-9eeb-41953bbcf7e9,239872002,Osteoarthritis of hip
 * 1990-09-01,,5e0d195e-1cd9-494d-8f9a-757c15da2aed,918b17f4-e815-44ef-9eeb-41953bbcf7e9,410429000,Cardiac Arrest
 * </pre>
 */
public class CSVExporter {
  /**
   * Writer for patients.csv.
   */
	private FileWriter patients;
  /**
   * Writer for allergies.csv.
   */
	private FileWriter allergies;
  /**
   * Writer for medications.csv.
   */
	private FileWriter medications;
  /**
   * Writer for conditions.csv.
   */
	private FileWriter conditions;
  /**
   * Writer for careplans.csv.
   */
	private FileWriter careplans;
  /**
   * Writer for observations.csv.
   */
	private FileWriter observations;
  /**
   * Writer for procedures.csv.
   */
	private FileWriter procedures;
  /**
   * Writer for immunizations.csv.
   */
	private FileWriter immunizations;
  /**
   * Writer for encounters.csv.
   */
	private FileWriter encounters;
	
	/**
	 * System-dependent string for a line break. (\n on Mac, *nix, \r\n on Windows)
	 */
	private static final String NEWLINE = System.lineSeparator();
	
	/**
	 * Constructor for the CSVExporter -
	 *  initialize the 9 specified files and store the writers in fields.
	 */
	private CSVExporter() {
		try {
			File output = Exporter.getOutputFolder("csv", null);
			output.mkdirs();
			Path outputDirectory = output.toPath();
			File patientsFile = outputDirectory.resolve("patients.csv").toFile();
			File allergiesFile = outputDirectory.resolve("allergies.csv").toFile();
			File medicationsFile = outputDirectory.resolve("medications.csv").toFile();
			File conditionsFile = outputDirectory.resolve("conditions.csv").toFile();
			File careplansFile = outputDirectory.resolve("careplans.csv").toFile();
			File observationsFile = outputDirectory.resolve("observations.csv").toFile();
			File proceduresFile = outputDirectory.resolve("procedures.csv").toFile();
			File immunizationsFile = outputDirectory.resolve("immunizations.csv").toFile();
			File encountersFile = outputDirectory.resolve("encounters.csv").toFile();
	
			patients = new FileWriter(patientsFile);
			allergies = new FileWriter(allergiesFile);
			medications = new FileWriter(medicationsFile);
			conditions = new FileWriter(conditionsFile);
			careplans = new FileWriter(careplansFile);
			observations = new FileWriter(observationsFile);
			procedures = new FileWriter(proceduresFile);
			immunizations = new FileWriter(immunizationsFile);
			encounters = new FileWriter(encountersFile);
			writeCSVHeaders();
		} catch (IOException e) {
		  // wrap the exception in a runtime exception.
		  // the singleton pattern below doesn't work if the constructor can throw
		  // and if these do throw ioexceptions there's nothing we can do anyway
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * Write the headers to each of the CSV files.
	 * @throws IOException if any IO error occurs
	 */
	private void writeCSVHeaders() throws IOException {
    patients.write("ID,BIRTHDATE,DEATHDATE,SSN,DRIVERS,PASSPORT,PREFIX,FIRST,LAST,SUFFIX,MAIDEN,MARITAL,RACE,ETHNICITY,GENDER,BIRTHPLACE,ADDRESS\n");
    allergies.write("START,STOP,PATIENT,ENCOUNTER,CODE,DESCRIPTION\n");
    medications.write("START,STOP,PATIENT,ENCOUNTER,CODE,DESCRIPTION,REASONCODE,REASONDESCRIPTION\n");
    conditions.write("START,STOP,PATIENT,ENCOUNTER,CODE,DESCRIPTION\n");
    careplans.write("ID,START,STOP,PATIENT,ENCOUNTER,CODE,DESCRIPTION,REASONCODE,REASONDESCRIPTION\n");
    observations.write("DATE,PATIENT,ENCOUNTER,CODE,DESCRIPTION,VALUE,UNITS\n");
    procedures.write("DATE,PATIENT,ENCOUNTER,CODE,DESCRIPTION,REASONCODE,REASONDESCRIPTION\n");
    immunizations.write("DATE,PATIENT,ENCOUNTER,CODE,DESCRIPTION\n");
    encounters.write("ID,DATE,PATIENT,CODE,DESCRIPTION,REASONCODE,REASONDESCRIPTION\n");
	}
	
	/**
	 *  Thread safe singleton pattern adopted from <commit_msg>fix csv newlines<commit_after>package org.mitre.synthea.export;

import static org.mitre.synthea.export.ExportHelper.dateFromTimestamp;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Path;
import java.util.UUID;

import org.mitre.synthea.world.agents.Person;
import org.mitre.synthea.world.concepts.HealthRecord;
import org.mitre.synthea.world.concepts.HealthRecord.CarePlan;
import org.mitre.synthea.world.concepts.HealthRecord.Code;
import org.mitre.synthea.world.concepts.HealthRecord.Encounter;
import org.mitre.synthea.world.concepts.HealthRecord.Entry;
import org.mitre.synthea.world.concepts.HealthRecord.Medication;
import org.mitre.synthea.world.concepts.HealthRecord.Observation;
import org.mitre.synthea.world.concepts.HealthRecord.Procedure;

/**
 * Researchers have requested a simple table-based format 
 * that could easily be imported into any database for analysis. 
 * Unlike other formats which export a single record per patient, 
 * this format generates 9 total files, 
 * and adds lines to each based on the clinical events for each patient. 
 * These files are intended to be analogous to database tables, 
 * with the patient UUID being a foreign key. 
 * Files include: 
 * patients.csv, encounters.csv, allergies.csv, 
 * medications.csv, conditions.csv, careplans.csv, 
 * observations.csv, procedures.csv, and immunizations.csv .
 * 
 * Sample:  
 * - patients.csv <pre>
 * ID,BIRTHDATE,DEATHDATE,SSN,DRIVERS,PASSPORT,PREFIX,FIRST,LAST,SUFFIX,MAIDEN,MARITAL,RACE,ETHNICITY,GENDER,BIRTHPLACE,ADDRESS
 * 5e0d195e-1cd9-494d-8f9a-757c15da2aed,1946-12-14,2015-10-03,999-12-2377,S99962866,false,Mrs.,Miracle267,Ledner332,,Raynor597,M,white,irish,F,Millbury MA,2502 Fisher Manor Boston MA 02132
 * 52082709-06ce-4fde-9c93-cfb4e6542ae1,1968-05-23,,999-17-1808,S99941406,X41451685X,Mrs.,Alda869,Gorczany848,,Funk527,M,white,italian,F,Gardner MA,46973 Velda Gateway Franklin Town MA 02038
 * 8b4c62c8-b116-4b58-9259-466485b0345c,1967-06-22,1985-07-04,999-11-1173,S99955795,,Ms.,Moshe832,Zulauf396,,,,white,english,F,Boston MA,250 Reba Park Carver MA 02330
 * 965c5539-598b-4a9b-a670-e0259667deb8,1934-11-04,2015-06-19,999-63-2195,S99931866,X71888970X,Mr.,Verla554,Roberts329,,,S,white,irish,M,Fall River MA,321 Abdullah Bridge Needham MA 02492
 * 2b28d6c3-9e0c-48d4-99f9-292488133101,1964-08-13,,999-55-5054,S99990374,X68574707X,Ms.,Henderson277,Labadie810,,,S,black,dominican,F,North Attleborough MA,55825 Barrows Prairie Suite 144 Boston MA 02134
 * </pre>
 * 
 * - conditions.csv <pre>
 * START,STOP,PATIENT,ENCOUNTER,CODE,DESCRIPTION
 * 1965-10-10,,5e0d195e-1cd9-494d-8f9a-757c15da2aed,918b17f4-e815-44ef-9eeb-41953bbcf7e9,38341003,Hypertension
 * 1966-09-09,,5e0d195e-1cd9-494d-8f9a-757c15da2aed,918b17f4-e815-44ef-9eeb-41953bbcf7e9,15777000,Prediabetes
 * 1988-09-25,,5e0d195e-1cd9-494d-8f9a-757c15da2aed,918b17f4-e815-44ef-9eeb-41953bbcf7e9,239872002,Osteoarthritis of hip
 * 1990-09-01,,5e0d195e-1cd9-494d-8f9a-757c15da2aed,918b17f4-e815-44ef-9eeb-41953bbcf7e9,410429000,Cardiac Arrest
 * </pre>
 */
public class CSVExporter {
  /**
   * Writer for patients.csv.
   */
	private FileWriter patients;
  /**
   * Writer for allergies.csv.
   */
	private FileWriter allergies;
  /**
   * Writer for medications.csv.
   */
	private FileWriter medications;
  /**
   * Writer for conditions.csv.
   */
	private FileWriter conditions;
  /**
   * Writer for careplans.csv.
   */
	private FileWriter careplans;
  /**
   * Writer for observations.csv.
   */
	private FileWriter observations;
  /**
   * Writer for procedures.csv.
   */
	private FileWriter procedures;
  /**
   * Writer for immunizations.csv.
   */
	private FileWriter immunizations;
  /**
   * Writer for encounters.csv.
   */
	private FileWriter encounters;
	
	/**
	 * System-dependent string for a line break. (\n on Mac, *nix, \r\n on Windows)
	 */
	private static final String NEWLINE = System.lineSeparator();
	
	/**
	 * Constructor for the CSVExporter -
	 *  initialize the 9 specified files and store the writers in fields.
	 */
	private CSVExporter() {
		try {
			File output = Exporter.getOutputFolder("csv", null);
			output.mkdirs();
			Path outputDirectory = output.toPath();
			File patientsFile = outputDirectory.resolve("patients.csv").toFile();
			File allergiesFile = outputDirectory.resolve("allergies.csv").toFile();
			File medicationsFile = outputDirectory.resolve("medications.csv").toFile();
			File conditionsFile = outputDirectory.resolve("conditions.csv").toFile();
			File careplansFile = outputDirectory.resolve("careplans.csv").toFile();
			File observationsFile = outputDirectory.resolve("observations.csv").toFile();
			File proceduresFile = outputDirectory.resolve("procedures.csv").toFile();
			File immunizationsFile = outputDirectory.resolve("immunizations.csv").toFile();
			File encountersFile = outputDirectory.resolve("encounters.csv").toFile();
	
			patients = new FileWriter(patientsFile);
			allergies = new FileWriter(allergiesFile);
			medications = new FileWriter(medicationsFile);
			conditions = new FileWriter(conditionsFile);
			careplans = new FileWriter(careplansFile);
			observations = new FileWriter(observationsFile);
			procedures = new FileWriter(proceduresFile);
			immunizations = new FileWriter(immunizationsFile);
			encounters = new FileWriter(encountersFile);
			writeCSVHeaders();
		} catch (IOException e) {
		  // wrap the exception in a runtime exception.
		  // the singleton pattern below doesn't work if the constructor can throw
		  // and if these do throw ioexceptions there's nothing we can do anyway
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * Write the headers to each of the CSV files.
	 * @throws IOException if any IO error occurs
	 */
	private void writeCSVHeaders() throws IOException {
	  patients.write("ID,BIRTHDATE,DEATHDATE,SSN,DRIVERS,PASSPORT,PREFIX,FIRST,LAST,SUFFIX,MAIDEN,MARITAL,RACE,ETHNICITY,GENDER,BIRTHPLACE,ADDRESS");
	  patients.write(NEWLINE);
	  allergies.write("START,STOP,PATIENT,ENCOUNTER,CODE,DESCRIPTION");
	  allergies.write(NEWLINE);
	  medications.write("START,STOP,PATIENT,ENCOUNTER,CODE,DESCRIPTION,REASONCODE,REASONDESCRIPTION");
	  medications.write(NEWLINE);
	  conditions.write("START,STOP,PATIENT,ENCOUNTER,CODE,DESCRIPTION");
	  conditions.write(NEWLINE);
	  careplans.write("ID,START,STOP,PATIENT,ENCOUNTER,CODE,DESCRIPTION,REASONCODE,REASONDESCRIPTION");
	  careplans.write(NEWLINE);
	  observations.write("DATE,PATIENT,ENCOUNTER,CODE,DESCRIPTION,VALUE,UNITS");
	  observations.write(NEWLINE);
	  procedures.write("DATE,PATIENT,ENCOUNTER,CODE,DESCRIPTION,REASONCODE,REASONDESCRIPTION");
	  procedures.write(NEWLINE);
	  immunizations.write("DATE,PATIENT,ENCOUNTER,CODE,DESCRIPTION");
	  immunizations.write(NEWLINE);
	  encounters.write("ID,DATE,PATIENT,CODE,DESCRIPTION,REASONCODE,REASONDESCRIPTION");
	  encounters.write(NEWLINE);
	}
	
	/**
	 *  Thread safe singleton pattern adopted from 
{'fraction_non_alphanumeric': 0.12047751574630144, 'fraction_numerical': 0.08554269811044382, 'mean_word_length': 5.212465878070973, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7246062', 'n_tokens_mistral': 5711, 'n_tokens_neox': 4742, 'n_words': 799}