require 'canvas'

W = 640
H = 480

COLORS = [[255,128,128],
          [192,255,128],
          [128,128,255],
          [255,192,128],
          [128,255,128],
          [128,255,192],
          [128,255,255],
          [128,192,255],
          [255,255,128],
          [192,128,255],
          [255,128,255],
          [255,128,192],
         ]

class State
  attr_accessor :x, :y, :clicked

  def initialize
    @x = @y = 0
    @clicked = false
  end

  def set_xy(x, y)
    @x = x
    @y = y
  end
end

class ParticleApp < App
  def initialize
    @ws = {}
    @objs = []
  end

  def onTimer
    ctx = CanvasContext.new
    ctx.fillStyle = 'rgb(0,0,0)'
    ctx.fillRect(0, 0, W, H)

    ctx.fillStyle = 'rgba(255,255,255,0.8)'
    @ws.each do |ws, st|
      ctx.fillRect(st.x - 10, st.y - 10, 20, 20)

      if st.clicked
        10.times{
          v = rand(3.0) + 1.0
          r = rand(Math::PI * 2)
          @objs << [st.x, st.y, v * Math.cos(r), v * Math.sin(r),
                    COLORS[rand(COLORS.size)]]
        }
      end

      st.clicked = false
    end

    nobjs = []
    @objs.each do |obj|
      obj[0] += obj[2]
      obj[1] += obj[3]
      if obj[0] < 0 || obj[0] > W || obj[1] < 0 || obj[1] > H
      else
        nobjs << obj

        ctx.fillStyle = 'rgba(%d,%d,%d,0.5)' % obj[4]
        ctx.fillRect(obj[0] - 5, obj[1] - 5, 10, 10)
      end
    end
    @objs = nobjs

    @ws.each do |ws, st|
      begin
        ws.send(ctx.code)
      rescue
        puts $!
        puts $!.backtrace
        @ws.delete(ws)
      end
    end
  end

  def onOpen(ws)
    @ws[ws] = State.new
  end

  def onClose(ws)
    @ws.delete(ws)
  end

  def onMouseMove(ws, x, y)
    @ws[ws].set_xy(x, y)
  end

  def onMouseDown(ws, x, y)
    @ws[ws].set_xy(x, y)
  end

  def onMouseUp(ws, x, y)
    @ws[ws].set_xy(x, y)
    @ws[ws].clicked = true
  end
end

def newApp
  ParticleApp.new
end
