require "util/eventable"
require "risc/interpreter"
require_relative "compiling"
require_relative "output"

module Risc
  module Ticker
    include ScopeHelper
    include Output
    include Preloader

    def setup
      compiler = RubyX::RubyXCompiler.new(RubyX.interpreter_test_options)
      @linker = compiler.ruby_to_binary(preload + @string_input, :interpreter)
      @interpreter = Interpreter.new(@linker)
      @interpreter.start_program
    end
    alias :do_setup :setup

    def yielder
      "def yielder; return yield ; end"
    end
    def tenner
      "def tenner; return yield(10) ;end"
    end
    def block_main( main , extra = yielder)
      in_Space("#{extra} ; def main(arg) ; #{main} ; end")
    end

    # check the given array of instructions is what the interpreter actually does
    # possible second argument ignores the given amount, usually up until main
    def check_chain( should , start_at = 0 )
      ticks( start_at ) if start_at > 0
      should.each_with_index do |name , index|
        got = ticks(1)
        assert_equal got.class ,name , "Wrong class for #{index + 1}, expect #{name} , got #{got}"
      end
    end
    # check the main only, ignoring the __init instructions
    def check_main_chain( should )
      check_chain( should , main_at)
    end

    # how many instruction up until the main starts, ie
    # ticks(main_at) will be the label for main
    def main_at
      Risc.init_length
    end

    def get_return
      assert_equal Parfait::Message , @interpreter.get_register(:saved_message).class
      @interpreter.get_register(:syscall_1)
    end

    # do as many as given ticks in the main, ie main_at more
    def main_ticks(num)
      ticks( main_at + num)
    end

    # do a certain number of steps in the interpreter and return the last executed instruction
    def ticks( num )
      last = nil
      num.times do
        last = @interpreter.instruction
        @interpreter.tick
      end
      return last
    end
    def risc(num)
      return @instruction if @instruction
      @instruction = main_ticks(num)
    end

    # collect the classes of all executed istructions
    def all_classes(max = 300)
      classes = []
      tick = 1
      begin
        while(classes.length < max)
          cl = ticks(1).class
          tick += 1
          classes << cl
          break if cl == NilClass
        end
      rescue => e
        puts "Error at tick #{tick}"
        puts e
        puts e.backtrace
      end
      classes
    end

    # do the setup, compile and run the input (a main) to the end
    def run_main_return(input)
      run_main("return #{input}")
    end

    # get the return from the message (not exit code)
    # exit code must be int
    def get_message_return
      @interpreter.get_register(:message).return_value
    end

    # wrap the input so it is a main, compile and run it
    def run_main(input)
      run_input as_main(input)
    end

    # use the input as it, compile and run it
    # input muts contain a Space.main, but may contain more classes and methods
    def run_input(input)
      @string_input = input
      do_setup
      run_all
    end

    def run_all
      while(@interpreter.instruction)
        @interpreter.tick
        #puts @interpreter.instruction
      end
      @interpreter.clock
    end

    # for chaning the tests quickly output all instructions that are executed
    def show_ticks
      classes = all_classes
      output_classes(classes)
    end
    # show all instructions of the main only
    def show_main_ticks
      classes = all_classes
      classes = classes.slice(main_at , 1000)
      output_classes(classes)
    end

    def output_classes(classes)
      puts class_list(classes)
      exit(1)
    end
  end
end