package osa.attribute.atgrammar.xml;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import java.io.File;
import java.io.IOException;

import org.w3c.dom.Document;
import org.w3c.dom.DOMException;

import org.w3c.dom.*;

import osa.attribute.atgrammar.grammar.*;
import osa.attribute.atgrammar.grammar.symbols.*;


/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2005</p>
 * <p>Company: </p>
 * @author not attributable
 * @version 1.0
 */

public class XMLParser
  {
  // Global value so it can be ref'd by the tree-adapter
  protected Document document;

  protected Grammar grammar_reference;


  public XMLParser(Grammar grammar_reference)
    {
    this.grammar_reference=grammar_reference;
    }

  public void parseXMLFile(File file)
    {
    DocumentBuilderFactory factory =DocumentBuilderFactory.newInstance();
    //factory.setValidating(true);
    //factory.setNamespaceAware(true);
    try{
       DocumentBuilder builder = factory.newDocumentBuilder();
       document = builder.parse( file );
       }
    catch(SAXException sxe)
       {
       // Error generated during parsing)
       Exception  x = sxe;
       if(sxe.getException() != null)
         {
         x = sxe.getException();
         }
         x.printStackTrace();
       }
    catch(ParserConfigurationException pce)
       {
       // Parser with specified options can't be built
       pce.printStackTrace();
       }
    catch(IOException ioe)
       {
       // I/O error
       ioe.printStackTrace();
       }


    NodeList children=document.getChildNodes();
    int children_count=children.getLength();
    Node temp_node;
    for(int i=0;i<children_count;i++)
       {
       temp_node = children.item(i);
       if(temp_node.getNodeType()==Node.ELEMENT_NODE)
         {
         if(temp_node.getNodeName().equals("GRAMMAR"))
           {
           buildGrammar(temp_node);
           }
         }
       }
    }

  public void buildGrammar(Node grammar_element)
    {
    NodeList nodes_list=grammar_element.getChildNodes();

    Node temp_node;
    int children_count=nodes_list.getLength();
    for(int i=0;i<children_count;i++)
       {
       temp_node=nodes_list.item(i);
       if(temp_node.getNodeType()==Node.ELEMENT_NODE)
         {
         String node_name=temp_node.getNodeName();
         if(node_name.equals("TYPE_SYSTEM"))
           {
           System.err.println("type system");
           buildTypeSystem(temp_node);
           }
         else
           {
           if(node_name.equals("DICTIONARY"))
             {
             System.err.println("dictionary");
             buildDictionary(temp_node);
             }
           else
             {
             if(node_name.equals("PRODUCTIONS"))
               {
               System.err.println("productions");
               buildProductions(temp_node);
               }
             else
               {
               if(node_name.equals("START_SYMBOL"))
                 {
                 System.err.println("start_symbol");
                 buildInitialSymbol(temp_node);
                 }
               }
             }
           }
         }
       }
    }

  public void buildTypeSystem(Node type_system_node)
    {
    AttributeTypeSystem result=grammar_reference.getAttributeTypeSystem();

    NodeList children=type_system_node.getChildNodes();

    int children_count=children.getLength();

    Node temp_node;
    for(int i=0;i<children_count;i++)
       {
       temp_node=children.item(i);
       if(temp_node.getNodeType()==Node.ELEMENT_NODE)
         {
         result.addAttributeType(buildType(temp_node));
         }
       }
    }

  public AttributeType buildType(Node type_node)
    {
    AttributeType result;
    String type_name;

    NamedNodeMap attributes=type_node.getAttributes();
    type_name=attributes.getNamedItem("NAME").getNodeValue();



    result=new AttributeType(type_name,false);

    return result;
    }


  public void buildDictionary( Node dictionary_node )
    {
    NodeList dictionaries=dictionary_node.getChildNodes();

    int child_count=dictionaries.getLength();
    Node temp_node;
    for(int i=0;i<child_count;i++)
       {
       temp_node=dictionaries.item(i);
       if(temp_node.getNodeType()==Node.ELEMENT_NODE)
         {
         if(temp_node.getNodeName().equals("NON_TERMINALS")||
            temp_node.getNodeName().equals("TERMINALS")||
            temp_node.getNodeName().equals("OUTPUTS"))
           {
           buildSymbols(temp_node);
           }
         }
       }
    }



  public void buildSymbols(Node symbols_node)
    {
    NodeList children = symbols_node.getChildNodes();

    int child_count=children.getLength();
    Node temp_node;
    for(int i=0;i<child_count;i++)
       {
       temp_node=children.item(i);
       if(temp_node.getNodeType()==Node.ELEMENT_NODE)
         {
         buildSymbol(temp_node);
         }
       }
    }

  public void buildSymbol(Node symbol_node)
    {
    String symbol_type=symbol_node.getNodeName();
    NamedNodeMap attrs=symbol_node.getAttributes();

    String symbol_name=attrs.getNamedItem("NAME").getNodeValue();
    String evaluator_path_name=attrs.getNamedItem("EVALUATOR").getNodeValue();

    Symbol new_symbol=null;

    if(symbol_type.equals("NON_TERMINAL"))
      {
      new_symbol=new NonTerminalSymbol(symbol_name);
      new_symbol.setEvaluatorClassFile(new File(evaluator_path_name));
      grammar_reference.getDictionary().putNonTerminalSymbol((NonTerminalSymbol)new_symbol);
      }
    else
      {
      if(symbol_type.equals("TERMINAL"))
        {
        new_symbol=new TerminalSymbol(symbol_name);
        new_symbol.setEvaluatorClassFile(new File(evaluator_path_name));
        ((TerminalSymbol)new_symbol).setDefaultLexicalValue(attrs.getNamedItem("DEFAULT_LEXICAL_VALUE").getNodeValue());
        grammar_reference.getDictionary().putTerminalSymbol((TerminalSymbol)new_symbol);
        }
      else
        {
        if(symbol_type.equals("OUTPUT"))
          {
          new_symbol=new OutputSymbol(symbol_name);
          new_symbol.setEvaluatorClassFile(new File(evaluator_path_name));
          grammar_reference.getDictionary().putOutputSymbol((OutputSymbol)new_symbol);
          }
        }
      }

    NodeList attributes=symbol_node.getChildNodes();

    int children_count=attributes.getLength();
    Node temp_node;
    Attribute temp_attribute;
    for(int i=0;i<children_count;i++)
       {
       temp_node=attributes.item(i);
       if(temp_node.getNodeType()==Node.ELEMENT_NODE)
         {
         temp_attribute=buildAttribute(temp_node);
         new_symbol.addAttribute(temp_attribute);
         }
       }
    }


  public Attribute buildAttribute(Node attribute_node)
    {
    Attribute result_attribute;
    NamedNodeMap attrs=attribute_node.getAttributes();
    String name=attrs.getNamedItem("NAME").getNodeValue();
    String type=attrs.getNamedItem("TYPE").getNodeValue();
    String class_type=attrs.getNamedItem("CLASS_TYPE").getNodeValue();

    result_attribute=new Attribute(name);
    result_attribute.setType(grammar_reference.getAttributeTypeSystem().getAttributeType(type));
    result_attribute.setClassType(Integer.parseInt(class_type));

    return result_attribute;
    }

  public void buildProductions(Node productions_node)
    {
    NodeList children=productions_node.getChildNodes();
    int children_count=children.getLength();
    Node temp_node;
    for(int i=0;i<children_count;i++)
       {
       temp_node=children.item(i);
       System.err.println("node "+temp_node.getNodeName());
       if(temp_node.getNodeType()==Node.ELEMENT_NODE)
         {
         System.err.println("Production:");
         buildProduction(temp_node);
         }
       }
    }

  public void buildProduction(Node production_node)
    {
    NodeList children=production_node.getChildNodes();
    int children_count=children.getLength();
    Node temp_node;

    GrammarProduction temp_production=null;
    NonTerminalSymbol temp_left_part=null;
    SymbolsString temp_right_part=null;

    for(int i=0;i<children_count;i++)
       {
       temp_node=children.item(i);
       if(temp_node.getNodeType()==Node.ELEMENT_NODE)
         {
         if(temp_node.getNodeName().equals("LEFT_PART"))
           {
           grammar_reference.getDictionary().resetAllCounters();
           temp_left_part=(NonTerminalSymbol)buildLeftPart(temp_node).clone();
           }
         else
           {
           if(temp_node.getNodeName().equals("RIGHT_PART"))
             {
             temp_right_part=buildSymbolsString(temp_node);
             temp_production=new GrammarProduction(grammar_reference,
                                                   temp_left_part,
                                                   temp_right_part);
             System.err.println("Production"+temp_production.toString());
             }
           else
             {
             if(temp_node.getNodeName().equals("ASSIGNMENTS"))
               {
               buildAssignmentsList(temp_production,temp_node);
               }
             }
           }
         }
       }
    grammar_reference.addGrammarProduction(temp_production);
    }

  public NonTerminalSymbol buildLeftPart(Node left_part_node)
    {
    NodeList children=left_part_node.getChildNodes();
    int children_count=children.getLength();

    Symbol result=null;

    Node temp_node;
    for(int i=0;i<children_count;i++)
       {
       temp_node=children.item(i);
       if(temp_node.getNodeType()==Node.ELEMENT_NODE)
         {
         result=buildSymbolReference(temp_node);
         }
       }
    return (NonTerminalSymbol)result;
    }

  public SymbolsString buildSymbolsString(Node symbols_string_node)
    {
    NodeList children=symbols_string_node.getChildNodes();
    int children_count=children.getLength();

    SymbolsString result=new SymbolsString();

    Symbol temp_symbol;

    Node temp_node;
    for(int i=0;i<children_count;i++)
      {
      temp_node=children.item(i);
      if(temp_node.getNodeType()==Node.ELEMENT_NODE)
        {
        temp_symbol=buildSymbolReference(temp_node);
        result.appendSymbol((Symbol)temp_symbol.clone());
        }
      }
    return result;
    }


  public void buildAssignmentsList(GrammarProduction production, Node assignments_node)
    {
    NodeList children=assignments_node.getChildNodes();
    int children_count=children.getLength();
    Node temp_node;

    for(int i=0;i<children_count;i++)
       {
       temp_node=children.item(i);
       if(temp_node.getNodeType()==Node.ELEMENT_NODE)
         {
         buildAssignment(production,temp_node);
         }
       }
    }

  public void buildAssignment(GrammarProduction production, Node assignment_node)
    {
    NodeList children=assignment_node.getChildNodes();
    int children_count=children.getLength();
    Node temp_node;

    String recipient_symbol_label="";
    int recipient_symbol_index=-1;
    String recipient_attribute_label="";
    int recipient_attribute_index=-1;

    String source_symbol_label="";
    int source_symbol_index=-1;
    String source_attribute_label="";
    int source_attribute_index=-1;

    for(int i=0;i<children_count;i++)
       {
       temp_node=children.item(i);
       if(temp_node.getNodeType()==Node.ELEMENT_NODE)
         {
         if(temp_node.getNodeName().equals("RECIPIENT"))
           {
           NamedNodeMap attrs=temp_node.getAttributes();
           recipient_symbol_label=attrs.getNamedItem("SYMBOL_LABEL").getNodeValue();
           recipient_symbol_index=Integer.parseInt(attrs.getNamedItem("SYMBOL_INDEX").getNodeValue());
           recipient_attribute_label=attrs.getNamedItem("ATTRIBUTE_LABEL").getNodeValue();
           recipient_attribute_index=Integer.parseInt(attrs.getNamedItem("ATTRIBUTE_INDEX").getNodeValue());
           }
         else
           {
           if(temp_node.getNodeName().equals("SOURCE"))
             {
             NamedNodeMap attrs=temp_node.getAttributes();
             source_symbol_label=attrs.getNamedItem("SYMBOL_LABEL").getNodeValue();
             source_symbol_index=Integer.parseInt(attrs.getNamedItem("SYMBOL_INDEX").getNodeValue());
             source_attribute_label=attrs.getNamedItem("ATTRIBUTE_LABEL").getNodeValue();
             source_attribute_index=Integer.parseInt(attrs.getNamedItem("ATTRIBUTE_INDEX").getNodeValue());
             }
           }
         }
       }

    SimpleAssignment assignment=new SimpleAssignment(production);

    assignment.setRecipientSymbolLabel(recipient_symbol_label);
    assignment.setRecipientSymbolIndex(recipient_symbol_index);
    assignment.setRecipientAttributeLabel(recipient_attribute_label);
    assignment.setRecipientAttributeIndex(recipient_attribute_index);

    assignment.setSourceSymbolLabel(source_symbol_label);
    assignment.setSourceSymbolIndex(source_symbol_index);
    assignment.setSourceAttributeLabel(source_attribute_label);
    assignment.setSourceAttributeIndex(source_attribute_index);

    production.addAssignment(assignment);
    }



  public Symbol buildSymbolReference(Node symbol_node)
    {
    String symbol_type;
    String symbol_name;

    symbol_type=symbol_node.getNodeName();
    symbol_name=symbol_node.getAttributes().getNamedItem("NAME").getNodeValue();

    Symbol result=null;

    if(symbol_type.equals("NON_TERMINAL"))
      {
      result=grammar_reference.getDictionary().getNonTerminalSymbol(symbol_name);
      }
    else
      {
      if(symbol_type.equals("TERMINAL"))
        {
        result=grammar_reference.getDictionary().getTerminalSymbol(symbol_name);
        }
      else
        {
        if(symbol_type.equals("OUTPUT"))
          {
          result=grammar_reference.getDictionary().getOutputSymbol(symbol_name);
          }
        }
      }
    return result;
    }

  public void buildInitialSymbol(Node initial_symbol_node)
    {
    String initial_symbol_name=initial_symbol_node.
                               getAttributes().
                               getNamedItem("NAME").
                               getNodeValue();

    NonTerminalSymbol initial=grammar_reference.getDictionary().getNonTerminalSymbol(initial_symbol_name);

    grammar_reference.setInitialSymbol(initial);
    }

  }

