package osa.attribute.atgrammar.grammar;

import java.util.*;
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 Grammar
  {
  protected ArrayList productions_list=new ArrayList();

  protected CommonDictionary dictionary;

  protected NonTerminalSymbol initial_symbol;

  protected int productions_count=0;

  protected static Grammar singleton=null;

  protected AttributeTypeSystem attribute_type_system;

  public static Grammar instantiateGrammar()
    {
    if(singleton==null)
      {
      singleton=new Grammar();
      }
    return singleton;
    }

  public static Grammar getInstance()
    {
    return singleton;
    }



  protected Grammar()
    {
    dictionary=new CommonDictionary(this);
    attribute_type_system=new AttributeTypeSystem();
    }

  public void createFromSyntax(osa.Grammar grammar)
    {
    clearGrammar();

    ArrayList[] productions_array=grammar.RT.m_rules;
    int size_of_grammar=grammar.RT.m_size;

    ArrayList temp_production;
    int temp_production_lenghth;
    // Enumerating strings that contains productions
    for(int productions_counter=0;
        productions_counter<size_of_grammar;
        productions_counter++)
       {
       temp_production=productions_array[productions_counter];
       temp_production_lenghth=temp_production.size();

       String temp_symbol_text_rep;
       String temp_symbol_name;
       Symbol temp_symbol;
       char first_char;

       NonTerminalSymbol left_part=null;
       SymbolsString right_part=new SymbolsString();

       // Creating new production
       dictionary.resetAllCounters();

       for(int symbols_counter=0;
           symbols_counter<temp_production_lenghth;
           symbols_counter++)
          {
          temp_symbol_text_rep=(String)temp_production.get(symbols_counter);
          first_char=temp_symbol_text_rep.charAt(0);
          switch(first_char)
                {
                case '<':
                  temp_symbol_name=temp_symbol_text_rep.substring(1,temp_symbol_text_rep.length()-1);
                  temp_symbol_name=temp_symbol_name.trim();
                  temp_symbol=dictionary.getNonTerminalSymbol(temp_symbol_name);
                  if(temp_symbol==null)
                    {
                    temp_symbol=new NonTerminalSymbol(temp_symbol_name);
                    dictionary.putNonTerminalSymbol((NonTerminalSymbol)temp_symbol);
                    }
                  //cloning
                  temp_symbol=(NonTerminalSymbol)temp_symbol.clone();
                  break;
/*                case '{':
                  temp_symbol_name=temp_symbol_text_rep.substring(1,temp_symbol_text_rep.length()-1);
                  temp_symbol_name=temp_symbol_name.trim();
                  temp_symbol=dictionary.getOutputSymbol(temp_symbol_name);
                  if(temp_symbol==null)
                    {
                    temp_symbol=new OutputSymbol(temp_symbol_name);
                    dictionary.putOutputSymbol((OutputSymbol)temp_symbol);
                    }
                  //cloning
                  temp_symbol=(OutputSymbol)temp_symbol.clone();
                  break;*/
                case '"':
                  temp_symbol_name=temp_symbol_text_rep.substring(1,temp_symbol_text_rep.length()-1);
                  temp_symbol_name=temp_symbol_name.trim();
                  temp_symbol=dictionary.getTerminalSymbol(temp_symbol_name);
                  if(temp_symbol==null)
                    {
                    temp_symbol=new TerminalSymbol(temp_symbol_name);
                    dictionary.putTerminalSymbol((TerminalSymbol)temp_symbol);
                    }
                  //cloning
                  temp_symbol=(TerminalSymbol)temp_symbol.clone();
                  break;
                default:
                  temp_symbol_name=temp_symbol_text_rep;
                  temp_symbol=dictionary.getTerminalSymbol(temp_symbol_name);
                  if(temp_symbol==null)
                    {
                    temp_symbol=new TerminalSymbol(temp_symbol_name);
                    dictionary.putTerminalSymbol((TerminalSymbol)temp_symbol);
                    }
                  //cloning
                  temp_symbol=(TerminalSymbol)temp_symbol.clone();
                }

          if(symbols_counter==0)
            {
            left_part=(NonTerminalSymbol)temp_symbol;
            if(productions_counter==0)
              {
              setInitialSymbol(left_part);
              }
            }
          else
            {
            right_part.appendSymbol(temp_symbol);
            }
          }
       addGrammarProduction(new GrammarProduction(this,left_part,right_part));
       }
    }

  public GrammarProduction getProductionAt(int index)
    {
    if(index<productions_count)
      {
      return (GrammarProduction) productions_list.get(index);
      }
    return null;
    }

  public void addGrammarProduction(GrammarProduction production)
    {
    productions_list.add(production);
    productions_count++;
    }

  public NonTerminalSymbol getInitialSymbol()
    {
    return initial_symbol;
    }

  public void setInitialSymbol(NonTerminalSymbol symbol)
    {
    initial_symbol=symbol;
    }



  public int getProductionsCount()
    {
    return productions_count;
    }

  public String toString()
    {
    String result=new String();
    for(int i=0;i<this.productions_count;i++)
       {
       result+=getProductionAt(i).toString();
       result+="\n";
       }
    return result;
    }

  public void clearGrammar()
    {
    dictionary.clearDictionary();
    productions_count=0;
    productions_list.clear();
    this.initial_symbol=null;
    }

  public CommonDictionary getDictionary()
    {
    return dictionary;
    }

  public AttributeTypeSystem getAttributeTypeSystem()
    {
    return attribute_type_system;
    }

  public void updateProductions()
    {
    GrammarProduction temp_production;
    for(int i=0;i<this.productions_count;i++)
       {
       temp_production=(GrammarProduction)productions_list.get(i);
       temp_production.updateProduction();
       }
    }

  public void updateAssignmentsLabels()
    {
    GrammarProduction temp_production;
    for(int i=0;i<this.productions_count;i++)
       {
       temp_production=(GrammarProduction)productions_list.get(i);
       temp_production.updateAssignmentLabels();
       }
    }

  public void updateAssignmentsIndexes()
    {
    GrammarProduction temp_production;
    for(int i=0;i<this.productions_count;i++)
       {
       temp_production=(GrammarProduction)productions_list.get(i);
       temp_production.updateAssignmentsIndexes();
       }
    }

  public ArrayList getProductionsList()
    {
    return productions_list;
    }

  public void setProductionList(ArrayList productions_list)
    {
    this.productions_list=productions_list;
    this.productions_count=productions_list.size();
    }

  }