public class Instruction
{
   static int num=0;
   static final int CURRENT_STATE= 0;
   static final int CURRENT_SYMBOL= 1;
   static final int NEXT_STATE= 2;
   static final int HEAD_INSTRUCTION= 3;
   String [] transition;
   String precomment;
   String print_instr;
   int instruction_number;

// I added the tm_description to give a more informative
// error message when there is a bad instruction.
   public void exit_error(String tm_description, int code)
   {
       System.out.println("TM so far: \n" + tm_description);
       System.out.println("*** Error [" + code + 
       "]- Invalid termination of TM.");
       System.out.println("Make sure you started with a start state.");
       System.out.println("Check that you included $ at end of TM.");
       System.out.println("Ensure all transitions have 4 components.");
       System.exit(code);
   }
   public Instruction(Input in, String tm_description)
   {
       String comment;
       int typ;

       int i;

       transition= new String[4];
       
       transition[0]= in.readOneString();
       if (transition[0] == null)
       {
          exit_error(tm_description, 1);
       }
       typ= type_string(transition[0]);
       print_instr="";
       precomment= "";
       while (typ != 2)
       {
           if (typ == 1)
           {
              transition= null;
              return;
           }
           comment= in.flush_line();
	   precomment+= transition[0] + comment + "\n";
           transition[0]= in.readOneString();
           if (transition[0]== null)
           {
              exit_error(tm_description, 2);
           }
           typ= type_string(transition[0]);
       }
       for (i=1; i < 4; i++)
       {
           transition[i]= in.readOneString();
	   if (transition[i]== null)
	   {
               exit_error(tm_description, 3);
	   }
       }
       num++;
       instruction_number= num;
       print_instr+= table_print_instruction();
       comment=in.flush_line();
       print_instr+= comment + "\n";
       check_instruction(tm_description);
       return;
   }
   void check_instruction(String tm_description)
   {
       int i;
       
       for (i=0; i < 4; i++)
       {
           if (i== CURRENT_SYMBOL || i== HEAD_INSTRUCTION)
           {
               if (transition[i].length() != 1)
               {
                  System.out.println("TM so far: \n" + tm_description);
                  System.out.println("**** Error- Component " + i + 
                    " of transition " 
                    + "is [" + transition[i] + "] does not have length 1.");
                  System.out.println("BAD TRANSITION:");
                  System.out.println(table_print_instruction());
                  System.exit(4);
               }
           }
       }
   }
   public Instruction(String [] init)
   {
       int i;

       transition= new String[4];
       for (i=0; i < 4; i++)
           transition[i]= init[i]; 
   }
   public String print_instruction()
   {
      String s;
      int i;

      s="(";
      for (i=0; i < 4; i++)
      {
	  s+= transition[i];
          if (i < 3) s+=", ";
      }
      s+= ")  -> ";
      return(s);
   }
   public String table_print_instruction()
   {
      String s;
      int i;

      if (instruction_number > 0)
      {
         s="Rule ";
         if (instruction_number <=  99) s+=" ";
         if (instruction_number <= 9) s+=" ";
         s+= num + ": ";
      }
      else s="        : ";

      for (i=0; i < 4; i++)
      {
          if (i==0 || i== 2) s+= pad(transition[i], 7);
          else               s+= " " + pad(transition[i], 3);
      }
      return(s);
   }
   public static String pad(String x, int width)
   {
       int i;
       String t;
    
       t=x;
       while (t.length() < width) 
       {
          t= t+" ";
       }
       return(t);
   }
   public boolean valid_move(String state, String symbol)
   {
      if (! transition[CURRENT_STATE].equals(state)) return(false);
      if (! transition[CURRENT_SYMBOL].equals(symbol)) return(false);
      return(true);
   }
   public static int type_string(String s)
   {
       if (s== null) return(3);
       if (is_comment(s)) return(0);
       if (s.charAt(0) == '$') return(1);
       return(2);
   }
   public static boolean is_comment(String s)
   {
       if (s.length() < 2) return(false);
       if (s.charAt(0)!= '/') return(false);
       if (s.charAt(1)!= '/') return(false);
       return(true);
   }
}
