require "./sdl/sdl"

class ColorMaker
  enum State
    BlueUp
    BlueDown
    GreenUp
    GreenDown
    RedUp
    RedDown
  end

  @state : State

  def initialize(@delay : Int32)
    @r = 0
    @g = 255
    @b = 0
    @time = 0
    @state = :blue_up
  end

  def next
    @time += 1
    if @time == @delay
      next_state
      @time = 0
    end
  end

  def next_state
    case @state
    when .green_up?
      @g += 1
      @state = :red_down if @g == 255
    when .red_down?
      @r -= 1
      @state = :blue_up if @r == 0
    when .blue_up?
      @b += 1
      @state = :green_down if @b == 255
    when .green_down?
      @g -= 1
      @state = :red_up if @g == 0
    when .red_up?
      @r += 1
      @state = :blue_down if @r == 255
    when .blue_down?
      @b -= 1
      @state = :green_up if @b == 0
    end
  end

  def black_color
    make_alpha_color(0.25)
  end

  def dark_color
    make_alpha_color(0.5)
  end

  def light_color
    make_alpha_color(1.0)
  end

  def make_alpha_color(multiplier)
    rand = Random.next_int
    r = ((rand >> 16) % 256).to_i
    g = ((rand >> 8) % 256).to_i
    b = (rand % 256).to_i
    r = saturate_color(r, @r, multiplier)
    g = saturate_color(g, @g, multiplier)
    b = saturate_color(b, @b, multiplier)
    make_color r, g, b, 0
  end

  def saturate_color(random, component, multiplier)
    Math.min(random, (component * multiplier).to_i)
  end

  def make_color(r, g, b, a)
    (b << 24) + (g << 16) + (r << 8) + a
  end
end

class Rectangle
  def initialize(@x : Int32, @y : Int32, @light : Bool)
  end

  def light?
    @light
  end

  def contains?(x, y)
    @x == x && @y == y
  end
end

def parse_rectangles
  rects = [] of Rectangle
  lines = File.read("#{__DIR__}/tv.txt").split('\n').map(&.rstrip)
  lines.each_with_index do |line, y|
    x = 0
    line.each_char do |c|
      if c == 'x'
        rects << Rectangle.new(x, y, true)
      elsif c == '.'
        rects << Rectangle.new(x, y, false)
      end
      x += 1
    end
  end
  rects
end

width = 640
height = 480

delay = ARGV.size > 1 ? ARGV[1].to_i : 1

SDL.init
SDL.show_cursor

surface = SDL.set_video_mode width, height, 32, LibSDL::DOUBLEBUF | LibSDL::HWSURFACE | LibSDL::ASYNCBLIT | LibSDL::FULLSCREEN

frames = 0_u32
start = SDL.ticks

color_maker = ColorMaker.new(delay)
rects = parse_rectangles
puts "Rects: #{rects.size}"

begin
  while true
    SDL.poll_events do |event|
      if event.type.in?(LibSDL::QUIT, LibSDL::KEYDOWN)
        ms = SDL.ticks - start
        puts "#{frames} frames in #{ms} ms"
        puts "Average FPS: #{frames / (ms * 0.001)}"
        SDL.quit
        exit
      end
    end

    surface.lock

    (height // 10).times do |h|
      (width // 10).times do |w|
        rect = rects.find(&.contains?(w, h))
        10.times do |y|
          10.times do |x|
            surface[x + 10 * w, y + 10 * h] = rect ? (rect.light? ? color_maker.light_color : color_maker.dark_color) : color_maker.black_color
          end
        end
      end
    end

    color_maker.next

    surface.unlock
    surface.flip

    frames += 1
  end
ensure
  SDL.quit
end
