package osa;
import java.util.*;
import javax.swing.*;

public class Wasp
{
  private boolean minTerminalCountReached;
  private int terminalsAmount;
  private int minChainLength;
  private MainFrame wFrame;
  private JSlider jSlider1 = new JSlider();
  private Recognizer RC=new Recognizer();
  private Grammar GR=new Grammar(wFrame);
  public Wasp(MainFrame pFrame)
      {wFrame = pFrame;}

  void Analyse()
  {
    wFrame.alRuleList.clear();
    wFrame.alNonTerminalList.clear();
    wFrame.alTerminalList.clear();
    int result;
    GR=new Grammar(wFrame);
    String t=new String();
    t=wFrame.ArrayListToString(wFrame.alMainTextArea);
    result=GR.GrammarInit(wFrame.alMainTextArea);                        // Анализируем грамматику, стрим списки Т и N, правил, опередляем тип

    if(result==3||result==4)
    {
      for(int i=0;i<GR.NT.m_Ntable.size();i++)
      {
        wFrame.alNonTerminalList.add(" "+GR.NT.m_Ntable.get(i)+GR.nu[i]);
      }
      for(int i=0;i<GR.TT.m_Ttable.size();i++)
      {
        wFrame.alTerminalList.add(" "+GR.TT.m_Ttable.get(i));
      }
      for(int i=0;i<GR.RT.m_size;i++){t="";
      for(int j=1;j<GR.RT.m_rules[i].size();j++)
        t+=GR.RT.m_rules[i].get(j);
      wFrame.alRuleList.add(" "+(i+1)+":  "+GR.RT.m_rules[i].get(0)+"  -->  "+t);}
      }else if(result==2)
      {
        for(int i=0;i<GR.RT.m_size;i++){t="";
        for(int j=1;j<GR.RT.m_rules[i].size();j++)
          t+=GR.RT.m_rules[i].get(j);
        wFrame.alRuleList.add(" "+(i+1)+":  "+GR.RT.m_rules[i].get(0)+"  -->  "+t);}
        for(int i=0;i<GR.N_2.size();i++) // выводим список непроизводящих
          wFrame.alNonTerminalList.add(" "+GR.N_2.get(i));
        for(int i=0;i<GR.D_2.size();i++) // выводим список недостижимых
          wFrame.alTerminalList.add(" "+GR.D_2.get(i));
      }
      else for(int i=0;i<GR.err;i++){
        t="";
        if(GR.RE[i].type==0)t="Пропущен символ '\"'";
        if(GR.RE[i].type==1)t="Пропущен символ '>'";
        if(GR.RE[i].type==2)t="Пропущена правая часть правила";
        if(GR.RE[i].type==3)t="Недопустимый символ";
        if(GR.RE[i].type==4)t="Пропущен символ '|'";
        if(GR.RE[i].type==5)t="Лишнее '$'";
        if(GR.RE[i].type==6)t="В грамматике слишком много правил.";
        if(GR.RE[i].type==7)t="Пропущен символ ':'";
        if(GR.RE[i].type==8)t="Пропущен символ '='";
      wFrame.alRuleList.add(" "+"Ошибка в строке: "+(GR.RE[i].str+1)+"    "+t);}
      wFrame.AnalyseReturn=result;
  }

  ArrayList[] AR=new ArrayList[2000];        // Список альтернативных правил
  ArrayList alCurrentChain=new ArrayList();  // Выводимая цепочка
  int a=0;                                   // Число альтернатив
  int noNt=0;                                // Флаг равен 1 если в выводимой цепочке есть нетрминал
  String st="";
  Random rn=new Random();
  int ii,u,r,n=0;
  boolean StyleFlag;
  public void BeginChainGeneration()
  {
    ii=0; u=0; r=0;
    wFrame.CurrentStepNumber=ii;
    ++n; if(n>4) n=0; alCurrentChain=new ArrayList();
    alCurrentChain.add(0,GR.NT.m_Ntable.get(0));
    wFrame.alCurrentChain.clear();
    wFrame.alCurrentChain.add(0,GR.NT.m_Ntable.get(0));
    wFrame.sLength=GR.NT.m_Ntable.get(0).toString().length();
    wFrame.alCurrentRules.clear();
    wFrame.alCurrentChain.set(0,alCurrentChain.toString());
    BuildAlRulesList(-1); // Строим начальный список альтернатив
    String t;             // Добавляем новый список альтернатив
    for(int i=0;i<a;i++){t="";
    for(int j=1;j<AR[i].size();j++)
      t+=AR[i].get(j);
    wFrame.alCurrentRules.add(" "+(i+1)+":  "+AR[i].get(0)+"  -->  "+t);}
  }


  public void CurrentChainUpdate()
  {
    //if(StyleFlag!=wFrame.RightStyle){BeginChainGeneration();} // ОБРАТИ ВНИМАНИЕ СЮДА !!! <<<<<<<<<<<<<<<<-----
    wFrame.CurrentStepNumber=ii;
    wFrame.alCurrentRules.clear();
    wFrame.alCurrentChain.set(0,alCurrentChain.toString());
    String t; st="";                              // Добавляем новый список альтернатив
    for(int i=0;i<alCurrentChain.size();i++)
      st+=alCurrentChain.get(i).toString();
    wFrame.alCurrentChain.set(0,st);
    if(alCurrentChain.toString().length()<=20000){
      noNt=0;
      for(int i=0;i<alCurrentChain.size();i++)
        if(alCurrentChain.get(i).toString().startsWith("<")==true)
        {
        t=alCurrentChain.get(i).toString();
        noNt=1;
        break;
      }
      if(noNt==1)
      {
        for(int i=0;i<a;i++){t="";
        for(int j=1;j<AR[i].size();j++)
          t+=AR[i].get(j);
        wFrame.alCurrentRules.add(" "+(i+1)+":  "+AR[i].get(0)+"  -->  "+t);}}else ii=10000;
    }else{
      wFrame.alCurrentChain.add("Cлишком длинный вывод!");ii=10000;
    }
  }

  public boolean CanUndo() { if(u>0) return(true); else return(false); }
  public boolean CanRedo() { if(r>0) return(true); else return(false); }
  public boolean CanNext() { if(ii<10000) return(true); else return(false); }
  public void Undo()
  {
    --u; ++r; --ii;
    CurrentChainUpdate();
  }

  public void Redo()
  {
    ++u; --r; ++ii;
    CurrentChainUpdate();
  }

  public void Next(int i)
  {
    ++u; r=0; ++ii;
    BuildAlRulesList(i);
    CurrentChainUpdate();
  }


  public void GenerateFunctions(int k)
  {
    Random RandGen=new Random(0);
    int i,rnd;
    String str;
    ArrayList OptimizedFunctions=new ArrayList();
    ArrayList GenericFunctions=new ArrayList();
    ArrayList PopStackFunctions=new ArrayList();
    ArrayList PopTerminalFunctions=new ArrayList();

    int TotalNumOfFunctions=GR.LL.OptimizedFunctions.size()+
                            GR.LL.GenericFunctions.size()+
                            GR.LL.PopStackFunctions.size()+
                            GR.LL.PopTerminalFunctions.size();

    int NumOfGeneratedFunctions=(int)(k*TotalNumOfFunctions*.01);

    for(i=0;i<GR.LL.OptimizedFunctions.size();i++)
      OptimizedFunctions.add((String)GR.LL.OptimizedFunctions.get(i));
    for(i=0;i<GR.LL.GenericFunctions.size();i++)
      GenericFunctions.add((String)GR.LL.GenericFunctions.get(i));
    for(i=0;i<GR.LL.PopStackFunctions.size();i++)
      PopStackFunctions.add((String)GR.LL.PopStackFunctions.get(i));
    for(i=0;i<GR.LL.PopTerminalFunctions.size();i++)
      PopTerminalFunctions.add((String)GR.LL.PopTerminalFunctions.get(i));

    i=TotalNumOfFunctions-NumOfGeneratedFunctions;
    while(i>0){
      rnd=RandGen.nextInt(100);
      if(rnd<50)
      {
        if(rnd<25)
        {
          if(OptimizedFunctions.size()>0)
          {
            OptimizedFunctions.remove(RandGen.nextInt(OptimizedFunctions.size()));
            i--;
          }
        }
        else
        {
          if(GenericFunctions.size()>0)
          {
            GenericFunctions.remove(RandGen.nextInt(GenericFunctions.size()));
            i--;
          }
        }
      }
      else
      {
        if(rnd<75)
        {
          if(PopStackFunctions.size()>0)
          {
            PopStackFunctions.remove(RandGen.nextInt(PopStackFunctions.size()));
            i--;
          }
        }
        else
        {
          if(PopTerminalFunctions.size()>0)
          {
            PopTerminalFunctions.remove(RandGen.nextInt(PopTerminalFunctions.size()));
            i--;
          }
        }
      }
    };
    wFrame.alGeneratedFinctions.clear();
    wFrame.alGeneratedFinctions.add(" -- Оптимизированные функции для правил, правая часть которых начинается с терминала");
    wFrame.alGeneratedFinctions.add(" -- сдвиг, вытолкнуть, заменить");
    for(i=0;i<OptimizedFunctions.size();i++)
      wFrame.alGeneratedFinctions.add((String)OptimizedFunctions.get(i));
    wFrame.alGeneratedFinctions.add("");

    wFrame.alGeneratedFinctions.add(" -- Функции общего вида");
    wFrame.alGeneratedFinctions.add(" -- нет сдвига, заменить");
    for(i=0;i<GenericFunctions.size();i++)
      wFrame.alGeneratedFinctions.add((String)GenericFunctions.get(i));
    wFrame.alGeneratedFinctions.add("");

    wFrame.alGeneratedFinctions.add(" -- Функции для аннулирующих правил");
    wFrame.alGeneratedFinctions.add(" -- нет сдвига, вытолкнуть");
    for(i=0;i<PopStackFunctions.size();i++)
      wFrame.alGeneratedFinctions.add((String)PopStackFunctions.get(i));
    wFrame.alGeneratedFinctions.add("");

    wFrame.alGeneratedFinctions.add(" -- Функции выталкивания терминалов");
    wFrame.alGeneratedFinctions.add(" -- сдвиг, вытолкнуть");
    for(i=0;i<PopTerminalFunctions.size();i++)
      wFrame.alGeneratedFinctions.add((String)PopTerminalFunctions.get(i));
    wFrame.alGeneratedFinctions.add("");

    wFrame.alGeneratedFinctions.add(" -- Функция перехода в заключительное состояние");

    wFrame.alGeneratedFinctions.add(" (S,\"-|\",\"[]\")=(S,$,$)");
    NumOfGeneratedFunctions++;

    wFrame.alGeneratedFinctions.add("");
    wFrame.alGeneratedFinctions.add(" -- Фактор определённости: "+k+"%");
    wFrame.alGeneratedFinctions.add(" -- Всего функций для данной грамматики: "+(TotalNumOfFunctions+1));
    wFrame.alGeneratedFinctions.add(" -- Выдано функций: "+NumOfGeneratedFunctions);
  }

  public void BuildAlRulesList(int sel)
  {
    sel++;
    a=0;
    String t;
    if(sel==0)// Это первый вызов,поэтому строим список альтернатив для аксимомы грамматики
    {
      minTerminalCountReached = false;   // Не достигли минимального количества терминальных символов в цепочке
      terminalsAmount = 0;              // В начале в цепочке нет ни одного терминального символа
      for(int i=0;i<GR.RT.m_size;i++)
        if(GR.RT.m_rules[0].get(0).equals(GR.RT.m_rules[i].get(0))==true){
      AR[a]=new ArrayList();
      for(int j=0;j<GR.RT.m_rules[i].size();j++)
        AR[a].add(GR.RT.m_rules[i].get(j));
      a++;
        }
    }
    else      // Цепочка уже существует
    {
      terminalsAmount = 0;
      sel--;t="";
      int i,rem;a=0;int hasnot=0;       // Полагаю что нетерминалы в выводимой цепочке есть

      if(wFrame.RightStyle==false){     // ЕСЛИ ЛЕВЫЙ ВЫВОД, ТО ИЩЕМ САМЫЙ ЛЕВЫЙ НЕТЕРМИНАЛ В ВЫВОДИМОЙ ЦЕПОЧКЕ
        for(i=0;i<alCurrentChain.size();i++)
          if(alCurrentChain.get(i).toString().startsWith("<")==true)
              {t=alCurrentChain.get(i).toString();rem=i;
        alCurrentChain.remove(i); // Удалем заменяемый нетерминал
        for(i=1;i<AR[sel].size();i++)
          alCurrentChain.add(i+rem-1,AR[sel].get(i));
        hasnot=1;
      break;}
      else terminalsAmount++;
      }
      else {                          // ЕСЛИ ПРАВЫЙ ВЫВОД, ТО ИЩЕМ САМЫЙ ПРАВЫЙ НЕТЕРМИНАЛ
        for(i=alCurrentChain.size()-1;i>=0;i--){
          if(alCurrentChain.get(i).toString().startsWith("<")==true)
              {t=alCurrentChain.get(i).toString();rem=i;
          alCurrentChain.remove(i);                          // Удалем заменяемый нетерминал
          for(i=1;i<AR[sel].size();i++)
            alCurrentChain.add(i+rem-1,AR[sel].get(i));   // Добавим выбранную цепочку на выходную ленту
          hasnot=1;
      break;}
      else terminalsAmount++;
      }}
      //System.out.println(""+terminalsAmount);
      alCurrentChain.remove("$");

      if(hasnot!=0){
        if(wFrame.RightStyle==false){     // ЕСЛИ ЛЕВЫЙ ВЫВОД, ТО ИЩЕМ САМЫЙ ЛЕВЫЙ НЕТЕРМИНАЛ
          for(i=0;i<alCurrentChain.size();i++)
            if(alCurrentChain.get(i).toString().startsWith("<")==true)
                {t=alCurrentChain.get(i).toString();
          hasnot=1;
        break;}}
        else {                            // ЕСЛИ ПРАВЫЙ ВЫВОД, ТО ИЩЕМ САМЫЙ ПРАВЫЙ НЕТЕРМИНАЛ
          for(i=alCurrentChain.size()-1;i>=0;i--){
            if(alCurrentChain.get(i).toString().startsWith("<")==true)
                {t=alCurrentChain.get(i).toString();
            hasnot=1;
        break;}}}

        AR=new ArrayList[2000];
        for( i=0;i<GR.RT.m_size;i++){    // НАКОНЕЦ СТРОИМ НОВЫЙ СПИСОК АЛЬТЕРНАТИВ
          if(t.equals(GR.RT.m_rules[i].get(0))==true){
            AR[a]=new ArrayList();
            for(int j=0;j<GR.RT.m_rules[i].size();j++)
              AR[a].add(GR.RT.m_rules[i].get(j));
            a++;}
        }
      }
    }

    if(terminalsAmount >= minChainLength && minChainLength > 0) {
      //System.out.println("Reducing mode is on" + minChainLength);
      minTerminalCountReached = true;
    }
    Random r=new Random();
    if(a!=0) {
      if(!minTerminalCountReached) {
        wFrame.SelectedRuleNumber=(r.nextInt()&0xFFFF)%a; // Возвращаем случаное число от 0 до числа альтернатив-1
      } else {
        int ruleNumber = getAvoidingRuleNumber();
        if(ruleNumber != -1 ) {
          wFrame.SelectedRuleNumber = ruleNumber; // Возвращаем случаное число от 0 до числа альтернатив-1
        } else {
          wFrame.SelectedRuleNumber=(r.nextInt()&0xFFFF)%a;
        }
      }
    }

  }

  public int getAvoidingRuleNumber() {
    int i;
    for(i = 0; i < a; i++) {
        if(AR[i].get(1).toString().equals("$")) {
          //System.out.print(AR[i].get(1).toString());
          return i;
        }
    }
    return -1;
  }


  public boolean GenerateChain(int n)
  {
    minChainLength = n;
    //if(n>=500)return false;
    Random r=new Random();
    //int cycles=10-GR.RT.m_size;
    //if(cycles<=0)cycles=10;
    //int c=cycles/GR.TT.m_Ttable.size();
    int  c=10;int watchdog=0;
    for(int i=0; i < c;i++)
    {
      BeginChainGeneration();
      do{
  //      if(a!=0)
 //        wFrame.mWasp.Next((r.nextInt()&0xFFFF)%a);
     if(a!=0) {
     if(!minTerminalCountReached) {
       wFrame.mWasp.Next((r.nextInt()&0xFFFF)%a); // Возвращаем случаное число от 0 до числа альтернатив-1
     } else {
       int ruleNumber = getAvoidingRuleNumber();
       if(ruleNumber != -1 ) {
          wFrame.mWasp.Next(ruleNumber); // Возвращаем случаное число от 0 до числа альтернатив-1
       } else {
         wFrame.mWasp.Next((r.nextInt()&0xFFFF)%a);
       }
     }
    }
        watchdog++;
        if(watchdog>1500)return false;
      }while(noNt==1);
      if(terminalsAmount >=n){Conv();return true;}

    }
    return false;
  }

  public void Conv(){
    wFrame.alCurrentChain.add("");
    String st="";                              // Добавляем новый список альтернатив
    for(int i=0;i<alCurrentChain.size();i++)
      st+=alCurrentChain.get(i).toString();
    wFrame.alCurrentChain.set(0,st);
  }


  public void Translate(ArrayList Chain,ArrayList Functions)
  {
    int i=0;
    StringBuffer b=new StringBuffer();
    do{b.append(Chain.get(i).toString());i++;}while(i<Chain.size());
    int result;
    RC=new Recognizer();
    result=RC.ExpressAnanlyze(Functions,b.toString(),true,GR.NT.m_Ntable.get(0).toString());
    wFrame.alTStack.clear();String t="";
    for(i=0;i<RC.err;i++){
      t="";
      if(RC.FE[i].pos==-1)t="Функции перехода не заданы.";
      if(RC.FE[i].pos==0)t="Пропущено имя состояния";
      if(RC.FE[i].pos==1)t="Пропущена ','";
      if(RC.FE[i].pos==2)t="Пропущен символ грамматики";
      if(RC.FE[i].pos==3)t="Пропущен магазинный символ";
      if(RC.FE[i].pos==4)t="Пропущена ')'";
      if(RC.FE[i].pos==5)t="Пропущен '='";
      if(RC.FE[i].pos==6)t="Пропущен '('";
      if(RC.FE[i].pos==7)t="Пропущен символ выходной ленты";
      if(RC.FE[i].pos==8)t="Пропущен символ '\"'";
      if(RC.FE[i].pos==9)t="Пропущен символ '>'";
      if(RC.FE[i].pos==10)t="Пропущен символ '#'";
      if(RC.FE[i].pos==11)t="Недопустимый символ";
      if(RC.FE[i].pos==12)t="Слишком много функций перехода";
      if(RC.FE[i].pos==13)t="Слишком длинная цепочка для автомата";
      if(RC.FE[i].pos==14)t="Reserved for additional errors messages";
    wFrame.alTStack.add("Ошибка в строке: "+(RC.FE[i].str+1)+"   "+t);}
    wFrame.TStepQ=RC.FL[0].steps;
    wFrame.TranslateReturn=result;
  }

  public void getTStep(int sn)
  {
    wFrame.alTStack.clear();
    wFrame.alInputChain.clear();
    wFrame.alOutputChain.clear();
    wFrame.alTStack.clear();
    sn=sn+1;
    for(int i=0;i<RC.FL[sn].STACK.size();i++)
      wFrame.alTStack.add(RC.FL[sn].STACK.get(i));
    wFrame.alInputChain.add(RC.FL[sn].Chain);
    wFrame.alOutputChain.add(RC.FL[sn].Outchain);
    wFrame.TFunction=RC.FL[sn].Function;
    wFrame.TState="S";
  }

  public void getTLog()
  {
    wFrame.alTLog.clear();
    for(int i=1;i<RC.FL[0].steps+1;i++){
      wFrame.alTLog.add("\n");
      wFrame.alTLog.add("Шаг:     "+(i-1));
      wFrame.alTLog.add("Магазин:  "+RC.FL[i].STACK.toString());
      wFrame.alTLog.add("Входная цепочка:  "+RC.FL[i].Chain);
      wFrame.alTLog.add("Выходная цепочка:  "+RC.FL[i].Outchain);
      wFrame.alTLog.add("Функция перехода:  "+RC.FL[i].Function);
    }
  }

  public Grammar getGrammar()
    {
    this.Analyse();
    return this.GR;
    }

}