package osa.attribute.atgrammar.xml;

import java.io.*;
import java.util.*;

import javax.xml.parsers.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

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



public class XMLWriter
  {

  protected Document document;


  public XMLWriter()
    {
    try
      {
      //создаем документ
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      DocumentBuilder builder = factory.newDocumentBuilder();
      document = builder.newDocument();
      }
    catch(ParserConfigurationException e)
      {
      e.printStackTrace();
      }
    }

  public Element createGrammarElement(Grammar grammar)
    {
    Element grammar_element=document.createElement("GRAMMAR");

    grammar_element.appendChild(createTypeSystemElement(grammar.getAttributeTypeSystem()));
    grammar_element.appendChild(createDictionaryElement(grammar.getDictionary()));
    grammar_element.appendChild(createProductionsListElement(grammar.getProductionsList()));
//    grammar_element.appendChild(createStartSymbolElement(grammar.getInitialSymbol()));

    return grammar_element;
    }

  public Element createTypeSystemElement(AttributeTypeSystem type_system)
    {
    ArrayList types_list=type_system.getTypesList();

    Element type_system_element=document.createElement("TYPE_SYSTEM");

    AttributeType temp_type;
    int size=types_list.size();
    for(int i=0;i<size;i++)
       {
       temp_type=(AttributeType)types_list.get(i);
       type_system_element.appendChild(createTypeElement(temp_type));
       }

    return type_system_element;
    }

  public Element createTypeElement(AttributeType type)
    {
    Element type_element=document.createElement("ATTRIBUTE_TYPE");
    type_element.setAttribute("NAME",type.getName());
    return type_element;
    }

  public Element createDictionaryElement(CommonDictionary dictionary)
    {
    Element dictionary_element=document.createElement("DICTIONARY");

    dictionary_element.appendChild(createNonTerminalsDictionaryElement(dictionary.getNonTerminals()));
    dictionary_element.appendChild(createTerminalsDictionaryElement(dictionary.getTerminals()));
    dictionary_element.appendChild(createOutputsDictionaryElement(dictionary.getOutputs()));

    return dictionary_element;
    }

  public Element createNonTerminalsDictionaryElement(Collection non_terminals_dict)
    {
    ArrayList non_terminals_list=new ArrayList(non_terminals_dict);
    Element non_terminals_dict_element=document.createElement("NON_TERMINALS");

    int symbols_count=non_terminals_list.size();
    NonTerminalSymbol temp_symbol;
    for(int i=0;i<symbols_count;i++)
       {
       temp_symbol=(NonTerminalSymbol)non_terminals_list.get(i);
       non_terminals_dict_element.appendChild(createNonTerminalSymbolElement(temp_symbol));
       }
    return non_terminals_dict_element;
    }

  public Element createTerminalsDictionaryElement(Collection terminals_dict)
    {
    ArrayList terminals_list=new ArrayList(terminals_dict);
    Element terminals_dict_element=document.createElement("TERMINALS");

    int symbols_count=terminals_list.size();
    TerminalSymbol temp_symbol;
    for(int i=0;i<symbols_count;i++)
       {
       temp_symbol=(TerminalSymbol)terminals_list.get(i);
       terminals_dict_element.appendChild(createTerminalSymbolElement(temp_symbol));
       }
    return terminals_dict_element;
    }

  public Element createOutputsDictionaryElement(Collection outputs_dict)
    {
    ArrayList outputs_list=new ArrayList(outputs_dict);
    Element outputs_dict_element=document.createElement("OUTPUTS");

    int symbols_count=outputs_list.size();
    OutputSymbol temp_symbol;
    for(int i=0;i<symbols_count;i++)
       {
       temp_symbol=(OutputSymbol)outputs_list.get(i);
       outputs_dict_element.appendChild(createOutputSymbolElement(temp_symbol));
       }
    return outputs_dict_element;
    }


  public Element createNonTerminalSymbolElement(NonTerminalSymbol symbol)
    {
    Element non_terminal_element=document.createElement("NON_TERMINAL");

    non_terminal_element.setAttribute("NAME",symbol.getOriginalName());

    File evaluator=symbol.getEvaluatorClassFile();
    if(evaluator!=null)
      {
      non_terminal_element.setAttribute("EVALUATOR",evaluator.getAbsolutePath());
      }
    else
      {
      non_terminal_element.setAttribute("EVALUATOR","");
      }

    int attrs_count=symbol.getAttrubutesCount();
    Attribute temp_attribute;
    for(int i=0;i<attrs_count;i++)
       {
       temp_attribute=symbol.getAttributeAt(i);
       non_terminal_element.appendChild(createAttributeElement(temp_attribute));
       }

    return non_terminal_element;
    }

  public Element createTerminalSymbolElement(TerminalSymbol symbol)
    {
    Element terminal_element=document.createElement("TERMINAL");

    terminal_element.setAttribute("NAME",symbol.getOriginalName());

    File evaluator=symbol.getEvaluatorClassFile();
    if(evaluator!=null)
      {
      terminal_element.setAttribute("EVALUATOR",evaluator.getAbsolutePath());
      }
    else
      {
      terminal_element.setAttribute("EVALUATOR","");
      }

     String lexical_value=symbol.getDefaultLexicalValue();
     if(lexical_value!=null)
       {
       terminal_element.setAttribute("DEFAULT_LEXICAL_VALUE",symbol.getDefaultLexicalValue());
       }
     else
       {
       terminal_element.setAttribute("DEFAULT_LEXICAL_VALUE","");
       }

    int attrs_count=symbol.getAttrubutesCount();
    Attribute temp_attribute;
    for(int i=0;i<attrs_count;i++)
       {
       temp_attribute=symbol.getAttributeAt(i);
       terminal_element.appendChild(createAttributeElement(temp_attribute));
       }
    return terminal_element;
    }

  public Element createOutputSymbolElement(OutputSymbol symbol)
    {
    Element output_element=document.createElement("OUTPUT");

    output_element.setAttribute("NAME",symbol.getOriginalName());

    File evaluator=symbol.getEvaluatorClassFile();
    if(evaluator!=null)
      {
      output_element.setAttribute("EVALUATOR",evaluator.getAbsolutePath());
      }
    else
      {
      output_element.setAttribute("EVALUATOR","");
      }

    int attrs_count=symbol.getAttrubutesCount();
    Attribute temp_attribute;
    for(int i=0;i<attrs_count;i++)
       {
       temp_attribute=symbol.getAttributeAt(i);
       output_element.appendChild(createAttributeElement(temp_attribute));
       }

    return output_element;
    }


  public Element createAttributeElement( Attribute attribute )
    {
    Element attribute_element=document.createElement("ATTRIBUTE");

    attribute_element.setAttribute("NAME",attribute.getName());
    attribute_element.setAttribute("TYPE",attribute.getType().getName());
    attribute_element.setAttribute("CLASS_TYPE",new Integer(attribute.getClassType()).toString());

    return attribute_element;
    }


  public Element createProductionsListElement(ArrayList productions_list)
    {
    Element productions_list_element=document.createElement("PRODUCTIONS");

    int productions_count=productions_list.size();


    GrammarProduction temp_production;

    for(int i=0;i<productions_count;i++)
       {
       temp_production=(GrammarProduction)productions_list.get(i);
       productions_list_element.appendChild(createProductionElement(temp_production));
       }

    return productions_list_element;
    }

  public Element createProductionElement(GrammarProduction production)
    {
    Symbol temp_symbol;
    Element temp_symbol_element;


    Element production_element=document.createElement("PRODUCTION");

    Element left_part_element=document.createElement("LEFT_PART");

    temp_symbol_element=document.createElement("NON_TERMINAL");
    temp_symbol_element.setAttribute("NAME",production.getLeftPart().getOriginalName());


    left_part_element.appendChild(temp_symbol_element);

    SymbolsString right_part=production.getRightPart();
    int right_part_len=right_part.getLength();
    Element right_part_element=document.createElement("RIGHT_PART");

    for(int i=0;i<right_part_len;i++)
       {
       temp_symbol=right_part.getSymbolAt(i);

       switch(temp_symbol.getType())
             {
             case Symbol.NON_TERMINAL_SYMBOL:
               temp_symbol_element=document.createElement("NON_TERMINAL");
               temp_symbol_element.setAttribute("NAME",temp_symbol.getOriginalName());
               break;
             case Symbol.TERMINAL_SYMBOL:
               temp_symbol_element=document.createElement("TERMINAL");
               temp_symbol_element.setAttribute("NAME",temp_symbol.getOriginalName());
               break;
             case Symbol.OUTPUT_SYMBOL:
               temp_symbol_element=document.createElement("OUTPUT");
               temp_symbol_element.setAttribute("NAME",temp_symbol.getOriginalName());
               break;
             default:
               temp_symbol_element=document.createElement("ERROR");
               temp_symbol_element.setAttribute("NAME",temp_symbol.getOriginalName());
             }
       right_part_element.appendChild(temp_symbol_element);
       }


    production_element.appendChild(left_part_element);
    production_element.appendChild(right_part_element);

    ArrayList assignments_list=production.getAssignmentsList();
    production_element.appendChild(createAssignmentsListElement(assignments_list));

    return production_element;
    }

  public Element createAssignmentsListElement(ArrayList assignments_list)
    {
    Element assignments_list_element=document.createElement("ASSIGNMENTS");

    int assignments_count = assignments_list.size();
    SimpleAssignment temp_assignment;
    for(int i=0;i<assignments_count;i++)
       {
       temp_assignment=(SimpleAssignment)assignments_list.get(i);
       assignments_list_element.appendChild(createAssignmentElement(temp_assignment));
       }
    return assignments_list_element;
    }

  public Element createAssignmentElement( SimpleAssignment assignment)
    {
    Element assignment_element=document.createElement("ASSIGNMENT");

    Element recipient = document.createElement("RECIPIENT");

    recipient.setAttribute("SYMBOL_LABEL", assignment.getRecipientSymbolLabel());
    recipient.setAttribute("SYMBOL_INDEX", new Integer(assignment.getRecipientSymbolIndex()).toString());
    recipient.setAttribute("ATTRIBUTE_LABEL",assignment.getRecipientAttributeLabel());
    recipient.setAttribute("ATTRIBURE_INDEX",new Integer(assignment.getRecipientAttributeIndex()).toString());

    Element source = document.createElement("SOURCE");
    source.setAttribute("SYMBOL_LABEL", assignment.getSourceSymbolLabel());
    source.setAttribute("SYMBOL_INDEX", new Integer(assignment.getSourceSymbolIndex()).toString());
    source.setAttribute("ATTRIBUTE_LABEL",assignment.getSourceAttributeLabel());
    source.setAttribute("ATTRIBURE_INDEX",new Integer(assignment.getSourceAttributeIndex()).toString());


    assignment_element.appendChild(recipient);
    assignment_element.appendChild(source);

    return assignment_element;
    }

  public Element createStartSymbolElement(NonTerminalSymbol start_symbol)
    {
    Element start_symbol_element=document.createElement("START_SYMBOL");

    start_symbol_element.setAttribute("NAME",start_symbol.getOriginalName());

    return start_symbol_element;
    }

  public void writeGrammarToXML(File file)
    {
    try
      {
      TransformerFactory tDom = TransformerFactory.newInstance();
      Transformer trans = tDom.newTransformer();
      trans.setOutputProperty("encoding", "windows-1251");
      trans.setOutputProperty("indent", "yes");


      Element grammar=createGrammarElement(Grammar.getInstance());

      DOMSource source = new DOMSource(grammar);

      StreamResult result = new StreamResult(file);
      trans.transform(source, result);
      }
    catch(TransformerException e)
      {
      e.printStackTrace();
      }
    }

  }

