/*
 * @(#)PhraseBuilder.java	0.1 2002/04/25
 *
 * Copyright 2002 by Carnegie Mellon, All rights reserved.
 */

package phrase_builder;

import lmt.*;
import java.sql.*;
import java.util.*;
import java.io.*;

public class PhraseBuilder
{
  private String databaseURL;

  SQLConnection dbConnection;

  Hashtable abbrev;

  boolean openDBConnection() 
  {
    if ( dbConnection == null ) {
      dbConnection = new SQLConnection(databaseURL);

      Debug.debug("-- openDBConnection server:" + databaseURL );	
      boolean success = dbConnection.connect();
      if ( !success ) closeDBConnection();

      return success;
    }
    return true;
  }

  void closeDBConnection() 
  {
    if ( dbConnection != null ) {
      dbConnection.close();
      dbConnection = null;
    }
  }

  private static final int WARN = 0;
  private static final int FAIL = 1;
  private static final int FAIL_PHRASE = 2;
  private static final int FAIL_SINGLE = 3;

  private PrintStream succeeded, failed, 
    failedSingleWord, failedPhrase, warning;
    
  private void tossOut(String entry, String comment, int type)
  {
    PrintStream stream = null;
    if (type == WARN)
      stream = warning;
    else if (type == FAIL)
      stream = failed;
    else if (type == FAIL_PHRASE)
      stream = failedPhrase;
    else if (type == FAIL_SINGLE)
      stream = failedSingleWord;
    else
    {
      System.err.println("Internal Error: toss_out: Bad type");
      System.exit(-1);
    }
    StringTokenizer t = new StringTokenizer(comment, "\r\n");
    while (t.hasMoreTokens())
    {
      stream.println(";; " + t.nextToken());
    }
    stream.println(entry + "\n");
  }

  private void openOutputFiles()
  {
    try
    {
      succeeded = new PrintStream(new FileOutputStream("succeeded"));
      failed = new PrintStream(new FileOutputStream("failed"));
      failedSingleWord = 
	new PrintStream(new FileOutputStream("failed_single_word"));
      failedPhrase = new PrintStream(new FileOutputStream("failed_phrase"));
      warning = new PrintStream(new FileOutputStream("warning"));
    }
    catch (FileNotFoundException e)
    {
      System.err.println("Couldn't open files for writing: " + e.getMessage());
      System.exit(3);
    }
  }

  private BufferedReader templateReader;

  public PhraseBuilder(String db, String templates)
  {
    abbrev = new Hashtable();
    try 
    {
      FileReader abbrevFile = new FileReader("abbrev_map");
      BufferedReader abbrevStream = new BufferedReader(abbrevFile);
      try
      {
	String line = abbrevStream.readLine();
	while (line != null && line.length() != 0)
	{
	  StringTokenizer t = new StringTokenizer(line);
	  if (t.countTokens() == 2)
	  {
	    String key = t.nextToken();
	    String value = t.nextToken();
	    abbrev.put(key, value);
	  }
	  else
	  {
	    System.err.println("Error: Malformed abbrev_map.");
	    System.exit(1);
	  }
	  line = abbrevStream.readLine();
	}
      }
      catch (IOException e) 
      {
	System.err.println("Error: IO Exception reading abbrev_map.");
	System.err.println(e.getMessage());
	System.exit(1);
      }
    }
    catch (FileNotFoundException e)
    {
      System.err.println("Error: Cannot find abbrev_map in CWD.");
      System.exit(1);
    }

    try 
    {
      FileReader templateFile = new FileReader(templates);
      templateReader = new BufferedReader(templateFile);
    }
    catch (FileNotFoundException e)
    {
      System.err.println("Error: Cannot find " + templates);
      System.exit(1);
    }

    int colon = db.indexOf(':');
    if (colon == -1)
      databaseURL = db + ":1521:lmt2";
    else
    {
      int colon2 = db.indexOf(':', colon + 1);
      if (colon2 == -1)
	databaseURL = db + ":lmt2";
      else
      {
	String machine = db.substring(0, colon);
	String port;
	if (colon2 == colon + 1)
	  port = "1521";
	else
	  port = db.substring(colon + 1, colon2);
	String dbname;
	if (db.length() <= colon2 + 1)
	  dbname = "lmt2";
	else
	  dbname = db.substring(colon2 + 1);
	databaseURL = machine + ":" + port + ":" + dbname;
      }
    }
    openOutputFiles();
  }

  static private class LispReader
  {
    private Reader reader;
    StringBuffer buf;
    LispReader(Reader r) {reader = r; buf = new StringBuffer();}
    int read() throws IOException
    {
      if (buf.length() != 0)
      {
	char c = buf.charAt(buf.length() - 1);
	buf.setLength(buf.length() - 1);
	return c;
      }
      if (reader.ready())
      {
	int c =  reader.read();
	return c;
      }
      return -1;
    }
    int pk() throws IOException
    {
      if (buf.length() != 0)
	return buf.charAt(buf.length() - 1);
      if (reader.ready())
      {
	int c = reader.read();
	if (c != -1)
	  buf.append((char)c);
	return c;
      }
      return -1;
    }
    void putBack(char c)
    {
      buf.append(c);
    }
    private boolean in_string = false;
    private boolean escaped = false;
    int peek() throws IOException
    {
      int c = pk();
      if (!in_string)
	if (c == ';' && !escaped)
	  while ((c = pk()) != -1 && c != '\n')
	    read();
	else
	  while (c == '#')
	  {
	    c = read();
	    if (pk() == '|')
	    {
	      read();
	      int depth = 1;
	      while (depth != 0 && (c = read()) != -1)
	      {
		if (c == '|' && pk() == '#')
		{
		  read();
		  depth--;
		}
		if (c == '#' && pk() == '|')
		{
		  read();
		  depth++;
		}
	      }
	      c = pk();
	    }
	    else
	    {
	      putBack((char)c);
	      break;
	    }
	  }
      return c;
    }
    int get() throws IOException
    {
      int c = read();
      if (!in_string)
	if (c == ';' && !escaped)
	  while ((c = read()) != -1 && c != '\n');
	else
	  while (c == '#')
	  {
	    if (pk() == '|')
	    {
	      read();
	      int depth = 1;
	      while (depth != 0 && (c = read()) != -1)
	      {
		if (c == '|' && pk() == '#')
		{
		  read();
		  depth--;
		}
		if (c == '#' && pk() == '|')
		{
		  read();
		  depth++;
		}
	      }
	      c = read();
	    }
	    else
	      break;
	  }
      if (c == '\"' && !escaped)
	in_string = !in_string;
      if (escaped)
	escaped = false;
      return c;
    }
  }
	
  private static void ignoreWS(LispReader r) throws IOException
  {
    while (r.peek() != -1 && Character.isWhitespace((char)r.peek()))
      r.read();
  }

  private static boolean isWordChar(char c)
  {
    return (c != -1 && !Character.isWhitespace(c) &&
	    "()[]{}<>=,\"".indexOf(c) == -1);
  }

  private static String readString(LispReader r) throws IOException
  {
    char c;
    ignoreWS(r);
    String retval = new String();
    
    int p = r.peek();
    c = (char)p;
    
    boolean isword = p != -1 && isWordChar(c);

    if (isword)
      while (isword)
      {
	if (c == '\\')
	  retval += (char)r.get();
	retval += (char)r.get();
	p = r.peek();
	c = (char)p;
	isword = p != -1 && isWordChar(c);
      }
    else if (p == -1)
      r.get();
    else if ("([{<\"".indexOf(c) != -1)
    {
      retval += (char)r.get();
      char open = c;
      String parens = "()[]{}<>\"\"";
      char match = parens.charAt(parens.indexOf(c) + 1);
      int depth = 0;
      p = r.peek();
      c = (char)p;
      while (p != -1 && (c != match || depth != 0))
      {
	if (c == '\\')
	  retval += (char)r.get();
	else if (c == match)
	  depth--;
	else if (c == open)
	  depth++;
	else if (c == '\"')
	{
	  retval += (char)r.get();
	  p = r.peek();
	  c = (char)p;
	  while (p != -1 && c != '\"')
	  {
	    if (c == '\\')
	      retval += (char)r.get();
	    retval += (char)r.get();
	    c = (char)r.peek();
	  }
	  if (p == -1)
	    break;
	}
	retval += (char)r.get();
	p = r.peek();
	c = (char)p;
      }
      if (p != -1)
	retval += (char)r.get();
      else
      {
	r.get();
	System.err.println("Premature end-of-file encountered while reading string!");
	System.err.println("(String starts with initial '" + retval.charAt(0) +
			   "' and lacks matching '" + match + "')");
	System.exit(1);
      }
    }
    else
      retval += (char)r.get();

    return retval;
  }

  private static void expect(char expected, char actual, 
			     BufferedReader r, String where)
  {
    if (expected != actual)
    {
      try
      {
	System.err.println("Error: " + where + " should have a '" + expected +
			   "', but instead got: " + actual + r.readLine());
      }
      catch (IOException e) 
      {
	System.err.println("Error: " + where + " should have a '" + expected +
			   "'.");
      }
      System.exit(1);
    }
  }

  private static String dequote(String x)
  {
    if (x.length() >= 2 && x.charAt(0) == '\"' 
	&& x.charAt(x.length() - 1) == '\"')
      return x.substring(1, x.length() - 1);
    return x;
  }

  private static Vector parseValues(LispReader r) throws IOException
  {
    Vector v = new Vector();
    char c;
    ignoreWS(r);
    while (r.peek() != -1 && (c = (char)r.peek()) != ')')
    {
      String x = readString(r);
      switch (c)
      {
      case '(':
	{
	  x = x.substring(1, x.length() - 1);
	  LispReader nr = new LispReader(new StringReader(x));
	  v.addAll(parseValues(nr));
	}
	break;
      case '\"':
	x = dequote(x);
	x = x.trim();
      default:
	if (x.length() != 0)
	{
	  v.add(x);
	}
      }
      ignoreWS(r);
    }
    return v;
  }
	  
  class Pair
  {
    public Object first;
    public Object last;
    Pair(Object a, Object b) {first = a; last = b;}
  }

  private void go()
  {
    java.text.DateFormat df = 
      new java.text.SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
    Hashtable entrydata = new Hashtable();
    System.out.println("Reading templates...");
    try
    {
      while (true)
      {
	LispReader r = new LispReader(templateReader);
	ignoreWS(r);
	if (r.peek() == -1)
	  break;
	String entry = readString(r);
	BufferedReader b = new BufferedReader(new StringReader(entry));
	LispReader s = new LispReader(b);
	char c;
	c = (char)s.get();
	expect('(', c, b, "Beginning of entry");
	Hashtable entrymap = new Hashtable();
	ignoreWS(s);
	while (s.peek() != ')')
	{
	  c = (char)s.get();
	  expect('(', c, b, "Beginning of field");
	  String type = readString(s);
	  ignoreWS(s);
	  if (type.length() < 2 || type.charAt(0) != ':')
	  {
	    System.err.println("Error: Expected a field name beginning with a colon.");
	    System.exit(1);
	  }
	  type = type.toUpperCase();
	  Vector v = parseValues(s);
	  if (v.size() != 0)
	    entrymap.put(type, v);
	  c = (char)s.get();
	  expect(')', c, b, "End of field entry");
	  ignoreWS(s);
	}
	c = (char)s.get();
	expect(')', c, b, "End of entry");

	Vector value = (Vector)entrymap.get(":CTE");
	if (value == null) 
	{
	  tossOut(entry, "Could not find a term string. (:CTE)", FAIL);
	  continue;
	}
	if (value.size() != 1)
	{
	  tossOut(entry, "Missing or multiple term strings. (:CTE)", FAIL);
	  continue;
	}
	String root = (String)value.get(0);
	if (root.length() > 100)
	{
	  tossOut(entry, "Term string too large. (:CTE) (> 100)", FAIL);
	  continue;
	}
	root = root.toLowerCase();
	
	value = (Vector)entrymap.get(":REQUEST");
	if (value == null) 
	{
	  tossOut(entry, "Absent request field.", FAIL);
	  continue;
	}
	if (value.size() != 1)
	{
	  tossOut(entry, "Missing or multiple request field entries.", FAIL);
	  continue;
	}
	String request = (String)value.get(0);
	request = request.toUpperCase();
	if (request.equals("CHANGE"))
	{
	  tossOut(entry, "Changes require manual intervention.", FAIL);
	  continue;
	}
	else if (request.equals("DELETE") || request.equals("REMOVE"))
	{
	  tossOut(entry, "Deletions can't be handled in an incremental load.",
		  FAIL);
	  continue;
	}
	else if (!request.equals("ADD"))
	{
	  tossOut(entry, "Invalid request field.", FAIL);
	  continue;
	}

	value = (Vector)entrymap.get(":POS");
	if (value == null) 
	{
	  tossOut(entry, "Absent POS field.", FAIL);
	  continue;
	}
	if (value.size() != 1)
	{
	  tossOut(entry, "Missing or multiple POS entries.", FAIL);
	  continue;
	}
	String pos = (String)value.get(0);
	pos = pos.toUpperCase();
	boolean phrase = root.indexOf(' ') != -1;
	if (!pos.equals("N") && !pos.equals("NOUN"))
	{
	  tossOut(entry, "Not a noun according to the POS field.", 
		  phrase ? FAIL_PHRASE : FAIL);
	  continue;
	}
	if (!phrase)
	{
	  tossOut(entry, "Term string is not a phrase.", FAIL_SINGLE);
	  continue;
	}
	
	Pair t = (Pair)entrydata.get(root);
	if (t != null)
	{
	  tossOut(entry, "Duplicate entry.", FAIL);
	  String pe = (String)(t.first);
	  if (pe.length() != 0)
	  {
	    tossOut(pe, "Duplicate entry.", FAIL);
	    Object o = t.last;
	    entrydata.remove(root);
	    entrydata.put(root, new Pair("", o));
	  }
	  continue;
	}
	else
	  entrydata.put(root, new Pair(entry, entrymap));
      }
    }
    catch (IOException e) {
      System.err.println("Error: IO Error.  Resubmit data.");
      System.err.println(e.getMessage());
      System.exit(1);
    }

    System.out.println("Done");

    try
    {
      if (!openDBConnection())
      {
	System.err.println("Could not open database connection to " + 
			   databaseURL);
	System.exit(1);
      }

      Enumeration keys = entrydata.keys();
      while (keys.hasMoreElements())
      {
	String term = (String)keys.nextElement();
	Pair p = (Pair)entrydata.get(term);
	String entry = (String)p.first;
	Hashtable entrymap = (Hashtable)p.last;
	String cptstr = null;
	Vector cpt = (Vector)entrymap.get(":CONCEPT");
	if (cpt != null)
	{
	  if (cpt.size() != 1)
	  {
	    tossOut(entry, "Bad concept slot.", FAIL);
	    continue;
	  }
	  cptstr = (String)cpt.get(0);
	}

	String sql = "SELECT term_id FROM LMT_TERMS WHERE term_string = '" +
		     term + "' AND POS = 'N'";
	SQLConnection.Result dbid = dbConnection.query(sql);
	Vector v = new Vector();
	while (dbid.hasData())
	{
	  sql = "SELECT concept_symbol FROM LMT_CONCEPTS where term_id = '" +
		dbid.rs.getString(1) + "'";
	  SQLConnection.Result dbcpts = dbConnection.query(sql);
	  while (dbcpts.hasData())
	    v.add(dbcpts.rs.getString(1));
	  dbcpts.close();
	}
	dbid.close();
	if (v.size() != 0)
	{
	  String s = "There already exists an entry for this term.";
	  for (int i = 0; i < v.size(); i++)
	    s += "\n" + (String)v.get(i);
	  tossOut(entry, s, FAIL);
	  continue;
	}

	String warning_string = null;
	String count = null;
	// Make the concept string, if it doesn't exist.
	if (cptstr == null)
	{
	  StringTokenizer words = new StringTokenizer(term, " ");
	  Vector cptstrs = new Vector();
	  Vector orphans = new Vector();
	  cptstrs.add("*O");
	  while (words.hasMoreElements())
	  {
	    int x = cptstrs.size();
	    String current = words.nextToken();
	    String word = (String)abbrev.get(current);
	    if (word == null)
	    {
	      Term t = new Term(dbConnection);
	      t.setTermString(current);
	      t.setPos("ANY");
	      Vector tv = t.searchTerms();
	      StringBuffer bword = new StringBuffer(current.toUpperCase());
	      for (int k = 0; k < bword.length(); k++)
		if (bword.charAt(k) == '/')
		  bword.setCharAt(k, '-');
	      word = bword.toString();
	      if (tv.size() == 0)
		orphans.add(current);
	      else
	      {
		for (int i = 0; i < tv.size(); i++)
		{
		  Vector sv = (Vector)tv.get(i);
		  t.setTermID((String)sv.get(2));
		  t.fetchTerm();
		  Vector cv = t.getConcepts();
		  for (int j = 0; j < cv.size(); j++)
		  {
		    Concept c = (Concept)cv.get(j);
		    Syntax s = c.getSyntax();
		    if (s != null && 
			(s.getAbbreviation().equals("T") ||
			 s.getAcronym().equals("T")))
		    {
		      String sym = c.getConceptSymbol();
		      sym = sym.substring(sym.indexOf('-'));
		      for (int k = 0; k < x; k++)
			cptstrs.add((String)cptstrs.get(k) + sym);
		    }
		    // If this is the last word in the phrase, steal
		    // its count feature.
		    if (s instanceof SyntaxNoun &&
			!words.hasMoreElements())
		      count = ((SyntaxNoun)s).getCount();
		  }
		}
	      }
	    }
	    for (int k = 0; k < x; k++)
	      cptstrs.set(k, (String)cptstrs.get(k) + "-" + word);
	  }
	  if (orphans.size() != 0)
	  {
	    warning_string = 
	      "The following words in this entry have no DMK entry:";
	    for (int i = 0; i < orphans.size(); i++)
	      warning_string += "\n" + (String)orphans.get(i);
	  }
	  if (cpt == null && cptstrs.size() > 1)
	  {
	    String s = 
	      "There could be several possible concept string expansions:";
	    for (int i = 0; i < cptstrs.size(); i++)
	      s += "\n(:CONCEPT " + (String)cptstrs.get(i) + ")";
	    tossOut(entry, s, FAIL);
	    continue;
	  }
	  cptstr = (String)cptstrs.get(0);
	}
	if (cptstr.length() > 100)
	{
	  tossOut(entry, "Concept string is too large. (> 100)", FAIL);
	  continue;
	}

	String caps = new String();
	String irreg_caps = new String();
	Vector capsv = (Vector)entrymap.get(":CAPS");
	if (capsv != null)
	{
	  if (capsv.size() != 1)
	  {
	    tossOut(entry, "Multiple values in :CAPS field.", FAIL);
	    continue;
	  }
	  String cap = (String)capsv.get(0);
	  cap = cap.toUpperCase();
	  if (cap.length() != 0)
	  {
	    if (cap.equals(":ALL"))
	      caps = "A";
	    else if (cap.equals(":FIRST"))
	      caps = "F";
	    else if (cap.equals(":EACH"))
	      caps = "E";
	    else if (cap.equals(":ANY"))
	      caps = "N";
	    else
	    {
	      tossOut(entry, "Invalid :CAPS field.", FAIL);
	      continue;
	    }
	  }
	}
	Vector irregv = (Vector)entrymap.get(":IRREG-CAPS");
	if (irregv != null)
	{
	  if (irregv.size() != 1)
	  {
	    tossOut(entry, "Multiple values in :IRREG-CAPS field.", FAIL);
	    continue;
	  }
	  String cap = (String)irregv.get(0);
	  if (cap.length() != 0)
	  {
	    if (caps.length() != 0)
	    {
	      tossOut(entry, "Conflicting :CAPS and :IRREG-CAPS fields.", 
		      FAIL);
	      continue;
	    }
	    caps = "I";
	    irreg_caps = cap;
	    if (irreg_caps.length() > 100)
	    {
	      tossOut(entry, ":IRREG-CAPS field is too large. (> 100)", FAIL);
	      continue;
	    }
	  }
	}

	String cnt = new String();
	Vector cntv = (Vector)entrymap.get(":COUNT");
	if (cntv != null)
	{
	  boolean pl = false, m = false, e = false;
	  for (int i = 0; i < cntv.size(); i++)
	  {
	    String ct = (String)cntv.get(i);
	    for (int j = 0; j < ct.length(); j++)
	    {
	      char c = ct.charAt(j);
	      if (c == '+')
		pl = true;
	      else if (c == '-')
		m = true;
	      else if (!Character.isWhitespace(c))
		e = true;
	    }
	  }
	  if (e)
	  {
	    tossOut(entry, "Invalid :COUNT field.", FAIL);
	    continue;
	  }
	  cnt = (pl && m) ? "B" : (pl ? "C" : (m ? "M" : ""));
	}
	if (cnt.length() == 0)
	  if (count != null)
	    cnt = count;
	  else
	    cnt = "C";
	  
	Vector cmtv = (Vector)entrymap.get(":COMMENT");
	if (cmtv != null)
	{
	  boolean illegal = false;
	  for (int k = 0; !illegal && k < cmtv.size(); k++)
	    if (((String)cmtv.get(k)).length() > 500)
	      illegal = true;
	  if (illegal)
	  {
	    tossOut(entry, "Comment too large. (> 500)", FAIL);
	    continue;
	  }
	}

	Vector def = (Vector)entrymap.get(":DEFINITION");
	Vector usage = (Vector)entrymap.get(":USAGE");
	Vector negdef = (Vector)entrymap.get(":NEG-DEFINITION");
	Vector neguse = (Vector)entrymap.get(":NEG-USAGE");
	if (def != null)
	{
	  boolean illegal = false;
	  for (int k = 0; !illegal && k < def.size(); k++)
	    if (((String)def.get(k)).length() > 500)
	      illegal = true;
	  if (illegal)
	  {
	    tossOut(entry, "Definition too large. (> 500)", FAIL);
	    continue;
	  }
	}
	if (usage != null)
	{
	  boolean illegal = false;
	  for (int k = 0; !illegal && k < usage.size(); k++)
	    if (((String)usage.get(k)).length() > 500)
	      illegal = true;
	  if (illegal)
	  {
	    tossOut(entry, "Usage too large. (> 500)", FAIL);
	    continue;
	  }
	}
	if (negdef != null)
	{
	  boolean illegal = false;
	  for (int k = 0; !illegal && k < negdef.size(); k++)
	    if (((String)negdef.get(k)).length() > 500)
	      illegal = true;
	  if (illegal)
	  {
	    tossOut(entry, "Negative definition too large. (> 500)", FAIL);
	    continue;
	  }
	}
	if (neguse != null)
	{
	  boolean illegal = false;
	  for (int k = 0; !illegal && k < neguse.size(); k++)
	    if (((String)neguse.get(k)).length() > 500)
	      illegal = true;
	  if (illegal)
	  {
	    tossOut(entry, "Negative usage too large. (> 500)", FAIL);
	    continue;
	  }
	}

	if (negdef != null && negdef.size() > 1)
	{
	  tossOut(entry, 
		  "I can't deal with more than one negative definition.",
		  FAIL);
	  continue;
	}
	if (def != null && def.size() > 1)
	{
	  tossOut(entry, "Too many definitions.", FAIL);
	  continue;
	}

	Vector acro = (Vector)entrymap.get(":ACRONYM");
	String acronym = null;
	if (acro != null)
	{
	  if (acro.size() > 1)
	  {
	    tossOut(entry, "Multiple values in :IRREG-CAPS field.", FAIL);
	    continue;
	  }
	  acronym = (String)acro.get(0);
	  if (acronym.indexOf(' ') != -1)
	  {
	    tossOut(entry, "I do not handle multi-word acronyms.", FAIL);
	    continue;
	  }
	  sql = "SELECT term_id FROM LMT_TERMS WHERE term_string = '" +
		acronym + "' AND POS = 'N'";
	  SQLConnection.Result dbx = dbConnection.query(sql);
	  if (dbx.hasData())
	  {
	    tossOut(entry, "Acronym already exists as term in LMT.", FAIL);
	    dbx.close();
	    continue;
	  }
	  dbx.close();
	}

	//Create a term
	Term theterm = new Term(dbConnection);
	theterm.setTermString(term);
	theterm.setPos("N");
	theterm.setTypePhrase("T");

	// Create a concept
	Concept concept = new Concept(dbConnection);
	concept.setConceptSymbol(cptstr);
	concept.setCteEntry("T");
	concept.setAmbiguity("N");
	concept.setCapitalization(caps);
	concept.setIrrCapitalization(irreg_caps);
	java.util.Date date = new java.util.Date();
	concept.setDateCreated(df.format(date));
	concept.setDateUpdated(df.format(date));
	concept.setPos("N");

	// Insert
	int rval = theterm.insert(concept);
	String cid = concept.getConceptID();
	String aid = null;
	if (acro != null)
	{
	  theterm.setTermString(acronym);
	  theterm.setTypePhrase("F");
	  theterm.insert(concept);
	  aid = concept.getConceptID();
	}

	// Create syntax
	SyntaxNoun syntax = new SyntaxNoun(dbConnection, cid);
	syntax.setCount(cnt);
	syntax.setFullForm("F");
	syntax.setNumber("S");
	syntax.setAbbreviation("F");
	syntax.setAcronym("F");
	syntax.setComplementS("F");
	syntax.setComplementX("F");
	syntax.insert();
	if (acro != null)
	{
	  syntax.setConceptID(aid);
	  syntax.setAcronym("T");
	  syntax.insert();
	}


	// Create morphology
	MorphNoun morph = new MorphNoun(dbConnection, cid);
	morph.setPlural("T");
	morph.setGensg("T");
	morph.setGenpl("T");
	morph.insert();
	if (acro != null)
	{
	  morph.setConceptID(aid);
	  morph.insert();
	}

	// Create Definitions and Examples
	Definition definition = new Definition(dbConnection, cid);
	definition.setAudience("B");
	definition.setCteUsage("T");
	String did = null;
	String adid = null;
	if (def != null)
	{
	  definition.setUsageDefinition((String)def.get(0));
	  definition.insert();
	  did = definition.getDefinitionID();
	  if (acro != null)
	  {
	    definition.setConceptID(aid);
	    definition.insert();
	    adid = definition.getDefinitionID();
	  }
	} 
	else if (usage != null)
	{
	  definition.setUsageDefinition("No definition");
	  definition.insert();
	  did = definition.getDefinitionID();
	  if (acro != null)
	  {
	    definition.setConceptID(aid);
	    definition.insert();
	    adid = definition.getDefinitionID();
	  }
	}
	if (usage != null)
	{
	  Example example = new Example(dbConnection, did);
	  for (int i = 0; i < usage.size(); i++)
	  {
	    example.setUsageExample((String)usage.get(i));
	    example.insert();
	    if (acro != null)
	    {
	      example.setDefinitionID(adid);
	      example.insert();
	      example.setDefinitionID(did);
	    }
	  }
	}
	definition.setCteUsage("F");
	definition.setConceptID(cid);
	if (negdef != null)
	{
	  definition.setUsageDefinition((String)negdef.get(0));
	  definition.insert();
	  did = definition.getDefinitionID();
	  if (acro != null)
	  {
	    definition.setConceptID(aid);
	    definition.insert();
	    adid = definition.getDefinitionID();
	  }
	} 
	else if (neguse != null)
	{
	  definition.setUsageDefinition("No definition");
	  definition.insert();
	  did = definition.getDefinitionID();
	  if (acro != null)
	  {
	    definition.setConceptID(aid);
	    definition.insert();
	    adid = definition.getDefinitionID();
	  }
	}
	if (neguse != null)
	{
	  Example example = new Example(dbConnection, did);
	  for (int i = 0; i < neguse.size(); i++)
	  {
	    example.setUsageExample((String)neguse.get(i));
	    example.insert();
	    if (acro != null)
	    {
	      example.setDefinitionID(adid);
	      example.insert();
	      example.setDefinitionID(did);
	    }
	  }
	}
	  
	// Create comments
	if (cmtv != null)
	{
	  Comment comment = new Comment(dbConnection);
	  comment.setDatetimeStamp(df.format(date));
	  for (int i = 0; i < cmtv.size(); i++)
	  {
	    comment.setConceptID(cid);
	    comment.setComments((String)cmtv.get(i));
	    comment.insert();
	    if (acro != null)
	    {
	      comment.setConceptID(aid);
	      comment.insert();
	    }
	  }
	}
	
	if (warning_string != null)
	  tossOut(entry, warning_string, WARN);
	succeeded.println(entry + "\n");
      }
      closeDBConnection();
    }
    catch (SQLException E) {
      System.err.println("Database error!");
      System.err.println("Entries in succeeded have already been added.");
      System.err.println("SQLException: " + E.getMessage());
      System.exit(2);
    }
  }

  private static void usage() 
  {
    System.err.println ("Usage: PhraseBuilder dbhost[:[port][:dbname]] <template-file>");
    System.exit(1);
  }

  public static void main(String[] args)
  {
    Debug.debugging = false;
    if (args.length != 2)
      usage();
    PhraseBuilder pb = new PhraseBuilder(args[0], args[1]);
    pb.go();
  }
}
