package com.enactor.pos.swing;

import com.enactor.core.automation.AUT.AutomationException;
import com.enactor.core.automation.AUT.IAUTControllerClient;
import com.enactor.core.automation.actions.AssertComponentTextAction;
import com.enactor.core.automation.actions.ClickComboBoxComponentAction;
import com.enactor.core.automation.actions.ClickComponentAction;
import com.enactor.core.automation.actions.ClickListComponentAction;
import com.enactor.core.automation.actions.InputTextAction;
import com.enactor.core.automation.actions.WaitForWindowAction;
import com.enactor.core.automation.component.IComponentAccessor;
import com.enactor.core.automation.component.IWindowAccessor;
import org.testng.Assert;

import java.util.List;

public class SwingAppStepsProvider implements ISwingAppStepsProvider {

    private IAUTControllerClient controller;
    private final long waitWindowTimeout;

    public SwingAppStepsProvider(IAUTControllerClient controller, long waitWindowTimeout) {
        this.controller = controller;
        this.waitWindowTimeout = waitWindowTimeout;
    }

   public void setController(IAUTControllerClient controller) {
        this.controller = controller;
   }

    @Override
    public void waitForWindow(String windowId, long timeout) throws AutomationException {
        checkWindowShown(windowId, timeout);
    }

    @Override
    public IComponentAccessor waitsForComponent(String componentId, String windowId, long timeout) throws AutomationException {
        IWindowAccessor window = getSwingWindowById(windowId);
        return window.waitForComponent(componentId, timeout);
    }

    @Override
    public String getComponentText(String componentId, String windowId) throws AutomationException {
        return getSwingWindowById(windowId).findComponent(componentId).getText();
    }

    @Override
    public void pressButtonWithLabel
            (String buttonLabel, String windowId,
             List<String> possibleComponentIds, long timeout) throws AutomationException {
        IWindowAccessor window = getSwingWindowById(windowId);
        String buttonId = getButtonConfig(window, buttonLabel, possibleComponentIds, timeout);
        window.waitForComponent(buttonId, timeout).click();
    }

    @Override
    public void pressButtonByComponentId(String componentId, String windowId) throws AutomationException {
        IWindowAccessor window = getSwingWindowById(windowId);
        ClickComponentAction.clickComponent(window, componentId);
    }

    @Override
    public void pressButtonByComponentId(String componentId, String windowId, long timeout) throws AutomationException {
        IWindowAccessor window = getSwingWindowById(windowId);
        ClickComponentAction.clickComponent(window, componentId, timeout);
    }

    
    @Override
    public void assertButtonWithLabelNotDisplayed
            (String buttonLabel, String windowId,
             List<String> possibleComponentIds, long timeout) throws AutomationException {
        IWindowAccessor window = getSwingWindowById(windowId);
        try {
            getButtonConfig(window, buttonLabel, possibleComponentIds, timeout);
        } catch (AutomationException e) {
            // button with given label not found
            return;
        }
        throw new AutomationException(
                "Button with label [" + buttonLabel + "] display on [" + windowId + "] page");
    }

    
    @Override
    public void enterText(String text, String componentId, String windowId) throws AutomationException {
        IWindowAccessor window = getSwingWindowById(windowId);
        InputTextAction.inputText(window, componentId, text);
    }

    
    @Override
    public void assertTextFieldHasEqualContent(String text, String componentId, String windowId) throws AutomationException {
        IWindowAccessor window = getSwingWindowById(windowId);
        AssertComponentTextAction.assertComponentText(window, componentId, text);
    }

    
    @Override
    public void assertTextFieldContainsValue(String text, String componentId, String windowId) throws AutomationException {
        IWindowAccessor window = getSwingWindowById(windowId);
        AssertComponentTextAction.assertComponentContainsText(window, componentId, text);
    }

    
    @Override
    public void assertTextFieldIsNotEmpty(String componentId, String windowId) throws AutomationException {
        IWindowAccessor window = getSwingWindowById(windowId);
        Assert.assertTrue((window.findComponent(componentId).getText()).length() > 0,
                "Field [" + componentId + "] is empty");
    }

    
    @Override
    public void assertLabelHasEqualContent(String text, String componentId, String windowId) throws AutomationException {
        IWindowAccessor window = getSwingWindowById(windowId);
        window.findComponent(componentId).assertPropertyEquals(text, "Text match - ");
    }

    
    @Override
    public void selectListItem(String item, String listComponentId, String windowId) throws AutomationException {
        IWindowAccessor window = getSwingWindowById(windowId);
        ClickListComponentAction.clickComponentWithRowText(window, listComponentId, item);
    }

    
    @Override
    public void selectComboboxItem(String item, String componentId, String windowId) throws AutomationException {
        IWindowAccessor window = getSwingWindowById(windowId);
        int index = window.findComponent(componentId).getItemIndex(item);
        ClickComboBoxComponentAction.clickComponent(window, componentId, index);
    }

    
    @Override
    public void assertPanelHasEqualContent(String text, String panelComponentId, String windowId) throws AutomationException {
        IWindowAccessor window = getSwingWindowById(windowId);
        Assert.assertTrue(window.findComponent(panelComponentId)
                .assertPropertyEquals(text, "Text [" + text + "] not found in panel [" + panelComponentId + "]"));
    }

    /**
     * Returns WindowAccessor of a given window id
     *
     * @param windowId
     * @return
     * @throws AutomationException
     */
    private IWindowAccessor getSwingWindowById(String windowId) throws AutomationException {
        return WaitForWindowAction.waitForWindow(controller, windowId, waitWindowTimeout);
    }

    /**
     * Returns Button config from <b>autClientPropertyFileName</b>
     * property file
     *
     * @param window
     * @param label
     * @return
     * @throws AutomationException
     */
    private String getButtonConfig(IWindowAccessor window, String label, List<String> buttonComponentIdList, long timeout) throws AutomationException {
        // Check button with label display on the page.
        // Loop through the list twice to find the button because buttons
        // not display as soon as page loads.
        for (int i = 1; i <= 2; i++) {
            for (String button : buttonComponentIdList) {
                try {
                    String actual = window.waitForComponent(button, timeout).getText();
                    if (label.equals(actual)) {
                        return button;
                    }
                } catch (AutomationException e) {
                    // button text not available. Continue loop
                }
            }
        }
        throw new AutomationException("Button with label [" + label + "] not displayed");
    }

    /**
     * Check whether the window with given id was shown.
     *
     * @param windowId
     * @throws AutomationException
     */
    private void checkWindowShown(String windowId, long wait) throws AutomationException {
        IWindowAccessor window = WaitForWindowAction.waitForWindow(controller, windowId, wait);
        assertNotNull(window, windowId);
    }

    private void assertNotNull(IWindowAccessor window, String windowId)
            throws AutomationException {
        if (window == null) {
            throw new AutomationException("Failed to find window with id " + windowId);
        }
    }
}
