require_relative '../cpu'
require_relative 'instruction'

module GBRb::InstructionSet
  class Res < Instruction
    def initialize bit, target, indirect=false, m=2, t=16
      super m, t
      @bit = bit
      @mask = 0xff - 0b10 ** bit
      @target = target.to_sym
      @indirect = indirect
    end

    def call r, mem
      if @indirect
        addr = r.public_send(@target).read
        mem.write_byte(addr, mem.read_byte(addr) & @mask)
      else
        r.public_send(@target).store r.public_send(@target).read & @mask
      end
    end
  end

  class Set < Instruction
    def initialize bit, target, indirect=false, m=2, t=16
      super m, t
      @bit = bit
      @mask = 0b10 ** bit
      @target = target.to_sym
      @indirect = indirect
    end

    def call r, mem
      if @indirect
        addr = r.public_send(@target).read
        mem.write_byte(addr, mem.read_byte(addr) | @mask)
      else
        r.public_send(@target).store r.public_send(@target).read | @mask
      end
    end
  end

  class Bit < Instruction
    def initialize bit, target, indirect=false, m=2, t=8
      super m,t
      @target = target
      @bit = bit
      @indirect = indirect
      @mask = 1 << @bit
    end

    def call r, mem
      if @indirect
        v = mem.read_byte r.public_send(@target).read
      else
        v = r.public_send(@target).read
      end

      v & @mask != @mask ? r.set_zero_flag : r.clear_zero_flag
      r.set_half_carry_flag
      r.clear_add_sub_flag
    end
  end
end
