import java.io.*;
import java.net.*;
import java.util.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.*;

public class KnowledgeBase
{
    private static BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
    private static Document theBase;
    private static Vector linkids;
    private static Vector links;
    
    private static int idno;

    private static int status;

    private static final int NOTHING_LOADED = 0;
    private static final int FILE_LOADED = 1;
    private static final int UNSAVED_CHANGES =2;
    
    public static void main(String[] args)
    {
	status = NOTHING_LOADED;

	while(true)
	    {
		System.out.println("1) Load file");
		System.out.println("2) Save file");
		System.out.println("3) Run query");
		System.out.println("4) New file");
		System.out.println("5) Quit");

		int i = getMenuOption(5);
		
		if(i==1)
		    load();
		
		if(i==2)
		    save();

		if(i==3)
		    query();		       		   

		if(i==4)
		    newBase();
		    
		if(i==5)
		    quit();
	    }
    }

    private static void quit()
    {
	if(status==UNSAVED_CHANGES)
	    {
		System.out.println("Changes not saved. Really quit?");
		System.out.println("1) Yes");
		System.out.println("2) No");

		if(getMenuOption(2) == 1)
		    System.exit(0);
	    }
	else
	    {
		System.exit(0);
	    }
    }

    private static void query()
    {
	if(status == NOTHING_LOADED)
	    {
		System.out.println("No file loaded");
		return;
	    }
	else
	    {
		System.out.println(theBase.getDocumentElement().getAttribute("opening"));
		ask("q1");
	    }
    }

    private static void newBase()
    {
	try
	    {
		if(status == UNSAVED_CHANGES)
		    {
			System.out.println("Discard changes?");
			System.out.println("1) Yes");
			System.out.println("2) No");

			if(getMenuOption(2) == 2)
			    return;
		    }


		DocumentBuilderFactory dbf = 
		    DocumentBuilderFactory.newInstance();

		dbf.setValidating(true);
		
		DocumentBuilder db = dbf.newDocumentBuilder();

		theBase = db.parse("mt.xml");

		System.out.println("What is this knowledge base about?");
		String inp = input.readLine();
		theBase.getDocumentElement().setAttribute("about" , inp);

		System.out.println("Enter opening, e.g. Think of an animal");
		inp = input.readLine();
		theBase.getDocumentElement().setAttribute("opening" , inp);

		System.out.println("Enter first question");
		inp = input.readLine();
		theBase.getElementById("q1").setAttribute("value" , inp);
		
		
		Vector links = new Vector();
		NodeList nl = theBase.getElementById("q1").getChildNodes();
	
		for(int i=0; i<nl.getLength(); i++)
		    {
			if(nl.item(i).getNodeType() == Node.ELEMENT_NODE)
			    {		
				links.add((Element)nl.item(i));
			    }
			
		    }

		System.out.println("Enter first reply");
		inp = input.readLine();
		((Element)links.get(0)).setAttribute("content" , inp);

		System.out.println("Enter item for this reply");
		inp = input.readLine();
		theBase.getElementById("a1").setAttribute("content" , inp);

		System.out.println("Enter second reply");
		inp = input.readLine();
		((Element)links.get(1)).setAttribute("content" , inp);

		System.out.println("Enter item for this reply");
		inp = input.readLine();
		theBase.getElementById("a2").setAttribute("content" , inp);

		status = UNSAVED_CHANGES;
		
		
	    }
	catch(IOException e)
	    {
		System.out.println(e);
	    }
	catch(ParserConfigurationException p)
	    {
		System.out.println(p);
	    }
	catch(SAXException s)
	    {
		System.out.println(s);
	    }
    }

    private static void save()
    {
	if(status == NOTHING_LOADED)
	    {
		System.out.println("No file loaded");
		return;
	    }

	try
	    {
		System.out.println("Enter filename:");
		String s = input.readLine();

		FileWriter fw = new FileWriter(s);
		fw.write("<?xml version='1.0'?>");
		fw.write("<!DOCTYPE base SYSTEM 'base.dtd'>");
		fw.write("\n " + theBase.getDocumentElement());
		fw.flush();
		fw.close();

		status = FILE_LOADED;
	    }
	catch(IOException e)
	    {
		System.out.println(e);
	    }
    }

    private static void fudge()
    {
	try
	    {
		FileWriter fw = new FileWriter("temp.xml");
		fw.write("<?xml version='1.0'?>");
		fw.write("<!DOCTYPE base SYSTEM 'base.dtd'>");
		fw.write("\n " + theBase.getDocumentElement());
		fw.flush();
		fw.close();

		DocumentBuilderFactory dbf = 
		    DocumentBuilderFactory.newInstance();

		dbf.setValidating(true);

		DocumentBuilder db = dbf.newDocumentBuilder();

		theBase = db.parse("temp.xml");

	    }
	catch(IOException e)
	    {
		System.out.println(e);
	    }
	catch(ParserConfigurationException p)
	    {
		System.out.println(p);
	    }
	catch(SAXException s)
	    {
		System.out.println(s);
	    }
    }

    private static void load()
    {
	try
	    {
		if(status == UNSAVED_CHANGES)
		    {
			System.out.println("Discard changes?");
			System.out.println("1) Yes");
			System.out.println("2) No");

			if(getMenuOption(2) == 2)
			    return;
		    }
		
		System.out.println("Enter filename");
		System.out.print("?");

		DocumentBuilderFactory dbf = 
		    DocumentBuilderFactory.newInstance();
		
		dbf.setValidating(true);

		DocumentBuilder db = dbf.newDocumentBuilder();
	
		theBase = db.parse(input.readLine());

		idno = Integer.parseInt(((Element)(theBase.getElementsByTagName("base").item(0))).getAttribute("idno"));

		status = FILE_LOADED;
		
	    }
	catch(IOException e)
	    {
		System.out.println(e);
	    }
	catch(ParserConfigurationException p)
	    {
		System.out.println(p);
	    }
	catch(SAXException s)
	    {
		System.out.println(s);
	    }
    }

    private static void ask(String id)
    {
	Vector linkids = new Vector();
	Vector links = new Vector();

	Element e = theBase.getElementById(id);

	
	System.out.println(e.getAttribute("value"));
	
	int items = 0;
	
	NodeList nl = e.getChildNodes();
	
	for(int i=0; i<nl.getLength(); i++)
	    {
		if(nl.item(i).getNodeType() == Node.ELEMENT_NODE)
		    {
			items++;
			System.out.print(items + ") ");
			System.out.println(((Element)nl.item(i)).getAttribute("content") );
			linkids.add(((Element)nl.item(i)).getAttribute("link"));
			links.add((Element)nl.item(i));
		    }
		
	    }
	
	System.out.println((items+1) + ") None of these" );
	System.out.println();
	
	int choice =  getMenuOption(items + 1);
	
	if(choice == items+1)
	    {
		newoption(id);
	    }
	else
	    {
		e = theBase.getElementById((String)linkids.get(choice -1));
		
		if(e.getTagName().equals("answer"))
		    guess((Element)links.get(choice -1));
		else
		    ask((String)linkids.get(choice -1));
	    }
	
    }

    private static void newoption(String id)
    {

	try
	    {
		Element e = theBase.getElementById(id);
		idno++;
		((Element)(theBase.getElementsByTagName("base").item(0))).setAttribute("idno" , "" + idno);

		System.out.println("What item were you thinking of?");
		System.out.print("?");
		String itemname = input.readLine();
	
		Element newans = theBase.createElement("answer");
		newans.setAttribute("id" , "a" + idno);
		newans.setAttribute("content" , itemname);

		theBase.getElementsByTagName("answers").item(0).appendChild(theBase.createTextNode(" "));
		theBase.getElementsByTagName("answers").item(0).appendChild(newans);
		theBase.getElementsByTagName("answers").item(0).appendChild(theBase.createTextNode("\n"));

		System.out.println("What is the answer for this item?");
		System.out.print("?");
		String itemvalue = input.readLine();

		Element newrep = theBase.createElement("reply");
		newrep.setAttribute("content" , itemvalue);
		newrep.setAttribute("link" , "a" + idno);

		e.appendChild(theBase.createTextNode("   "));
		e.appendChild(newrep);
                e.appendChild(theBase.createTextNode("\n"));

		fudge();
		status = UNSAVED_CHANGES;
	    }
	catch(IOException e)
	    {
		System.out.println(e);
	    }
    }

    private static void guess(Element oldReply)
    {
	Element e = theBase.getElementById(oldReply.getAttribute("link"));

	System.out.println("It is :");
	System.out.println(e.getAttribute("content"));

	System.out.println();
	System.out.println("1)OK ");
	System.out.println("2)Wrong");
	int i = getMenuOption(2);

	if(i==2)
	    addItem(oldReply);
    }

    private static void addItem(Element oldReply)
    {
	Element f = theBase.getElementById(oldReply.getAttribute("link"));
	idno++;
	((Element)(theBase.getElementsByTagName("base").item(0))).setAttribute("idno" , "" + idno);
	
	try
	    {
		System.out.println("What item were you thinking of?");
		System.out.print("?");
		String itemname = input.readLine();
	
		Element newans = theBase.createElement("answer");
		newans.setAttribute("id" , "a" + idno);
		newans.setAttribute("content" , itemname);


		theBase.getElementsByTagName("answers").item(0).appendChild(theBase.createTextNode(" "));
		theBase.getElementsByTagName("answers").item(0).appendChild(newans);
		theBase.getElementsByTagName("answers").item(0).appendChild(theBase.createTextNode("\n"));

		System.out.println("Enter a question to tell the two apart");
		String theq = input.readLine();

		Element newq = theBase.createElement("question");
		newq.setAttribute("id" , "q" + idno);
		newq.setAttribute("value" , theq);
		newq.setAttribute("media" , "text");

		theBase.getElementsByTagName("questions").item(0).appendChild(theBase.createTextNode("\n"));
		theBase.getElementsByTagName("questions").item(0).appendChild(newq);
		theBase.getElementsByTagName("questions").item(0).appendChild(theBase.createTextNode("\n"));

		System.out.println("The answer for " + itemname + "?");
		String replycnew = input.readLine();

		Element replynewitem = theBase.createElement("reply");
		replynewitem.setAttribute("content" , replycnew);
		replynewitem.setAttribute("link" , "a" + idno);

		newq.appendChild(theBase.createTextNode("\n   "));
		newq.appendChild(replynewitem);
		newq.appendChild(theBase.createTextNode("\n"));
		
		
		System.out.println("The answer for " + f.getAttribute("content") + "?");
		String replycold = input.readLine();

		Element replyolditem = theBase.createElement("reply");
		replyolditem.setAttribute("content" , replycold);
		replyolditem.setAttribute("link" , oldReply.getAttribute("link"));

		newq.appendChild(theBase.createTextNode("   "));
		newq.appendChild(replyolditem);
		newq.appendChild(theBase.createTextNode("\n"));
		

		oldReply.setAttribute("link" , "q" + idno);

		fudge();
		status = UNSAVED_CHANGES;
		
	    }
	catch(IOException e)
	    {
		System.out.println(e);
	    }
    }

    
    private static int getMenuOption(int numoptions)
    {       
	boolean notyet = true;
	while(notyet)
	    {
		System.out.print("?");
		String s = new String("");
		
		try
		    {
			s = input.readLine();
		    }
		catch(IOException e)
		    {
			System.out.println(e);
		    }
		
		int i;
		
		try
		    {
			i = Integer.parseInt(s);
			
			if(i<=numoptions && i>0)
			    {
				return i;
			    }
			else
			    {
				System.out.println("Not an option");
			    }
		    }
		catch(NumberFormatException e)
		    {
			System.out.println("Not an option");
		    }
		
		
	    }
	//never here;
	return -128;
	
    }

    
}
