require_relative "../spec_helper.rb"

module WinGuiTest

  describe Window do
    before(:each) { @win = launch_test_app.main_window }
    after(:each){ close_test_app }

    context 'initializing' do
      it 'can be wrapped around any existing window' do
        any_handle = find_window(nil, nil)
        use{ Window.new any_handle }
      end
    end

    context 'manipulating' do
      it 'closes when asked nicely' do
        @win.close
        sleep SLEEP_DELAY # needed to ensure window had enough time to close down
        find_window(nil, WIN_TITLE).should == nil
      end

      it 'waits for window to disappear (NB: this happens before handle is released!)' do
        start = Time.now
        @win.close
        @win.wait_for_close
        (Time.now - start).should be <= CLOSE_TIMEOUT
        window_visible?(@win.handle).should be false
        window?(@win.handle).should be false
      end
    end

    context 'handle-related WinGui functions as instance methods' do
      it 'calls all WinGui functions as instance methods (with handle as implicit first argument)' do
        @win.window?.should == true
        @win.visible?.should == true
        @win.foreground?.should == true
        @win.maximized?.should == false
        @win.minimized?.should == false
        @win.child?(any_handle).should == false

        @win.window_rect.should be_an Array
        @win.window_thread_process_id.should be_an Array
        @win.enum_child_windows.should be_an Array
      end
   end

    context 'derived properties' do
      it 'has handle property equal to underlying window handle' do
        any = Window.new any_handle
        any.handle.should == any_handle
      end

      it 'has class_name and text/title properties (derived from WinGui function calls)' do
        @win.class_name.should == WIN_CLASS
        # text propery accessed by sending WM_GETTEXT directly to window (convenience method in WinGui)
        @win.text.should == WIN_TITLE
        # window_text propery accessed via GetWindowText
        @win.window_text.should == WIN_TITLE
        # title property is just an alias for window_text
        @win.title.should == WIN_TITLE
      end

      it 'has thread and process properties derived from get_window_thread_process_id' do
        thread = @win.thread
        process = @win.process
        [thread, process].should == get_window_thread_process_id(@win.handle)
      end

      it 'has id property that only makes sense for controls' do
        use{ @win.id }
      end
    end

    describe '::top_level' do
      it 'finds top-level window by title and wraps it in a Window object' do
        window = Window.top_level( title: WIN_TITLE, timeout: 1)
        window.handle.should == @win.handle
      end

      it 'finds top-level window by class and wraps it in a Window object' do
        window = Window.top_level( class: WIN_CLASS, timeout: 1)
        window.handle.should == @win.handle
      end

      it 'finds ANY top-level window without args and wraps it in a Window object' do
        use { @window = Window.top_level() }
        @window.should be_a Window
      end

      it 'returns nil immediately if top-level window with given title not found' do
        start = Time.now
        Window.top_level( title: IMPOSSIBLE).should == nil
        (Time.now - start).should be_close 0, 0.03
      end

      it 'returns nil after timeout if top-level window with given title not found' do
        start = Time.now
        Window.top_level( title: IMPOSSIBLE, timeout: 0.3).should == nil
        (Time.now - start).should be_close 0.3, 0.03
      end

      it 'raises exception if asked to' do
        expect{ Window.top_level( title: IMPOSSIBLE, raise: "Horror!")}.to raise_error "Horror!"
      end

      it 'uses .find as alias for .top_level' do
        use { @window = Window.find() }
        @window.should be_a Window
      end
    end # describe .top_level

    describe '#child' do
      spec { use { @child = @win.child(title: "Title", class: "Class", id: 0)  }}

      it 'returns nil immediately if specific child not found' do
        start = Time.now
        @win.child( title: IMPOSSIBLE).should == nil
        (Time.now - start).should be_close 0, 0.03
      end

      it 'returns nil after timeout if specific child not found' do
        start = Time.now
        @win.child( title: IMPOSSIBLE, timeout: 0.5).should == nil
        (Time.now - start).should be_close 0.5, 0.03
      end

      it 'finds ANY child window without args' do
        use { @child = @win.child() }
        @child.should_not == nil
        @win.child?(@child.handle).should == true
      end

      it 'finds child window by class and returns it as a Window object (no timeout)' do
        child = @win.child( class: TEXTAREA_CLASS)
        child.should_not == nil
        @win.child?(child.handle).should == true
      end

      it 'finds child window by class and returns it as a Window object (with timeout)' do
        child = @win.child( class: TEXTAREA_CLASS, timeout: 0.5)
        child.should_not == nil

        @win.child?(child.handle).should == true
        child = @win.child( class: STATUSBAR_CLASS, timeout: 0.5)
        child.should_not == nil
        @win.child?(child.handle).should == true
      end

      it 'finds child with specific text and returns it as a Window object' do
        with_dialog(:save) do |dialog|
          child = dialog.child( title: "Cancel")
          child.should_not == nil
          dialog.child?(child.handle).should == true
          child.get_dlg_ctrl_id.should == IDCANCEL

          child = dialog.child( title: "&Save")
          child.should_not == nil
          dialog.child?(child.handle).should == true
          child.get_dlg_ctrl_id.should == IDOK
        end
      end

      it 'finds child control with a given ID and returns it as a Window object' do
        with_dialog(:save) do |dialog|
          child = dialog.child( id: IDCANCEL)
          child.should_not == nil
          dialog.child?(child.handle).should == true
          child.text.should == "Cancel"
        end
      end

      context 'indirect child' do
        it 'returns nil if specified child not found' do
          @win.child( title: IMPOSSIBLE, indirect: true).should == nil
        end

        it 'finds ANY child window without other args' do
          use { @child = @win.child(indirect: true) }
          @child.should_not == nil
          @win.child?(@child.handle).should == true
        end

        it 'finds child window by class' do
          child = @win.child( class: TEXTAREA_CLASS, indirect: true)
          child.should_not == nil
          @win.child?(child.handle).should == true
        end

        it 'finds child with specific text' do
          with_dialog(:save) do |dialog|
            child = dialog.child( title: "Cancel", indirect: true)
            child.should_not == nil
            dialog.child?(child.handle).should == true
            child.id.should == IDCANCEL

            child = dialog.child( title: "&Save", indirect: true)
            child.should_not == nil
            dialog.child?(child.handle).should == true
            child.id.should == IDOK
          end
        end

        it 'finds child control with a given ID ' do
          with_dialog(:save) do |dialog|
            child = dialog.child( id: IDCANCEL, indirect: true)
            child.should_not == nil
            dialog.child?(child.handle).should == true
            child.text.should == "Cancel"
          end
        end
      end # context indirect
    end # describe child

    describe '#children' do
      spec { use { children = @win.children  }}

      it 'returns an array of Windows that are descendants (not only DIRECT children) of a given Window' do
        children = @win.children
        children.should be_a_kind_of Array
        children.should_not be_empty
        children.should have(2).elements
        children.each{|child| child?(@win.handle, child.handle).should == true }
        children.last.class_name.should == TEXTAREA_CLASS
      end
    end # describe #children

    describe '#click' do
      it 'emulates left click of the control identified by id, returns click coords' do
        with_dialog(:save) do |dialog|
          point = dialog.click(id: IDCANCEL)
          point.should be_an Array
          sleep 0.3
          dialog.window?.should == false
        end
      end

      it 'emulates left click of the control identified by title, returns click coords' do
        with_dialog(:save) do |dialog|
          point = dialog.click(title: "Cancel")
          point.should be_an Array
          sleep 0.3
          dialog.window?.should == false
        end
      end

      it 'emulates right click of the control identified by id, returns click coords' do
        with_dialog(:save) do |dialog|
          point = dialog.click(id: IDCANCEL, mouse_button: :right)
          point.should be_an Array
          sleep 0.3
          dialog.window?.should == true
        end
      end

      it 'emulates right click of the control identified by title, returns click coords' do
        with_dialog(:save) do |dialog|
          point = dialog.click(title: "Cancel", mouse_button: :right)
          point.should be_an Array
          sleep 0.3
          dialog.window?.should == true
        end
      end

      it 'returns nil if the specified control was not found' do
        with_dialog(:save) do |dialog|
          dialog.click(title: "Shpancel").should == nil
          dialog.click(id: 66).should == nil
          sleep 0.3
          dialog.window?.should == true
        end
      end
    end # describe #click
  end
end