package 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 SimpleAssignment
  {
  protected int recipient_symbol_index;
  protected int recipient_attribute_index;
  protected int source_symbol_index;
  protected int source_attribute_index;

  protected String recipient_symbol_label;
  protected String recipient_attribute_label;
  protected String source_symbol_label;
  protected String source_attribute_label;

  protected Symbol recipient_symbol;
  protected Attribute recipient_attribute;
  protected Symbol source_symbol;
  protected Attribute source_attribute;


  protected GrammarProduction production_reference;

  protected boolean is_valid=false;

  protected class IndexesPair
    {
    public int symbol_index;
    public int attribute_index;

    public IndexesPair()
      {
      symbol_index=-1;
      attribute_index=-1;
      }

    public IndexesPair(int ymbol_index,int attribute_index)
      {
      this.symbol_index=symbol_index;
      this.attribute_index=attribute_index;
      }

    public boolean isValid()
      {
      return (symbol_index>=0)&&(attribute_index>=0);
      }
    }

  protected class LabelsPair
    {
    public String symbol_label;
    public String attribute_label;

    public LabelsPair()
      {
      symbol_label="";
      attribute_label="";
      }

    public LabelsPair(String symbol_label,String attribute_label)
      {
      this.symbol_label=symbol_label;
      this.attribute_label=attribute_label;
      }

    public boolean isValid()
      {
      return !((symbol_label.equals(""))||(attribute_label.equals("")));
      }
    }

  public SimpleAssignment(GrammarProduction production_reference)
    {
    recipient_symbol_index=-1;
    recipient_attribute_index=-1;
    source_symbol_index=-1;
    source_attribute_index=-1;

    recipient_symbol_label="";
    recipient_attribute_label="";
    source_symbol_label="";
    source_attribute_label="";
    }

  public SimpleAssignment(GrammarProduction production_reference,
                          int recipient_symbol_index,
                          int recipient_attribute_index,
                          int source_symbol_index,
                          int source_attribute_index)
    {
    this.production_reference=production_reference;

    this.recipient_symbol_index=recipient_symbol_index;
    this.recipient_attribute_index=recipient_attribute_index;
    this.source_symbol_index=source_symbol_index;
    this.source_attribute_index=source_attribute_index;

    this.updateLabels();
    }

  public SimpleAssignment(GrammarProduction production_reference,
                          String recipient_symbol_label,
                          String recipient_attribute_label,
                          String source_symbol_label,
                          String source_attribute_label)
    {
    this.production_reference=production_reference;

    this.recipient_symbol_label=recipient_symbol_label;
    this.recipient_attribute_label=recipient_attribute_label;
    this.source_symbol_label=source_symbol_label;
    this.source_attribute_label=source_attribute_label;

    this.updateIndexes();
    }

  // setters
  public void setRecipientSymbolIndex(int recipient_symbol_index)
    {
    this.recipient_symbol_index=recipient_symbol_index;
    }

  public void setRecipientAttributeIndex(int recipient_attribute_index)
    {
    this.recipient_attribute_index=recipient_attribute_index;
    }

  public void setSourceSymbolIndex(int source_symbol_index)
    {
    this.source_symbol_index=source_symbol_index;
    }

  public void setSourceAttributeIndex(int source_attribute_index)
    {
    this.source_attribute_index=source_attribute_index;
    }



  public void setRecipientSymbolLabel(String recipient_symbol_label)
    {
    this.recipient_symbol_label=recipient_symbol_label;
    }

  public void setRecipientAttributeLabel(String recipient_attribute_label)
    {
    this.recipient_attribute_label=recipient_attribute_label;
    }

  public void setSourceSymbolLabel(String source_symbol_label)
    {
    this.source_symbol_label=source_symbol_label;
    }

  public void setSourceAttributeLabel(String source_attribute_label)
    {
    this.source_attribute_label=source_attribute_label;
    }




  // getters
  public int getRecipientSymbolIndex()
    {
    return recipient_symbol_index;
    }

  public int getRecipientAttributeIndex()
    {
    return recipient_attribute_index;
    }

  public int getSourceSymbolIndex()
    {
    return source_symbol_index;
    }

  public int getSourceAttributeIndex()
    {
    return source_attribute_index;
    }





  public String getRecipientSymbolLabel()
    {
    return recipient_symbol_label;
    }

  public String getRecipientAttributeLabel()
    {
    return recipient_attribute_label;
    }

  public String getSourceSymbolLabel()
    {
    return source_symbol_label;
    }

  public String getSourceAttributeLabel()
    {
    return source_attribute_label;
    }



  public void executeAssignment(NonTerminalSymbol non_terminal,
                                SymbolsString string)
    {
    Symbol source;
    Symbol recipient;
    if(source_attribute_index==0)
      {
      source=non_terminal;
      }
    else
      {
      source=string.getSymbolAt(source_attribute_index-1);
      }

    if(recipient_attribute_index==0)
      {
      recipient=non_terminal;
      }
    else
      {
      recipient=string.getSymbolAt(recipient_attribute_index-1);
      }

    // assignation
    recipient.
        getAttributeAt(recipient_attribute_index).
        assign(source.getAttributeAt(source_attribute_index));

    }


  public void updateIndexes()
    {
    System.err.println("Update indexes!!!");
    LabelsPair source=new LabelsPair();
    LabelsPair recipient=new LabelsPair();

    IndexesPair updated_source;
    IndexesPair updated_recipient;

    source.symbol_label=source_symbol_label;
    source.attribute_label=source_attribute_label;

    recipient.symbol_label=recipient_symbol_label;
    recipient.attribute_label=recipient_attribute_label;

    updated_source=findIndexes(source);
    updated_recipient=findIndexes(recipient);

    this.source_symbol_index=updated_source.symbol_index;
    this.source_attribute_index=updated_source.attribute_index;
    this.recipient_symbol_index=updated_recipient.symbol_index;
    this.recipient_attribute_index=updated_recipient.attribute_index;

    System.err.println(recipient_symbol_label+
                       recipient_attribute_label+
                       source_symbol_label+
                       source_attribute_label
                       );

    is_valid=updated_source.isValid()||updated_recipient.isValid();
    }

  public void updateLabels()
    {
    IndexesPair source=new IndexesPair();
    IndexesPair recipient=new IndexesPair();

    LabelsPair updated_source;
    LabelsPair updated_recipient;

    source.symbol_index=source_symbol_index;
    source.symbol_index=source_attribute_index;

    recipient.symbol_index=recipient_symbol_index;
    recipient.symbol_index=recipient_attribute_index;

    updated_source=findLabels(source);
    updated_recipient=findLabels(recipient);


    this.source_symbol_label=updated_source.symbol_label;
    this.source_attribute_label=updated_source.attribute_label;
    this.recipient_symbol_label=updated_recipient.symbol_label;
    this.recipient_attribute_label=updated_recipient.attribute_label;

    is_valid=updated_source.isValid()||updated_recipient.isValid();
    }

  public void isLATValid()
    {

    }

  public boolean isTypesCompatible()
    {
    if(is_valid)
      {
      Attribute source_attribute=getSourceAttribute();
      Attribute recipient_attribute=getRecipientAttribute();
      if(source_attribute.getType()==recipient_attribute.getType()) // correct in redisign
        {
        return true;
        }
      else
        {
        return false;
        }
      }
    return false;
    }

  public boolean isValid()
    {
    return is_valid;
    }

  protected IndexesPair findIndexes(LabelsPair labels_pair)
    {
    Symbol symbol=null;
    Attribute attribute=null;

    IndexesPair result_pair=new IndexesPair(); // assuming that indexes alredy setted to -1

    Symbol temp_symbol=null;
    SymbolsString temp_symbols_string;
    // find symbol
    temp_symbol=production_reference.getLeftPart();
    if(temp_symbol.toString().equals(labels_pair.symbol_label))
      {
      result_pair.symbol_index=0;
      symbol=temp_symbol;
      }
    else
      {
      temp_symbols_string=production_reference.getRightPart();
      int len=temp_symbols_string.getLength();
      for(int i=0;i<len;i++)
         {
         temp_symbol=temp_symbols_string.getSymbolAt(i);
         if(temp_symbol.toString().equals(labels_pair.symbol_label))
           {
           result_pair.symbol_index=i+1;
           symbol=temp_symbol;
           break;
           }
         }
      }

    if(symbol!=null)
      {
      // find attrbute
      int at_list_len=symbol.getAttrubutesCount();
      for(int i=0;i<at_list_len;i++)
         {
         if(symbol.getAttributeAt(i).getName().equals(labels_pair.attribute_label))
           {
           result_pair.attribute_index=i;
           break;
           }
         }
      }

    return result_pair;
    }

  protected LabelsPair findLabels(IndexesPair indexes_pair)
    {
    Symbol symbol=null;
    SymbolsString temp_symbols_string=null;
    LabelsPair result_pair=new LabelsPair();// assuming that indexes alredy setted to ""

    // find symbol
    if(indexes_pair.symbol_index==0)
      {
      symbol=production_reference.getLeftPart();
      result_pair.symbol_label=symbol.toString();
      }
    else
      {
      temp_symbols_string=production_reference.getRightPart();
      if(temp_symbols_string.getLength()>=indexes_pair.symbol_index-1)
        {
        symbol=temp_symbols_string.getSymbolAt(indexes_pair.symbol_index-1);
        result_pair.symbol_label=symbol.toString();
        }
      }

    if(symbol!=null)
      {
      //find attribute
      if(symbol.getAttrubutesCount()>=indexes_pair.attribute_index)
        {
        result_pair.attribute_label=symbol.getAttributeAt(indexes_pair.attribute_index).getName();
        }
      }
    return result_pair;
    }


  public GrammarProduction getOwner()
    {
    return production_reference;
    }

  public void setOwner(GrammarProduction owner)
    {
    production_reference=owner;
    }

  protected void updateReferences()
    {
    updateIndexes();

    // recipient updating
    if(recipient_symbol_index==-1)
      {
      recipient_symbol=null;
      }
    else
      {
      if(recipient_symbol_index==0)
        {
        recipient_symbol=production_reference.getLeftPart();
        }
      else
        {
        recipient_symbol=production_reference.getRightPart().getSymbolAt(recipient_symbol_index);
        }
      if(recipient_attribute_index==-1)
        {
        recipient_attribute=null;
        }
      else
        {
        recipient_attribute=recipient_symbol.getAttributeAt(recipient_attribute_index);
        }
      }

      // source updating
      if(source_symbol_index==-1)
        {
        source_symbol=null;
        }
      else
        {
        if(source_symbol_index==0)
          {
          source_symbol=production_reference.getLeftPart();
          }
        else
          {
          source_symbol=production_reference.getRightPart().getSymbolAt(source_symbol_index);
          }
        if(source_attribute_index==-1)
          {
          source_attribute=null;
          }
        else
          {
          source_attribute=source_symbol.getAttributeAt(source_attribute_index);
          }
        }
    }

  public Symbol getRecipientSymbol()
    {
    updateReferences();
    return recipient_symbol;
    }

  public Attribute getRecipientAttribute()
    {
    updateReferences();
    return recipient_attribute;
    }

  public Symbol getSourceSymbol()
    {
    updateReferences();
    return source_symbol;
    }

  public Attribute getSourceAttribute()
    {
    updateReferences();
    return source_attribute;
    }
  }