require 'win/gui'

module WinGui
  # Delay between key commands (events)
  WG_KEY_DELAY = 0.00001
  # Wait delay quant
  WG_SLEEP_DELAY = 0.001
  # Timeout waiting for Window to be closed
  WG_CLOSE_TIMEOUT = 1

  class Window
    include Win::Gui
    extend Win::Gui
    
    def initialize(handle)
      @handle = handle
    end

    attr_reader :handle
    
    # find top level window by title, return wrapped Window object
    def self.top_level(title, seconds=3)
      @handle = timeout(seconds) do
        sleep WG_SLEEP_DELAY while (h = find_window nil, title) == nil; h
      end
      Window.new @handle
    end  
    
    # find child window (control) by title, window class, or control ID:
    def child(id)
      result = case id
        when String
        by_title = find_window_ex @handle, 0, nil, id.gsub('_' , '&' )
        by_class = find_window_ex @handle, 0, id, nil
        by_title ? by_title : by_class
        when Fixnum
        get_dlg_item @handle, id
        when nil
        find_window_ex @handle, 0, nil, nil
      else
        nil
      end
      raise "Control '#{id}' not found" unless result
      Window.new result
    end

    def children
      enum_child_windows(@handle).map{|child_handle| Window.new child_handle}
    end

    # emulate click of the control identified by id
    def click(id)
      h = child(id).handle
      rectangle = [0, 0, 0, 0].pack 'LLLL'
      get_window_rect h, rectangle
      left, top, right, bottom = rectangle.unpack 'LLLL'
      center = [(left + right) / 2, (top + bottom) / 2]
      set_cursor_pos *center
      mouse_event MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
      mouse_event MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
    end
    
    def close
      post_message @handle, WM_SYSCOMMAND, SC_CLOSE, nil
    end
    
    def wait_for_close
      timeout(WG_CLOSE_TIMEOUT) do
        sleep WG_SLEEP_DELAY while window_visible?(@handle) 
      end
    end
    
    def text
      buffer = "\x0" * 2048
      length = send_message @handle, WM_GETTEXT, buffer.length, buffer
      length == 0 ? '' : buffer[0..length - 1]
    end
  end
end