package timeflow.app.ui;
import timeflow.data.time.*;
import timeflow.data.db.*;
import timeflow.format.field.*;
import timeflow.format.file.DelimitedFormat;
import timeflow.model.*;
import timeflow.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.text.ParseException;
import java.util.*;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
public class ImportDelimitedPanel extends JFrame
{
String fileName;
SchemaPanel schemaPanel;
boolean exitOnClose=false; // for testing!
JScrollPane scroller;
TFModel model;
JLabel numLinesLabel=new JLabel();
// for testing:
public static void main(String[] args) throws Exception
{
System.out.println("Starting test of ImportEditor");
String file="data/probate.tsv";
String[][] data=DelimitedFormat.readArrayGuessDelim(file, System.out);
ImportDelimitedPanel editor=new ImportDelimitedPanel(new TFModel());
editor.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
editor.setFileName(file);
editor.setData(data);
editor.setBounds(50,50,900,800);
editor.setVisible(true);
editor.exitOnClose=true;
}
public ImportDelimitedPanel(final TFModel model)
{
super("Import File");
this.model=model;
setBackground(Color.white);
setLayout(new BorderLayout());
JPanel top=new JPanel();
add(top, BorderLayout.NORTH);
top.setLayout(new FlowLayout(FlowLayout.LEFT));
top.setBackground(Color.lightGray);
top.add(numLinesLabel);
final JTextField source=new JTextField(12);
JButton done=new JButton("Import This");
top.add(done);
done.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
model.setDB(schemaPanel.makeDB(source.getText()), fileName, true, this);
setVisible(false);
if (exitOnClose)
System.exit(0);
}});
JButton cancel=new JButton("Cancel");
top.add(cancel);
cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
if (exitOnClose)
System.exit(0);
}});
top.add(new JLabel(" Enter A Source:"));
top.add(source);
schemaPanel=new SchemaPanel();
schemaPanel.setBackground(Color.white);
scroller=new JScrollPane(schemaPanel);
add(scroller, BorderLayout.CENTER);
}
public void scrollToTop()
{
scroller.getViewport().setViewPosition(new Point(0,0));
}
public void setFileName(String fileName)
{
this.fileName=fileName;
}
public void setData(String[][] data)
{
numLinesLabel.setText((data.length-1)+" records read. ");
schemaPanel.display(data);
}
class SchemaPanel extends JPanel
{
int numFields, rows;
String[][] data;
ArrayList<FieldPanel> panels=new ArrayList<FieldPanel>();
ActDB makeDB(String source)
{
// count number of fields that are not ignored.
int n=0;
for (FieldPanel fp: panels)
if (!fp.ignore.isSelected())
n++;
Class[] types=new Class[n];
String[] fieldNames=new String[n];
int[] index=new int[n];
if (source.trim().length()==0)
source="[source unspecified]";
int i=0, j=0;
for (FieldPanel fp: panels)
{
if (!fp.ignore.isSelected())
{
fieldNames[i]=fp.fieldName;
String typeChoice=(String)fp.typeChoices.getSelectedItem();
Class type=FieldFormatCatalog.javaClass(typeChoice);
System.out.println("Type: "+type+" for: "+typeChoice+" from "+fp.fieldName);
types[i]=type;
index[i]=j;
i++;
}
j++;
}
ActDB db= new ArrayDB(fieldNames, types, source);
HashMap<Integer, StringBuffer> errors=new HashMap<Integer, StringBuffer>();
for (i=1; i<data.length; i++)
{
Act act=db.createAct();
for (int k=0; k<n; k++)
{
j=index[k];
String s=data[i][j];
Field f=db.getField(fieldNames[k]);
FieldFormat format=FieldFormatCatalog.getFormat(types[k]);
try
{
Object o=format.parse(s);
act.set(f,o);
}
catch (Exception e)
{
StringBuffer b=errors.get(i-1);
if (b==null)
{
b=new StringBuffer();
errors.put(i-1,b);
}
else
b.append("; ");
b.append(f.getName()+":"+s);
}
}
}
if (errors.size()>0)
{
Field error=db.addField("UNPARSED FIELDS", String.class);
for (int row:errors.keySet())
{
db.get(row).set(error, errors.get(row).toString());
}
}
for (j=0; j<n; j++)
{
System.out.println(db.getField(fieldNames[j]));
}
return db;
}
void display(String[][] data)
{
removeAll();
this.data=data;
// analyze data.
Class[] guesses=FieldFormatGuesser.analyze(data, 1, 100);
// go through first row, which is headers.
String[] headers=data[0];
// if there are duplicate headers, add indicators.
HashSet<String> h=new HashSet<String>();
for (int i=0; i<headers.length; i++)
{
String base=headers[i];
int j=2;
String name=base;
while (h.contains(name))
{
name=base+" "+j;
j++;
}
headers[i]=name;
h.add(name);
}
numFields=headers.length;
int cols=2;
rows=(int)Math.ceil(numFields/2.0);
setLayout(new GridLayout(rows, cols));
for (int i=0; i<numFields; i++)
{
Bag<String> vals=new Bag<String>();
for (int j=1; j<data.length; j++)
{
vals.add(data[j][i]);
}
java.util.List<String> top=vals.listTop(5);
int n=top.size();
String[] samples=new String[n];
for (int j=0; j<n; j++)
{
String s=top.get(j);
samples[j]=(s.length()==0 ? "*MISSING*" : s)+" ("+vals.num(s)+" times)";
}
JPanel p=new JPanel();
add(p);
p.setLayout(new BorderLayout());
FieldPanel f=new FieldPanel(headers[i], samples, guesses[i]);
panels.add(f);
p.add(f, BorderLayout.CENTER);
JPanel hr=new JPanel();
hr.setPreferredSize(new Dimension(20,20));
p.add(hr, BorderLayout.SOUTH);
}
}
public Dimension getPreferredSize()
{
return new Dimension(400,150*rows);
}
}
class FieldPanel extends JPanel
{
JComboBox typeChoices;
String fieldName;
JCheckBox ignore;
JLabel fieldLabel;
int x1=5, y1=20, y3=150,x2=150, x3=150, x4=375, dh=2;
FieldPanel(String fieldName, String[] sampleValues, Class typeGuess)
{
// just going with a null layout here, because it's a lot simpler!
setLayout(null);
setBackground(Color.white);
this.fieldName=fieldName;
fieldLabel=new JLabel(" \""+fieldName+'"');
fieldLabel.setFont(model.getDisplay().big());
add(fieldLabel);
fieldLabel.setBounds(x1,y1,fieldLabel.getPreferredSize().width, fieldLabel.getPreferredSize().height);
typeChoices=new JComboBox();
for (String choice: FieldFormatCatalog.classNames())
typeChoices.addItem(choice);
typeChoices.setSelectedItem(FieldFormatCatalog.humanName(typeGuess));
add(typeChoices);
int y2=fieldLabel.getY()+fieldLabel.getHeight()+dh+5;
typeChoices.setBounds(x1,y2,
typeChoices.getPreferredSize().width, typeChoices.getPreferredSize().height);
ignore=new JCheckBox("Ignore Field");
add(ignore);
ignore.setBounds(x1,typeChoices.getY()+typeChoices.getHeight()+dh,
ignore.getPreferredSize().width, ignore.getPreferredSize().height);
ignore.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Color c=ignore.isSelected() ? Color.gray : Color.black;
fieldLabel.setForeground(c);
typeChoices.setForeground(c);
}});
JTextArea values=new JTextArea();
values.setForeground(Color.gray);
for (int i=0; i<sampleValues.length; i++)
values.append(sampleValues[i]+"\n");
add(values);
values.setBounds(x3,y2,x4-x3,y3-y2);
}
public Dimension getPreferredSize()
{
return new Dimension(500,150);
}
}
}