package medsavant.incidental;
import com.jidesoft.grid.SortableTable;
import com.jidesoft.pane.CollapsiblePane;
import com.jidesoft.pane.CollapsiblePanes;
import com.jidesoft.swing.CheckBoxList;
import com.jidesoft.swing.JideButton;
import java.util.Calendar;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import javax.swing.BorderFactory;
import org.ut.biolab.medsavant.client.view.component.RoundedPanel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import medsavant.incidental.localDB.IncidentalDB;
import medsavant.incidental.localDB.IncidentalHSQLServer;
import net.miginfocom.swing.MigLayout;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.ut.biolab.medsavant.client.project.ProjectController;
import org.ut.biolab.medsavant.client.util.MedSavantWorker;
import org.ut.biolab.medsavant.client.view.component.ProgressWheel;
import org.ut.biolab.medsavant.client.view.dialog.IndividualSelector;
import org.ut.biolab.medsavant.client.view.util.ViewUtil;
import org.ut.biolab.medsavant.shared.format.AnnotationFormat;
import org.ut.biolab.medsavant.shared.format.CustomField;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ut.biolab.medsavant.MedSavantClient;
import org.ut.biolab.medsavant.client.api.Listener;
import org.ut.biolab.medsavant.client.settings.DirectorySettings;
import org.ut.biolab.medsavant.client.view.MedSavantFrame;
import org.ut.biolab.medsavant.client.view.SplitScreenPanel;
import org.ut.biolab.medsavant.client.view.component.SearchableTablePanel;
import org.ut.biolab.medsavant.client.view.genetics.inspector.ComprehensiveInspector;
import org.ut.biolab.medsavant.client.view.genetics.variantinfo.SimpleVariant;
import org.ut.biolab.medsavant.shared.format.BasicVariantColumns;
import org.ut.biolab.medsavant.shared.vcf.VariantRecord;
/**
* Default panel view for Incidentalome app
*
* @author rammar
*/
public class IncidentalPanel extends JPanel {
private static final Log LOG = LogFactory.getLog(MedSavantClient.class);
private static final Properties properties= new Properties();
private static final String PROPERTIES_FILENAME= DirectorySettings.getMedSavantDirectory().getPath() +
File.separator + "cache" + File.separator + "incidentalome_app_settings.xml";
private static final String DEFAULT_CGD_URL= "http://research.nhgri.nih.gov/CGD/download/txt/CGD.txt.gz";
private static final String DEFAULT_CGD_FILENAME= "CGD.txt";
private static final int DEFAULT_COVERAGE_THRESHOLD= 10;
private static final double DEFAULT_HET_RATIO= 0.3;
private static final double DEFAULT_AF_THRESHOLD= 0.05;
private static final String[] DEFAULT_AF_DB_LIST= new String[] {
"1000g2012apr_all, AnnotationFrequency", "esp6500_all, Score"};
private final int TOP_MARGIN= 0;
private final int SIDE_MARGIN= 5;
private final int BOTTOM_MARGIN= 5;
private final int TEXT_AREA_WIDTH= 80;
private final int TEXT_AREA_HEIGHT= 25;
private final int PANE_WIDTH= 380;
private final int PANE_HEIGHT= 20; // minimum, but it'll stretch down
public static final String PAGE_NAME = "Incidentalome";
private static final String INCIDENTAL_DB_USER= "incidental_user";
private static final String INCIDENTAL_DB_PASSWORD= "$hazam!2734"; // random password
private int coverageThreshold;
private double hetRatio;
private double afThreshold;
private String[] chooserAFArray;
private String incidentalPanelString;
private boolean analysisRunning= false;
private boolean dbLoaded= false;
private JPanel view;
private RoundedPanel workview;
private JideButton choosePatientButton;
private JideButton analyzeButton;
private String analyzeButtonDefaultText= "Refresh";
private IndividualSelector customSelector;
private Set<String> selectedIndividuals;
private String currentIndividual;
private String currentIndividualDNA;
private Calendar date;
private MedSavantWorker MSWorker;
private SearchableTablePanel stp;
private JScrollPane variantPane;
private ProgressWheel pw;
private JLabel progressLabel;
private final int preferredNumColumns= 10;
private JLabel coverageThresholdLabel= new JLabel("Min. variant coverage");
private JTextField coverageThresholdText;
private JButton coverageThresholdHelp;
private JLabel hetRatioLabel= new JLabel("Min. ratio of alt/total");
private JTextField hetRatioText;
private JButton hetRatioHelp;
private JLabel afThresholdLabel= new JLabel("Max. allele frequency");
private JTextField afThresholdText;
private JButton afThresholdHelp;
private JButton chooseAFColumns;
private JButton chooseAFColumnsHelp;
private CheckBoxList chooser;
//private JSeparator statusSeparator= new JSeparator(SwingConstants.HORIZONTAL);
private URL cgdURL;
private CollapsiblePane collapsible;
private CollapsiblePane collapsibleSettings;
private JLabel cgdURLLabel= new JLabel("Clinical Genomics Database URL");
private JTextField cgdText;
private JButton cgdHelp;
private JLabel incidentalPanelLabel= new JLabel("Incidental findings panel");
private JComboBox incidentalPanelComboBox;
private JButton incidentalPanelHelp;
private SplitScreenPanel ssp;
private ComprehensiveInspector vip;
private IncidentalHSQLServer server;
public IncidentalPanel() {
/* Set up the properties based on stored user preference. */
try {
loadProperties();
} catch (Exception e) {
System.err.println("Error loading properties.");
e.printStackTrace();
}
setupView();
this.setLayout(new BorderLayout());
add(view, BorderLayout.CENTER);
server= new IncidentalHSQLServer(INCIDENTAL_DB_USER, INCIDENTAL_DB_PASSWORD);
}
private void setupView() {
view= ViewUtil.getClearPanel();
view.setLayout(new BorderLayout());
//view.setBorder(BorderFactory.createLineBorder(Color.RED));
view.setBorder(BorderFactory.createEmptyBorder(TOP_MARGIN, SIDE_MARGIN, BOTTOM_MARGIN, SIDE_MARGIN));
choosePatientButton= new JideButton("Choose Patient");
choosePatientButton.setButtonStyle(JideButton.FLAT_STYLE);
choosePatientButton.setFont(new Font(choosePatientButton.getFont().getName(),
Font.PLAIN, 18));
analyzeButton= new JideButton(analyzeButtonDefaultText);
analyzeButton.setButtonStyle(JideButton.FLAT_STYLE);
analyzeButton.setFont(new Font(analyzeButton.getFont().getName(),
Font.BOLD, 14));
analyzeButton.setEnabled(false); // cannot click until valid DNA ID is selected
analyzeButton.setVisible(false);
Dimension d= new Dimension(TEXT_AREA_WIDTH, TEXT_AREA_HEIGHT);
coverageThresholdText= new JTextField(Integer.toString(coverageThreshold));
coverageThresholdText.setMinimumSize(d);
coverageThresholdText.setHorizontalAlignment(JTextField.RIGHT);
coverageThresholdHelp= ViewUtil.getHelpButton("Coverage Threshold",
"Minimum number of sequence reads supporting the alternate allele.");
hetRatioText= new JTextField(Double.toString(hetRatio));
hetRatioText.setMinimumSize(d);
hetRatioText.setHorizontalAlignment(JTextField.RIGHT);
hetRatioHelp= ViewUtil.getHelpButton("Alt/Total Ratio",
"In order for a variant to be included, it must exceeed this threshold, "
+ "so as not to be excluded as an erroneous variant. "
+ "Below this threshold, alternate alleles are not reported.");
afThresholdText= new JTextField(Double.toString(afThreshold));
afThresholdText.setMinimumSize(d);
afThresholdText.setHorizontalAlignment(JTextField.RIGHT);
afThresholdHelp= ViewUtil.getHelpButton("Allele Frequency Threshold",
"The maximum allele frequency for this variant. In order for a "
+ "variant to be reported, allele frequency must be below this "
+ "threshold across all allele frequency databases.");
cgdText= new JTextField(cgdURL.toString());
cgdHelp= ViewUtil.getHelpButton("Clinical Genomics Database",
"URL for automatic updates of CGD database");
// ADD AN ACTION LISTENER
/* Allow users to change the incidental findings panel to predefined options. */
incidentalPanelComboBox= new JComboBox(new String[]{"ACMG", "CGD"});
incidentalPanelComboBox.setSelectedItem("CGD"); // default value
incidentalPanelString= (String) incidentalPanelComboBox.getSelectedItem(); // assign the default
incidentalPanelComboBox.addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
incidentalPanelString= (String) incidentalPanelComboBox.getSelectedItem();
}
}
);
incidentalPanelHelp= ViewUtil.getHelpButton("Incidental Findings Panel Selection",
"Current options: All genes from the Clinical Genomics Database " +
"(CGD) for which the mode of inhertiance has been manually curated. "+
"Alternatively, one may choose the limited panel of incidental finding "+
"genes as assigned by the American College of Medical Genetics (ACMG).");
//statusSeparator.setVisible(false);
progressLabel= new JLabel();
progressLabel.setVisible(false);
pw= new ProgressWheel();
pw.setIndeterminate(true);
pw.setVisible(false);
chooser= new CheckBoxList(getDbColumnList());
chooser.addCheckBoxListSelectedValues(chooserAFArray);
variantPane= new JScrollPane();
/* Choose the patient's sample using the individual selector. */
customSelector= new IndividualSelector(true);
choosePatientButton.addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
customSelector.setVisible(true);
selectedIndividuals= customSelector.getHospitalIDsOfSelectedIndividuals();
if (customSelector.hasMadeSelection() && selectedIndividuals.size() == 1) {
currentIndividual= selectedIndividuals.iterator().next();
currentIndividualDNA= customSelector.getDNAIDsOfSelectedIndividuals().iterator().next();
if (currentIndividualDNA != null) {
choosePatientButton.setText(currentIndividual);
analyzeButton.setEnabled(true);
analyzeButton.doClick(); // trigger button's actionPerformed() even though it's not visible
} else {
choosePatientButton.setText("No DNA ID for " + currentIndividual);
}
} else if (customSelector.getHospitalIDsOfSelectedIndividuals().size() > 1){
choosePatientButton.setText("Choose only 1 patient");
}
}
}
);
/* Run incidental findings analysis */
analyzeButton.addActionListener(
new ActionListener() {
@Override
public void actionPerformed (ActionEvent e) {
if (selectedIndividuals != null && selectedIndividuals.size() == 1 && !analysisRunning) {
analysisRunning= true;
MSWorker= new MedSavantWorker<Object> (
IncidentalPanel.class.getCanonicalName()) {
IncidentalFindings incFin;
@Override
protected Object doInBackground() throws Exception {
/* Starts a new thread for background tasks. */
//statusSeparator.setVisible(true);
progressLabel.setVisible(true);
pw.setVisible(true);
analyzeButton.setText("Cancel analysis");
analyzeButton.setVisible(true);
//if (!server.isRunning()) { // No need to run a local server if using JDBC driver from hsqldb
if (!dbLoaded) {
progressLabel.setText("Preparing local filtering database");
try {
//server.startServer(); // No need to run a local server if using JDBC driver from hsqldb
dbLoaded= true;
IncidentalDB.populateDB(server.getURL(), INCIDENTAL_DB_USER, INCIDENTAL_DB_PASSWORD, properties);
} catch (SQLException e) {
e.printStackTrace();
}
}
progressLabel.setText("Downloading and filtering variants");
/* Get all the user settings. */
setAllValuesFromFields();
/* Every time an analysis is run, parameters/settings are saved. */
saveProperties();
/* Get incidental findings. */
incFin= new IncidentalFindings(currentIndividualDNA,
coverageThreshold, hetRatio, afThreshold,
Arrays.asList(chooser.getCheckBoxListSelectedValues()),
incidentalPanelString);
if (this.isCancelled()) {
progressLabel.setText("Analysis Cancelled.");
pw.setVisible(false);
analyzeButton.setEnabled(true);
analyzeButton.setText(analyzeButtonDefaultText);
} else {
progressLabel.setText(incFin.getVariantCount() + " variants. ");
}
pw.setVisible(false);
return null;
}
@Override
protected void showSuccess(Object t) {
/* All updates to display should happen here to be run. */
updateVariantPane(incFin);
analyzeButton.setText(analyzeButtonDefaultText);
analysisRunning= false;
}
};
MSWorker.execute();
} else if (selectedIndividuals != null && selectedIndividuals.size() == 1
&& analysisRunning) {
analysisRunning= false;
MSWorker.cancel(true);
analyzeButton.setEnabled(false);
progressLabel.setText("Cancelling Analysis");
}
}
}
);
chooseAFColumns= new JButton("Choose Allelle Frequency DBs");
chooseAFColumnsHelp= ViewUtil.getHelpButton("Allele Frequency Database selector",
"Choose the databases to use when filtering for allele frequency.");
chooseAFColumns.addActionListener(
new ActionListener() {
@Override
public void actionPerformed (ActionEvent e) {
JScrollPane chooserScrollPane= new JScrollPane(chooser);
chooserScrollPane.setBorder(BorderFactory.createEmptyBorder(2,3,4,1)); // just a little bit of border
chooserScrollPane.setBackground(Color.LIGHT_GRAY);
JDialog f = new JDialog(MedSavantFrame.getInstance(),"Allele Frequency Database selector");
f.add(chooserScrollPane);
f.setPreferredSize(new Dimension(300, 500));
f.setMinimumSize(new Dimension(300, 500));
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
);
/* Set up the layout for the UI.
* GroupLayout requires defintion of the same components from both
* horizontal and verical perspectives. */
/* Set up the layout for the analysis options collapsible panel. */
collapsible= new CollapsiblePane("Analysis options");
collapsible.setLayout(new MigLayout());
collapsible.add(incidentalPanelLabel);
collapsible.add(incidentalPanelComboBox);
collapsible.add(incidentalPanelHelp, "wrap 40px");
collapsible.add(coverageThresholdLabel);
collapsible.add(coverageThresholdText);
collapsible.add(coverageThresholdHelp, "wrap");
collapsible.add(hetRatioLabel);
collapsible.add(hetRatioText);
collapsible.add(hetRatioHelp, "wrap");
collapsible.add(afThresholdLabel);
collapsible.add(afThresholdText);
collapsible.add(afThresholdHelp, "wrap");
collapsible.add(chooseAFColumns);
collapsible.add(chooseAFColumnsHelp);
collapsible.setStyle(CollapsiblePane.PLAIN_STYLE);
collapsible.setFocusPainted(false);
collapsible.collapse(true);
/* Set up the layout for the Advanced settings collapsible panel. */
collapsibleSettings= new CollapsiblePane("Advanced Settings");
collapsibleSettings.setLayout(new MigLayout());
collapsibleSettings.add(cgdURLLabel);
collapsibleSettings.add(cgdHelp, "wrap");
collapsibleSettings.add(cgdText, "span");
collapsibleSettings.setStyle(CollapsiblePane.PLAIN_STYLE);
collapsibleSettings.setFocusPainted(false);
collapsibleSettings.collapse(true);
/* Progress bar panel. */
//JPanel progressPanel= new JPanel(new MigLayout("insets 0", "center", "center")); // Remove borders around the panel using "insets"
JPanel progressPanel= new JPanel(new MigLayout("gap 50px 50px"));
progressPanel.add(progressLabel);
progressPanel.add(pw);
/* Patient selection panel. */
CollapsiblePanes patientPanel= new CollapsiblePanes();
patientPanel.add(choosePatientButton);
patientPanel.add(collapsible);
patientPanel.add(collapsibleSettings);
patientPanel.add(progressPanel);
patientPanel.add(analyzeButton);
/* Set up the gene and variant inspectors. */
ssp = new SplitScreenPanel(variantPane);
vip = new ComprehensiveInspector();
vip.addClinvarSubInspector();
vip.addHGMDSubInspector();
vip.addOtherIndividualsVariantSubInspector(ssp);
vip.addSocialSubInspector();
/* Final window layout along with size preferences. */
workview= new RoundedPanel(10);
workview.setLayout(new MigLayout("", "center", "top"));
workview.add(patientPanel, "cell 0 0");
workview.add(ssp, "cell 1 0");
workview.add(vip, "cell 2 0");
collapsible.setMinimumSize(new Dimension(PANE_WIDTH, PANE_HEIGHT));
variantPane.setPreferredSize(variantPane.getMaximumSize());
vip.setMinimumSize(new Dimension(ComprehensiveInspector.INSPECTOR_WIDTH, 700)); //TEMP
vip.addSelectionListener(new Listener<Object>() {
@Override
public void handleEvent(Object event) {
stp.getTable().clearSelection();
}
});
/* Add the UI to the main app panel. */
view.add(workview, BorderLayout.CENTER);
}
private void updateVariantPane (final IncidentalFindings i) {
if (properties.getProperty("sortable_table_panel_columns") == null) {
stp= i.getTableOutput(null);
} else {
stp= i.getTableOutput(
getIntArrayFromString(properties.getProperty("sortable_table_panel_columns")));
}
stp.getColumnChooser().setProperties(properties, PROPERTIES_FILENAME);
variantPane.setViewportView(stp);
stp.scrollSafeSelectAction(new Runnable() {
@Override
public void run() {
if (stp.getTable().getSelectedRow() != -1) {
SortableTable st= stp.getTable();
int selectedIndex= st.getSelectedRow();
String chr= (String) st.getModel().getValueAt(selectedIndex, BasicVariantColumns.INDEX_OF_CHROM);
long pos= ((Integer) st.getModel().getValueAt(selectedIndex, BasicVariantColumns.INDEX_OF_POSITION)).longValue();
String ref= (String) st.getModel().getValueAt(selectedIndex, BasicVariantColumns.INDEX_OF_REF);
String alt= (String) st.getModel().getValueAt(selectedIndex, BasicVariantColumns.INDEX_OF_ALT);
String type= (String) st.getModel().getValueAt(selectedIndex, BasicVariantColumns.INDEX_OF_VARIANT_TYPE);
SimpleVariant v= new SimpleVariant(chr, pos, ref, alt, type);
vip.setSimpleVariant(v);
/* Create custom SubInspectors. */
Object[] line= new Object[i.header.size()];
for (int index= 0; index != i.header.size(); ++index)
line[index]= st.getModel().getValueAt(selectedIndex, index);
vip.setVariantLine(line, i.header);
}
}
});
}
public JPanel getView() {
return view;
}
/** Set all values from JTextFields. Also set the relevant properties. */
private void setAllValuesFromFields() {
coverageThreshold= Integer.parseInt(coverageThresholdText.getText());
hetRatio= Double.parseDouble(hetRatioText.getText());
afThreshold= Double.parseDouble(afThresholdText.getText());
/* Set the properties. */
properties.setProperty("coverage_threshold", Integer.toString(coverageThreshold));
properties.setProperty("het_ratio", Double.toString(hetRatio));
properties.setProperty("af_threshold", Double.toString(afThreshold));
properties.setProperty("CGD_DB_URL", cgdText.getText());
// quote-enclosed, comma-delimited list as string
String afChooserStringList= "\"" + StringUtils.join(Arrays.asList(
chooser.getCheckBoxListSelectedValues()), "\"\t\"") + "\"";
properties.setProperty("af_chooser_list", afChooserStringList);
}
/** Get the header for the table using the column aliases. */
public Object[] getDbColumnList() {
List<String> t= new ArrayList<String>();
try {
AnnotationFormat[] afs = ProjectController.getInstance().getCurrentAnnotationFormats();
for (AnnotationFormat af : afs)
for (CustomField field : af.getCustomFields())
t.add(field.getAlias());
} catch (Exception e) {
LOG.error(e);
}
return t.toArray();
}
/**
* Load the properties file if it exists.
*/
private void loadProperties () throws Exception {
File propertiesFile= new File(PROPERTIES_FILENAME);
if (!propertiesFile.exists()) {
/* Set the defaults. */
long defaultDate= (new GregorianCalendar(2013, Calendar.NOVEMBER,
27)).getTimeInMillis(); // CGD date at time of coding
properties.setProperty("CGD_DB_date", Long.toString(defaultDate));
properties.setProperty("CGD_DB_URL", DEFAULT_CGD_URL.toString());
properties.setProperty("CGD_DB_filename", DEFAULT_CGD_FILENAME);
properties.setProperty("coverage_threshold", Integer.toString(DEFAULT_COVERAGE_THRESHOLD));
properties.setProperty("het_ratio", Double.toString(DEFAULT_HET_RATIO));
properties.setProperty("af_threshold", Double.toString(DEFAULT_AF_THRESHOLD));
String afChooserStringList= "\"" + StringUtils.join(Arrays.asList(DEFAULT_AF_DB_LIST), "\"\t\"") + "\"";
properties.setProperty("af_chooser_list", afChooserStringList);
saveProperties();
} else {
properties.loadFromXML(new FileInputStream(propertiesFile));
}
/* Set the parameters from properties. */
cgdURL= new URL(properties.getProperty("CGD_DB_URL"));
coverageThreshold= Integer.parseInt(properties.getProperty("coverage_threshold"));
hetRatio= Double.parseDouble(properties.getProperty("het_ratio"));
afThreshold= Double.parseDouble(properties.getProperty("af_threshold"));
String s= properties.getProperty("af_chooser_list");
chooserAFArray= (s.substring(1, s.length() - 1)).split("\"\t\"");
// Update CGD file if necessary
updateCGD();
copyCGD();
}
/**
* Save the current set of properties to the properties XML file.
*/
private void saveProperties() {
try {
properties.storeToXML(new FileOutputStream(PROPERTIES_FILENAME),
"Configuration options for incidentalome app");
} catch (Exception e) {
System.err.println("[IncidentalPanel]: Error saving properties XML file.");
e.printStackTrace();
}
}
/**
* Update the CGD database if a new one exists at the specified URL.
*/
private void updateCGD() throws Exception {
HttpURLConnection conn= (HttpURLConnection) cgdURL.openConnection();
Date urlDate= new Date(conn.getLastModified());
Date currentDate= new Date(Long.parseLong((String) properties.getProperty("CGD_DB_date")));
if (currentDate.before(urlDate)) {
// notify users
DateFormat dateFormat= new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
System.out.println("[Incidental Panel]: Existing CGD version from " +
dateFormat.format(currentDate) + " to be replaced by newer CGD version from " +
dateFormat.format(urlDate));
// download file to cache, uncompress, removed compressed file, set new properties
File cgdFile= new File(DirectorySettings.getMedSavantDirectory().getPath() +
File.separator + "cache" + File.separator +
FilenameUtils.getName(cgdURL.getFile()));
FileUtils.copyURLToFile(cgdURL, cgdFile);
File newCgdFile= gunzip(cgdFile);
cgdFile.delete();
changeCGDHeader(newCgdFile); // should overwrite existing CGD.txt file if exists
// modify and save properties
properties.setProperty("CGD_DB_date", Long.toString(urlDate.getTime()));
properties.setProperty("CGD_DB_filename", newCgdFile.getName());
saveProperties();
}
}
/**
* Copy CGD file to cache if it is not already there.
*/
private void copyCGD() {
File f= new File(DirectorySettings.getMedSavantDirectory().getPath() +
File.separator + "cache" + File.separator + properties.getProperty("CGD_DB_filename"));
if (!f.exists()) { // copy the default pre-packaged CGD file from Nov. 26, 2013.
try {
InputStream in= IncidentalPanel.class.getResourceAsStream("/db_files/CGD.txt");
OutputStream out= new FileOutputStream(f);
IOUtils.copy(in, out);
in.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/** Uncompresses the gzipped File.
* Code adapted from StackOverFlow example.
* @param gzipFile the gzipped file object
* @precondition Expecting the gzipFile has a .gz extension
* @return the new file object
*/
public static File gunzip(File gzipFile) {
// Get the file name without the .gz extension
Pattern gunzipFilenamePattern= Pattern.compile("^(.+).gz$", Pattern.CASE_INSENSITIVE);
Matcher gunzipFilenameMatcher= gunzipFilenamePattern.matcher(gzipFile.getPath());
String gunzipFilename= null;
if (gunzipFilenameMatcher.find())
gunzipFilename= gunzipFilenameMatcher.group(1);
// read the compressed file and output an uncompressed version
GZIPInputStream in = null;
OutputStream out = null;
try {
in = new GZIPInputStream(new FileInputStream(gzipFile));
out = new FileOutputStream(gunzipFilename);
byte[] buf = new byte[1024 * 4];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len); // if you use write(buf), end up writing weird characters if buf not full
}
in.close();
out.close();
}
catch (IOException e) {
e.printStackTrace();
}
return new File(gunzipFilename);
}
/** Change CGD header to predefined header. Since the file is small, make
* all changes in memory and output a new file by the same name. */
public static void changeCGDHeader(File cgdFile) throws FileNotFoundException, IOException {
List<String> newLines= new LinkedList<String>();
BufferedReader reader= null;
// Store the custom header - just the first line
reader= new BufferedReader(
new InputStreamReader(IncidentalDB.class.getResourceAsStream("/db_files/CGD_header.txt")));
newLines.add(reader.readLine());
reader.close();
// Store all the non-header lines from the current CGD file
reader= new BufferedReader(new FileReader(cgdFile));
boolean inHeader= true;
String line= reader.readLine();
while (line != null) {
if (inHeader) {
inHeader= false;
} else {
newLines.add(line);
}
line= reader.readLine();
}
reader.close();
// Overwrite all the new lines to the file
BufferedWriter writer= new BufferedWriter(new FileWriter(cgdFile, false)); // do not append
for (String l : newLines) {
writer.write(l);
writer.newLine();
}
writer.close();
}
/**
* Convert string list of integers into an int[].
* @param arr String list in the format "[1,2,3,4,5]
*/
private int[] getIntArrayFromString(String arr) {
String[] items = arr.replaceAll("\\[", "").replaceAll("\\]", "").split("\\s?,\\s?");
int[] results = new int[items.length];
for (int i = 0; i < items.length; i++) {
try {
results[i] = Integer.parseInt(items[i]);
} catch (NumberFormatException nfe) {};
}
return results;
}
}