org.openremote.web.console.unit.ConsoleUnit.java Source code

Java tutorial

Introduction

Here is the source code for org.openremote.web.console.unit.ConsoleUnit.java

Source

/* OpenRemote, the Home of the Digital Home.
* Copyright 2008-2014, OpenRemote Inc.
*
* See the contributors.txt file in the distribution for a
* full listing of individual contributors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.openremote.web.console.unit;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openremote.web.console.controller.Controller;
import org.openremote.web.console.controller.ControllerCredentials;
import org.openremote.web.console.controller.ControllerCredentialsList;
import org.openremote.web.console.controller.EnumControllerResponseCode;
import org.openremote.web.console.event.ConsoleUnitEventManager;
import org.openremote.web.console.event.hold.HoldEvent;
import org.openremote.web.console.event.hold.HoldHandler;
import org.openremote.web.console.event.rotate.RotationEvent;
import org.openremote.web.console.event.rotate.RotationHandler;
import org.openremote.web.console.event.sensor.SensorChangeEvent;
import org.openremote.web.console.event.swipe.SwipeEvent;
import org.openremote.web.console.event.swipe.SwipeEvent.SwipeDirection;
import org.openremote.web.console.event.swipe.SwipeHandler;
import org.openremote.web.console.event.ui.CommandSendEvent;
import org.openremote.web.console.event.ui.CommandSendHandler;
import org.openremote.web.console.event.ui.NavigateEvent;
import org.openremote.web.console.event.ui.NavigateHandler;
import org.openremote.web.console.event.ui.ScreenViewChangeEvent;
import org.openremote.web.console.event.ui.WindowResizeEvent;
import org.openremote.web.console.event.ui.WindowResizeHandler;
import org.openremote.web.console.panel.Panel;
import org.openremote.web.console.panel.PanelIdentityList;
import org.openremote.web.console.panel.entity.DataValuePair;
import org.openremote.web.console.panel.entity.DataValuePairContainer;
import org.openremote.web.console.panel.entity.Gesture;
import org.openremote.web.console.panel.entity.Navigate;
import org.openremote.web.console.panel.entity.Screen;
import org.openremote.web.console.panel.entity.TabBar;
import org.openremote.web.console.service.AsyncControllerCallback;
import org.openremote.web.console.service.AutoBeanService;
import org.openremote.web.console.service.AutoDiscoveryRPCService;
import org.openremote.web.console.service.AutoDiscoveryRPCServiceAsync;
import org.openremote.web.console.service.ControllerService;
import org.openremote.web.console.service.JSONPControllerConnector;
import org.openremote.web.console.service.JSONControllerConnector;
import org.openremote.web.console.service.LocalDataService;
import org.openremote.web.console.service.LocalDataServiceImpl;
import org.openremote.web.console.service.PanelService;
import org.openremote.web.console.service.PanelServiceImpl;
import org.openremote.web.console.service.ScreenViewService;
import org.openremote.web.console.util.BrowserUtils;
import org.openremote.web.console.util.ImageContainer;
import org.openremote.web.console.util.PollingHelper;
import org.openremote.web.console.view.ScreenViewImpl;
import org.openremote.web.console.widget.ScreenIndicator;
import org.openremote.web.console.widget.TabBarComponent;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.web.bindery.autobean.shared.AutoBean;

/**
 * 
 *  
 * @author <a href="mailto:richard@openremote.org">Richard Turner</a>
 */
public class ConsoleUnit extends VerticalPanel implements RotationHandler, WindowResizeHandler, SwipeHandler,
        HoldHandler, NavigateHandler, CommandSendHandler {
    public static final int MIN_WIDTH = 320;
    public static final int MIN_HEIGHT = 460;
    public static final int DEFAULT_DISPLAY_WIDTH = 320;
    public static final int DEFAULT_DISPLAY_HEIGHT = 460;
    public static final String CONSOLE_HTML_ELEMENT_ID = "consoleUnit";
    public static int FRAME_WIDTH_TOP = 20;
    public static int FRAME_WIDTH_BOTTOM = 50;
    public static int FRAME_WIDTH_LEFT = 20;
    public static int FRAME_WIDTH_RIGHT = 20;
    public static int BOSS_WIDTH = 2;
    public static final String LOGO_TEXT_LEFT = "Open";
    public static final String LOGO_TEXT_RIGHT = "Remote";
    public static final int IMAGE_CACHE_LOAD_TIMEOUT_SECONDS = 10;
    protected ConsoleDisplay consoleDisplay;
    private Boolean isFullscreen = true;
    protected int width;
    protected int height;
    private String orientation = "portrait";
    private ControllerService controllerService = ControllerService.getInstance();
    private PanelService panelService = PanelServiceImpl.getInstance();
    private LocalDataService dataService = LocalDataServiceImpl.getInstance();
    private ScreenViewService screenViewService = ScreenViewService.getInstance();
    private ControllerCredentials currentControllerCredentials = null;
    private Panel systemPanel = null;
    private String currentPanelName = null;
    private Integer currentGroupId = 0;
    private Integer currentScreenId = 0;
    private Map<SwipeDirection, Gesture> gestureMap = new HashMap<SwipeDirection, Gesture>();
    private Map<Integer, PollingHelper> pollingHelperMap = new HashMap<Integer, PollingHelper>();
    private boolean invalidWarningDisplayed = false;
    private Map<String, ImageContainer> imageCache = new HashMap<String, ImageContainer>();

    AsyncControllerCallback<Map<Integer, String>> pollingCallback = new AsyncControllerCallback<Map<Integer, String>>() {
        @Override
        public void onSuccess(Map<Integer, String> result) {
            HandlerManager eventBus = ConsoleUnitEventManager.getInstance().getEventBus();
            for (Iterator<Integer> it = result.keySet().iterator(); it.hasNext();) {
                Integer id = it.next();
                String sensorValue = result.get(id);
                eventBus.fireEvent(new SensorChangeEvent(id, sensorValue));
            }
        }
    };

    public enum EnumSystemScreen {
        //      CONTROLLER_LIST(50, 2, "controllerlist"),
        //      ADD_EDIT_CONTROLLER(54, 5, "editcontroller"),
        //      CONSOLE_SETTINGS(51, 3, "settings"),
        //      LOGIN(52, 4, "login"),
        //      LOGOUT(53, 4, "logout"),
        //      PANEL_SELECTION(55, 6, "panelselection");

        //TODO: System Screens - For now point everything to settings screen

        CONTROLLER_LIST(50, 2, "controllerlist"), EDIT_CONTROLLER(54, 5, "editcontroller"), ADD_CONTROLLER(56, 7,
                "addcontroller"), CONSOLE_SETTING(51, 3, "setting"), CONSOLE_SETTINGS(51, 3, "settings"), LOGIN(52,
                        4, "login"), LOGOUT(50, 2, "logout"), PANEL_SELECTION(55, 6, "panelselection");

        private final int id;
        private final int groupId;
        private final String name;

        EnumSystemScreen(int id, int groupId, String name) {
            this.id = id;
            this.groupId = groupId;
            this.name = name;
        }

        public int getId() {
            return id;
        }

        public int getGroupId() {
            return groupId;
        }

        public String getName() {
            return name;
        }

        public static EnumSystemScreen getSystemScreen(int id) {
            EnumSystemScreen result = null;
            for (EnumSystemScreen screen : EnumSystemScreen.values()) {
                if (screen.getId() == id) {
                    result = screen;
                    break;
                }
            }
            return result;
        }

        public static EnumSystemScreen getSystemScreen(String name) {
            EnumSystemScreen result = null;
            for (EnumSystemScreen screen : EnumSystemScreen.values()) {
                if (screen.getName().equalsIgnoreCase(name)) {
                    result = screen;
                    break;
                }
            }
            return result;
        }
    }

    public ConsoleUnit() {
        this(false);
    }

    public ConsoleUnit(boolean fullscreen) {
        this(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT, fullscreen);
    }

    public ConsoleUnit(int width, int height) {
        this(width, height, false);
    }

    public ConsoleUnit(int width, int height, boolean fullscreen) {
        //      if (fullscreen) {
        //         width = BrowserUtils.getWindowWidth();
        //         height = BrowserUtils.getWindowHeight();
        //      }
        ////      if (width > height) {
        ////         int tempWidth = height;
        ////         height = width;
        ////         width = tempWidth;
        ////      }
        //
        //      this.width = width;
        //      this.height = height;

        // Create a display and add to console container
        consoleDisplay = new ConsoleDisplay();
        //      DOM.setStyleAttribute(consoleDisplay.getElement(), "borderStyle", "solid ");
        //      DOM.setStyleAttribute(consoleDisplay.getElement(), "borderWidth", BOSS_WIDTH + "px");
        add(consoleDisplay);

        // Create Logo
        SimplePanel logoPanel = new SimplePanel();
        logoPanel.getElement().setId("consoleFrameLogo");
        logoPanel.setHeight(FRAME_WIDTH_BOTTOM - BOSS_WIDTH + "px");
        logoPanel.getElement().setAttribute("onselect", "return false;");
        add(logoPanel);

        // Set static console unit styling
        setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
        getElement().setId(CONSOLE_HTML_ELEMENT_ID);
        addStyleName("portrait");
        getElement().setAttribute("unselectable", "on");
        BrowserUtils.setStyleAttributeAllBrowsers(getElement(), "userSelect", "none");
        consoleDisplay.getElement().setAttribute("unselectable", "on");

        // Set Size
        setSize(width, height, fullscreen);

        // Register gesture and controller message handlers
        registerHandlers();
    }

    public void setSize(boolean fullscreen) {
        setSize(0, 0, true);
    }

    public void setSize(int width, int height) {
        setSize(width, height, isFullscreen);
    }

    public void setSize(int width, int height, boolean setFullscreen) {
        int winWidth = BrowserUtils.getWindowWidth();
        int winHeight = BrowserUtils.getWindowHeight();
        int maxDim = 0;
        String winOrientation = BrowserUtils.getWindowOrientation();

        if (BrowserUtils.isMobile) {
            setFullscreen = true;
        }
        if (!setFullscreen) {
            if (width > height) {
                int tempWidth = height;
                height = width;
                width = tempWidth;
            }

            //         if (maxDim >= winWidth || maxDim >= winHeight) {
            //             setFullscreen = true;
            //         }
        }

        if (setFullscreen) {
            if (winOrientation.equals("portrait")) {
                width = winWidth;
                height = winHeight;
            } else {
                width = winHeight;
                height = winWidth;
            }
        }

        maxDim = width > height ? width : height;

        width = width < MIN_WIDTH ? MIN_WIDTH : width;
        height = height < MIN_HEIGHT ? MIN_HEIGHT : height;

        toggleFrame(!setFullscreen);

        this.width = width;
        this.height = height;
        isFullscreen = setFullscreen;

        if (setFullscreen || maxDim >= winWidth || maxDim >= winHeight) {

            setOrientation(winOrientation);

            if (!winOrientation.equals(getOrientation())) {
                // Load in the inverse screen to what is currently loaded if screen orientation doesn't match console orientation
                if (panelService.isInitialized()) {
                    if (!orientation.equalsIgnoreCase(consoleDisplay.getOrientation())
                            || (!BrowserUtils.isMobile && isFullscreen)) {
                        Screen inverseScreen = panelService.getInverseScreen(currentScreenId);
                        if (inverseScreen != null) {
                            loadDisplay(inverseScreen, true, null);
                        }
                    }
                }
            }
        }

        consoleDisplay.setSize(width, height);
    }

    private void toggleFrame(boolean showFrame) {
        if (showFrame) {
            addStyleName("framed");
            removeStyleName("fullscreen");
            RootPanel.getBodyElement().removeClassName("fullscreen");
            DOM.setStyleAttribute(consoleDisplay.getElement(), "margin", (FRAME_WIDTH_TOP - BOSS_WIDTH) + "px "
                    + (FRAME_WIDTH_RIGHT - BOSS_WIDTH) + "px 0 " + (FRAME_WIDTH_LEFT - BOSS_WIDTH) + "px");
            DOM.setStyleAttribute(getElement(), "position", "absolute");
        } else {
            RootPanel.getBodyElement().addClassName("fullscreen");
            addStyleName("fullscreen");
            removeStyleName("framed");
            DOM.setStyleAttribute(consoleDisplay.getElement(), "margin", "0");
            DOM.setStyleAttribute(getElement(), "position", "static");
        }
    }

    public ConsoleDisplay getConsoleDisplay() {
        return this.consoleDisplay;
    }

    public int getWidth() {
        if (isFullscreen) {
            return width;
        } else {
            return width + FRAME_WIDTH_LEFT + FRAME_WIDTH_RIGHT;
        }
    }

    public int getHeight() {
        if (isFullscreen) {
            return height;
        } else {
            return height + FRAME_WIDTH_TOP + FRAME_WIDTH_BOTTOM;
        }
    }

    /**
     * Position the console unit in the centre of the window
     */
    public void setPosition() {
        int winWidth = BrowserUtils.getWindowWidth();
        int winHeight = BrowserUtils.getWindowHeight();
        //      int xPos = 0;
        //      int yPos = 0;
        //      if (BrowserUtils.isIE && orientation.equalsIgnoreCase("landscape")) {
        //         xPos = (int)Math.round(((double)winWidth/2)-(getHeight()/2));
        //         yPos = (int)Math.round(((double)winHeight/2)-(getWidth()/2));
        //      } else {
        if (!isFullscreen) {
            int xPos = (int) Math.round(((double) winWidth / 2) - (getWidth() / 2));
            int yPos = (int) Math.round(((double) winHeight / 2) - (getHeight() / 2));
            DOM.setStyleAttribute(this.getElement(), "position", "absolute");
            DOM.setStyleAttribute(this.getElement(), "top", yPos + "px");
            DOM.setStyleAttribute(this.getElement(), "left", xPos + "px");
        } else {
            DOM.setStyleAttribute(this.getElement(), "position", "static");
        }
        //      }
        //      BrowserUtils.getConsoleContainer().setWidgetPosition(this, xPos, yPos);
    }

    /**
     * Adjusts the CSS class to either landscape or portrait
     * @param orientation
     */
    public void setOrientation(String orientation) {
        int halfOuterWidth = (width + FRAME_WIDTH_LEFT + FRAME_WIDTH_RIGHT) / 2;
        int halfOuterHeight = (height + FRAME_WIDTH_TOP + FRAME_WIDTH_BOTTOM) / 2;

        if ("portrait".equals(orientation)) {
            BrowserUtils.setStyleAttributeAllBrowsers(this.getElement(), "transform",
                    "rotate(0deg) translate(0,0)");
            this.addStyleName("portrait");
            this.removeStyleName("landscape");
        } else if ("landscape".equals(orientation)) {
            if (!isFullscreen) {
                BrowserUtils.setStyleAttributeAllBrowsers(this.getElement(), "transform",
                        "rotate(-90deg) translate( -" + (halfOuterHeight + halfOuterWidth) + "px,-"
                                + (halfOuterHeight - halfOuterWidth) + "px)");
            } else {
                BrowserUtils.setStyleAttributeAllBrowsers(this.getElement(), "transform",
                        "rotate(-90deg) translate( -" + width + "px,0)");
            }
            this.addStyleName("landscape");
            this.removeStyleName("portrait");
        }

        if (BrowserUtils.isMobile) {
            Window.scrollTo(0, 1);
        }

        this.orientation = orientation;
        //      setPosition(BrowserUtils.getWindowWidth(), BrowserUtils.getWindowHeight());
    }

    public boolean getIsFullscreen() {
        return isFullscreen;
    }

    public String getOrientation() {
        return orientation;
    }

    public void hide() {
        setVisible(false);
    }

    public void show() {
        setVisible(true);
    }

    private void loadController(ControllerCredentials controllerCreds) {
        // Unload current panel
        unloadPanel();

        BrowserUtils.showLoadingMsg("Loading Controller");

        if (controllerCreds == null) {
            loadSettings(EnumSystemScreen.CONTROLLER_LIST, null);
        } else {
            currentControllerCredentials = controllerCreds;

            final Controller controller = new Controller(controllerCreds);

            controller.initialise(new AsyncControllerCallback<Boolean>() {
                @Override
                public void onSuccess(Boolean result) {
                    // Controller is fully initialised let's see what state it's in
                    if (!controller.isValid()) {
                        // Alert the user
                        BrowserUtils.showAlert("Controller Error!<br /><br />Controller '" + controller.getUrl()
                                + "' can't be reached. Make sure controller is running and if it is secured check your browser supports HTML5 CORS.");
                        loadSettings(EnumSystemScreen.CONTROLLER_LIST, null);
                        return;
                    }

                    // Set the appropriate controller connector
                    if (!controller.isSameOrigin()) {
                        controllerService.setConnector(new JSONPControllerConnector());
                    } else {
                        controllerService.setConnector(new JSONControllerConnector());
                    }

                    // Load the controller
                    controllerService.setController(controller);
                    currentPanelName = currentControllerCredentials.getDefaultPanel();

                    // If current panel name set try and load it otherwise prompt for panel to load
                    if (currentPanelName != null && !currentPanelName.equalsIgnoreCase("")) {
                        dataService.setLastControllerCredentials(currentControllerCredentials);
                        loadPanel(currentPanelName);
                    } else {
                        loadPanelSelection();
                    }
                }
            });
        }
    }

    private void loadPanelSelection() {
        // Retrieve panel identity list from controller and display panel selection screen
        controllerService.getPanelIdentities(new AsyncControllerCallback<PanelIdentityList>() {
            @Override
            public void onSuccess(PanelIdentityList panelIdentities) {
                if (panelIdentities != null) {
                    String dataValue = AutoBeanService.getInstance().toJsonString(panelIdentities);
                    DataValuePairContainer dvpC = AutoBeanService.getInstance().getFactory()
                            .create(DataValuePairContainer.class).as();
                    DataValuePair dvp = AutoBeanService.getInstance().getFactory().create(DataValuePair.class).as();
                    dvp.setName("panelIdentityList");
                    dvp.setValue(dataValue);
                    dvpC.setDataValuePair(dvp);
                    List<DataValuePairContainer> data = new ArrayList<DataValuePairContainer>();
                    data.add(dvpC);

                    loadSettings(EnumSystemScreen.PANEL_SELECTION, data);
                } else {
                    onError(EnumConsoleErrorCode.PANEL_LIST_ERROR);
                }
            }

            @Override
            public void onFailure(EnumControllerResponseCode code) {
                if (code == EnumControllerResponseCode.NOT_AUTHORIZED) {
                    // Take them to the login screen
                    loadSettings(EnumSystemScreen.LOGIN, null);
                } else {
                    onError(code);
                }
            }

            @Override
            public void onFailure(Throwable error) {
                onError(EnumConsoleErrorCode.PANEL_LIST_ERROR);
            }
        });
    }

    private void loadPanel(final String panelName) {
        unloadPanel();
        BrowserUtils.showLoadingMsg("Loading Panel");
        controllerService.getPanel(panelName, new AsyncControllerCallback<Panel>() {
            @Override
            public void onFailure(EnumControllerResponseCode response) {
                BrowserUtils.hideLoadingMsg();
                if (response == EnumControllerResponseCode.NOT_AUTHORIZED
                        || response == EnumControllerResponseCode.FORBIDDEN) {
                    // Take them to the login screen
                    loadSettings(EnumSystemScreen.LOGIN, null);
                } else {
                    onError(response);
                }
            }

            @Override
            public void onSuccess(Panel result) {
                BrowserUtils.hideLoadingMsg();
                if (result != null) {
                    try {
                        // Update current controller credentials
                        currentControllerCredentials.setDefaultPanel(panelName);
                        dataService.setLastControllerCredentials(currentControllerCredentials);

                        if (!setPanel(result)) {
                            if (result != systemPanel) {
                                // Display error and go to system screen
                                onError(EnumConsoleErrorCode.PANEL_DEFINITION_ERROR);
                                return;
                            } else {
                                // Big problem if we can't load system screens so let's exit
                                Window.alert(
                                        "Failed to load a system screen!\n\nThis is a big problem and we can't continue.");
                                return;
                            }
                        }
                    } catch (Exception e) {
                        onError(EnumConsoleErrorCode.PANEL_DEFINITION_ERROR, e.getMessage());
                    }
                } else {
                    onError(EnumConsoleErrorCode.UNKNOWN_ERROR, "Load Panel Response Invalid");
                }
            }
        });
    }

    private boolean setPanel(Panel result) {
        boolean success = false;

        if (result != null) {
            // Unload current panel
            unloadPanel();

            // Set new panel and prefetch image resources
            panelService.setCurrentPanel(result);

            BrowserUtils.showLoadingMsg("Retrieving Resources..");

            try {
                //            List<String> imageUrls = panelService.getImageResourceUrls();

                //            for(String imageUrl : imageUrls ) {
                //               addImageToCache(imageUrl);
                //               Thread.sleep(100);
                //            }

                Timer imageCacher = new Timer() {
                    int i = 0;
                    String[] imageUrls = panelService.getPanelImageUrls();

                    @Override
                    public void run() {
                        if (i < imageUrls.length) {
                            addImageToCache(imageUrls[i]);
                            i++;
                            this.schedule(100);
                        } else {
                            // Prefetch All Images Resources before proceeding
                            loadCache(new AsyncControllerCallback() {

                                @Override
                                public void onSuccess(Object result) {
                                    initialisePanel();
                                }

                                @Override
                                public void onFailure(Throwable e) {
                                    initialisePanel();
                                }
                            });
                        }
                    }
                };

                imageCacher.run();
            } catch (Exception e) {
                return false;
            }
        }
        return true;
    }

    private void loadCache(final AsyncControllerCallback callback) {
        Timer imageLoader = new Timer() {
            private int secondCount = 0;
            private boolean allImagesLoaded = false;

            public void run() {
                boolean allImagesLoaded = true;
                for (Iterator<String> it = imageCache.keySet().iterator(); it.hasNext();) {
                    String url = it.next();
                    ImageContainer image = imageCache.get(url);
                    if (!image.getLoadAttempted()) {
                        allImagesLoaded = false;
                        break;
                    }
                }

                if (secondCount > IMAGE_CACHE_LOAD_TIMEOUT_SECONDS) {
                    callback.onFailure(new Exception("Timeout during image loading"));
                } else if (allImagesLoaded) {
                    callback.onSuccess(null);
                } else {
                    secondCount++;
                    this.schedule(1000);
                }
            }
        };
        imageLoader.run();
    }

    private void initialisePanel() {
        if (panelService.isInitialized()) {
            // Reset warning flag
            invalidWarningDisplayed = false;

            // Get default group ID
            Integer defaultGroupId = panelService.getDefaultGroupId();
            Screen defaultScreen = panelService.getDefaultScreen(defaultGroupId);

            if (defaultScreen != null) {
                String screenOrientation = (defaultScreen.getLandscape() != null && defaultScreen.getLandscape())
                        ? "landscape"
                        : "portrait";

                // Load in the inverse screen to what is currently loaded if screen orientation doesn't match console orientation
                if (panelService.isInitialized()) {
                    if (!screenOrientation.equalsIgnoreCase(consoleDisplay.getOrientation())) {
                        Screen inverseScreen = panelService.getInverseScreen(defaultScreen.getId());
                        if (inverseScreen != null) {
                            defaultScreen = inverseScreen;
                        }
                    }
                }

                loadDisplay(defaultGroupId, defaultScreen, null);
            } else {
                loadSettings(EnumSystemScreen.PANEL_SELECTION, null);
            }
        } else {
            loadSettings(EnumSystemScreen.PANEL_SELECTION, null);
        }
    }

    private void unloadPanel() {
        panelService.setCurrentPanel(null);
        screenViewService.reset();
        consoleDisplay.clearDisplay();
        clearGestureMap();

        for (Integer screenId : pollingHelperMap.keySet()) {
            PollingHelper helper = pollingHelperMap.get(screenId);
            if (helper != null) {
                helper.stopMonitoring();
            }
        }
        pollingHelperMap.clear();

        currentGroupId = 0;
        currentScreenId = 0;
    }

    private void unloadControllerAndPanel() {
        unloadPanel();
        unloadController();
    }

    private void unloadController() {
        // Clear last controller credentials
        dataService.setLastControllerCredentials(null);

        // Logout of controller
        controllerService.logout(new AsyncControllerCallback<Boolean>() {
            @Override
            public void onSuccess(Boolean result) {
            }

            @Override
            public void onFailure(Throwable error) {
            }

            @Override
            public void onFailure(EnumControllerResponseCode response) {
            }
        });

        controllerService.setController(null);
    }

    public void reloadControllerAndPanel() {
        unloadControllerAndPanel();

        // Wait 2s before reloading to allow controller time to re-initialise
        Timer reloadTimer = new Timer() {
            @Override
            public void run() {
                loadController(currentControllerCredentials);
            }
        };
        reloadTimer.schedule(5000);
    }

    public void restart() {
        unloadControllerAndPanel();
        onAdd();
    }

    private void loadSettings(EnumSystemScreen systemScreen, List<DataValuePairContainer> data) {
        if (systemScreen == EnumSystemScreen.CONTROLLER_LIST || systemScreen == EnumSystemScreen.LOGOUT) {
            unloadController();
        }

        if (panelService.getCurrentPanel() != systemPanel) {
            unloadPanel();

            panelService.setCurrentPanel(systemPanel);
        }

        int groupId = systemScreen.getGroupId();
        int screenId = systemScreen.getId();

        if (this.getOrientation().equalsIgnoreCase("landscape") && screenId < 1000) {
            screenId += 1000;
        }

        Screen screen = panelService.getScreenById(screenId);

        if (screen == null || !loadDisplay(groupId, screen, data)) {
            // Big problem if we can't load system screens so let's exit
            Window.alert("Failed to load a system screen!\n\nThis is a big problem and we can't continue.");
            return;
        }
    }

    private boolean loadDisplay(Screen screen, List<DataValuePairContainer> data) {
        return loadDisplay(currentGroupId, screen, data);
    }

    private boolean loadDisplay(Screen screen, boolean orientationChanged, List<DataValuePairContainer> data) {
        return loadDisplay(currentGroupId, screen, data);
    }

    private boolean loadDisplay(Integer newGroupId, Screen screen, List<DataValuePairContainer> data) {
        boolean screenChanged = false;
        boolean groupChanged = false;
        boolean screenOrientationChanged = false;
        ScreenViewImpl currentScreenView = consoleDisplay.getScreen();
        Integer oldScreenId = currentScreenId;

        if (screen == null || newGroupId == null) {
            onError(EnumConsoleErrorCode.PANEL_DEFINITION_ERROR);
            return false;
        }

        int newScreenId = screen.getId();

        if (currentScreenId != newScreenId) {
            screenChanged = true;
            screenOrientationChanged = (currentScreenView == null || ((currentScreenView.isLandscape() != null
                    && currentScreenView.isLandscape()) != (screen.getLandscape() != null
                            && screen.getLandscape()))) ? true : false;
        }
        if (currentGroupId != newGroupId) {
            groupChanged = true;
        }

        if (!screenChanged && !groupChanged) {
            return true;
        }

        if (screenChanged) {
            // Try setting new screen fall back to previous screen on failure only if this isn't the systemPanel
            try {
                ScreenViewImpl screenView = screenViewService.getScreenView(screen);
                if (screenView == null) {
                    throw new Exception("Failed to retrieve screen view for screen ID: " + screen.getId());
                }
                consoleDisplay.setScreenView(screenView, data);
                currentScreenView = screenView;
            } catch (Exception e) {
                if (panelService.getCurrentPanel() == systemPanel) {
                    // Just return
                    return false;
                }
                try {
                    // Put screen back to previous one
                    consoleDisplay.setScreenView(currentScreenView, data);
                    onError(EnumConsoleErrorCode.SCREEN_ERROR, "Screen ID = " + newScreenId);
                } catch (Exception ex) {
                    onError(EnumConsoleErrorCode.UNKNOWN_ERROR, ex.getMessage());
                }
                return false;
            }

            // Configure gestures
            setGestureMap(screen.getGesture());

            // Stop previous polling
            if (pollingHelperMap.containsKey(oldScreenId)) {
                PollingHelper pollingHelper = pollingHelperMap.get(oldScreenId);
                if (pollingHelper != null) {
                    pollingHelper.stopMonitoring();
                }
            }
            // Start new polling
            if (!pollingHelperMap.containsKey(newScreenId)) {
                Set<Integer> sensorIds = currentScreenView.getSensorIds();
                if (sensorIds == null || sensorIds.size() == 0) {
                    pollingHelperMap.put(newScreenId, null);
                } else {
                    pollingHelperMap.put(newScreenId, new PollingHelper(sensorIds, pollingCallback));
                }
            }
            PollingHelper pollingHelper = pollingHelperMap.get(newScreenId);
            if (pollingHelper != null) {
                pollingHelper.startSensorMonitoring();
            }
            currentScreenId = newScreenId;
        }

        if (groupChanged) {
            consoleDisplay.removeTabBar();
            // Get Tab Bar for this group
            TabBar tabBar = panelService.getTabBar(newGroupId);
            if (tabBar != null && tabBar.getItem() != null) {
                try {
                    TabBarComponent tabBarComponent = new TabBarComponent(tabBar);
                    consoleDisplay.setTabBar(tabBarComponent);
                    tabBarComponent.onScreenViewChange(new ScreenViewChangeEvent(newScreenId, newGroupId)); // Problem with event bus means tab bar doesn't receive event notification when first added
                } catch (Exception e) {
                    onError(EnumConsoleErrorCode.TABBAR_ERROR);
                }
            }
            currentGroupId = newGroupId;
        }
        if (groupChanged || (screenChanged && screenOrientationChanged)) {
            // Get Screen ID List and create screenIndicator
            List<Integer> screenIds = panelService.getGroupScreenIdsWithSameOrientation(newScreenId, newGroupId);
            if (screenIds != null && screenIds.size() > 1) {
                ScreenIndicator screenIndicator = new ScreenIndicator(screenIds);
                consoleDisplay.setScreenIndicator(screenIndicator);
                screenIndicator.onScreenViewChange(new ScreenViewChangeEvent(newScreenId, newGroupId)); // Problem with event bus means indicator doesn't receive event notification when first added
            } else {
                consoleDisplay.removeScreenIndicator();
            }
            consoleDisplay.updateScreenIndicator();
            consoleDisplay.updateTabBar();
        }

        if (screenChanged) {
            ConsoleUnitEventManager.getInstance().getEventBus()
                    .fireEvent(new ScreenViewChangeEvent(newScreenId, newGroupId));
        }
        return true;
    }

    private void setGestureMap(List<Gesture> gestures) {
        clearGestureMap();

        if (gestures != null) {
            for (Gesture gesture : gestures) {
                SwipeDirection direction = SwipeDirection.enumValueOf(gesture.getType());
                gestureMap.put(direction, gesture);
            }
        }
    }

    private void clearGestureMap() {
        gestureMap.put(SwipeDirection.LEFT, null);
        gestureMap.put(SwipeDirection.RIGHT, null);
        gestureMap.put(SwipeDirection.UP, null);
        gestureMap.put(SwipeDirection.DOWN, null);
    }

    private void getIsSecure() {
        controllerService.isSecure(new AsyncControllerCallback<Boolean>() {
            @Override
            public void onSuccess(Boolean result) {
                if (result) {
                    // TODO:
                    Window.alert("I'm Secure!");
                } else {
                    // TODO:
                    Window.alert("I'm not Secure");
                }
            }
        });
    }

    public ControllerService getControllerService() {
        return this.controllerService;
    }

    public LocalDataService getLocalDataService() {
        return this.dataService;
    }

    public void addImageToCache(String url) {
        if (imageCache.containsKey(url))
            return;

        String imageUrl = url;
        Controller controller = controllerService.getController();
        if (controller != null && controller.isProxied()) {
            ControllerCredentials creds = controller.getCredentials();
            imageUrl = BrowserUtils.getImageProxyURL(creds.getUsername(), creds.getPassword(), url);
        }

        imageCache.put(url, new ImageContainer(imageUrl));
    }

    public ImageContainer getImageFromCache(String url) {
        ImageContainer container = null;
        container = imageCache.get(url);
        if (container != null) {
            container = container.clone();
        } else {
            container = new ImageContainer("");
        }
        return container;
    }

    private void initialiseConsole() {
        // Check for Last Controller and Panel in Cache
        ControllerCredentials controllerCreds = dataService.getLastControllerCredentials();
        if (controllerCreds != null && controllerCreds.getUrl() != null) {
            loadController(controllerCreds);
        } else {
            // No controller to load so go to settings
            loadSettings(EnumSystemScreen.CONTROLLER_LIST, null);
        }

        //      // TODO: Check for default Controller in Settings
        //      controllerCreds = dataService.getDefaultControllerCredentials();
        //      if (controllerCreds != null) {
        //         panelName = controllerCreds.getDefaultPanel();
        //      } else {
        //         controllerCreds = AutoBeanService.getInstance().getFactory().create(ControllerCredentials.class).as();
        //         controllerCreds.setUrl("http://controller.openremote.org/iphone/controller/");
        //         controllerCreds.setDefaultPanel("My Home");
        //         dataService.setDefaultControllerCredentials(controllerCreds);
        //      }
        //      
        //      if (panelName != null && !panelName.equals("")) {
        //         loadControllerAndPanel(controllerCreds, panelName);
        //      } else {      

        //      }
    }

    /*
     * **********************************************
     * Event Handlers below here
     * **********************************************
     */
    private void registerHandlers() {
        HandlerManager eventBus = ConsoleUnitEventManager.getInstance().getEventBus();
        eventBus.addHandler(RotationEvent.getType(), this);
        eventBus.addHandler(WindowResizeEvent.getType(), this);
        eventBus.addHandler(SwipeEvent.getType(), this);
        eventBus.addHandler(HoldEvent.getType(), this);
        eventBus.addHandler(NavigateEvent.getType(), this);
        eventBus.addHandler(CommandSendEvent.getType(), this);
    }

    public void onAdd() {
        // Set Position
        setPosition();

        // Configure display
        consoleDisplay.onAdd(width, height);

        show();

        // Initialise the system panel
        //      String systemPanelStr = dataService.getObjectString(EnumDataMap.SYSTEM_PANEL.getDataName());
        //      if (systemPanelStr == null) {
        // Load from Server
        BrowserUtils.showLoadingMsg("Retreiving System Panel Definition");

        try {
            int displayDensity = BrowserUtils.getDisplayDensityValue();
            new RequestBuilder(RequestBuilder.GET, "resources/systempanel" + displayDensity + ".json")
                    .sendRequest("", new RequestCallback() {
                        @Override
                        public void onResponseReceived(Request request, Response response) {
                            String systemPanelStr = response.getText();
                            systemPanel = AutoBeanService.getInstance().fromJsonString(Panel.class, systemPanelStr)
                                    .as();

                            // Initialise the system panel
                            panelService.setCurrentPanel(systemPanel);

                            BrowserUtils.showLoadingMsg("Retrieving Resources..");

                            try {
                                //                     List<String> imageUrls = panelService.getImageResourceUrls();

                                //                     for(String imageUrl : imageUrls ) {
                                //                        addImageToCache(imageUrl);
                                //                        Thread.sleep(100);
                                //                     }

                                Timer imageCacher = new Timer() {
                                    int i = 0;
                                    String[] imageUrls = panelService.getPanelImageUrls();

                                    @Override
                                    public void run() {
                                        if (i < imageUrls.length) {
                                            addImageToCache(imageUrls[i]);
                                            i++;
                                            this.schedule(100);
                                        }
                                    }
                                };

                                imageCacher.run();

                                // Prefetch All Images Resources before proceeding
                                loadCache(new AsyncControllerCallback() {

                                    @Override
                                    public void onSuccess(Object result) {
                                        initialiseConsole();
                                    }

                                    @Override
                                    public void onFailure(Throwable e) {
                                        BrowserUtils.hideLoadingMsg();
                                        BrowserUtils.showAlert(
                                                "FATAL Error: Failed to retrieve System Panel Definition.");
                                    }
                                });
                            } catch (Exception e) {
                                BrowserUtils.hideLoadingMsg();
                                BrowserUtils.showAlert("FATAL Error: Failed to retrieve System Panel Definition.");
                            }
                        }

                        @Override
                        public void onError(Request request, Throwable exception) {
                            BrowserUtils.hideLoadingMsg();
                            BrowserUtils.showAlert("FATAL Error: Failed to retrieve System Panel Definition.");
                        }
                    });
        } catch (RequestException e) {
            BrowserUtils.hideLoadingMsg();
            BrowserUtils.showAlert("FATAL Error: Failed to retrieve System Panel Definition.");
        }
        //      }
        //      else {
        //         systemPanel = AutoBeanService.getInstance().fromJsonString(Panel.class, systemPanelStr).as();
        //         initialiseConsole();
        //      }

    }

    @Override
    public void onRotate(RotationEvent event) {
        String orientation = event.getOrientation();

        // Rotate the console unit if fullscreen or mobile but if desktop and fullscreen just rotate the display
        if (BrowserUtils.isMobile || (!BrowserUtils.isMobile && !isFullscreen)) {
            setOrientation(orientation);
        }

        // Load in the inverse screen to what is currently loaded if screen orientation doesn't match console orientation
        if (panelService.isInitialized()) {
            if (!orientation.equalsIgnoreCase(consoleDisplay.getOrientation())
                    || (!BrowserUtils.isMobile && isFullscreen)) {
                Screen inverseScreen = panelService.getInverseScreen(currentScreenId);
                if (inverseScreen != null) {
                    loadDisplay(inverseScreen, true, null);
                }
            }
        }
    }

    @Override
    public void onWindowResize(WindowResizeEvent event) {
        // If fullscreen unit then we update the console unit size
        if (BrowserUtils.isMobile || isFullscreen) {
            if (getOrientation().equalsIgnoreCase("portrait")) {
                setSize(event.getWindowWidth(), event.getWindowHeight());
            } else {
                setSize(event.getWindowHeight(), event.getWindowWidth());
            }
        } else {
            //         setPosition(event.getWindowWidth(), event.getWindowHeight());
            setPosition();
        }
    }

    @Override
    public void onHold(HoldEvent event) {
        if (event.getSource() == consoleDisplay && !BrowserUtils.disableFailsafe()) {
            loadSettings(EnumSystemScreen.CONTROLLER_LIST, null);
        }
    }

    @Override
    public void onSwipe(SwipeEvent event) {
        Gesture gesture = gestureMap.get(event.getDirection());
        boolean gestureHandled = false;
        Navigate navigate = null;
        Boolean hasControlCommand = null;
        Integer commandId = null;

        if (gesture != null) {
            navigate = gesture.getNavigate();
            hasControlCommand = gesture.getHasControlCommand();
            commandId = gesture.getId();
            HandlerManager eventBus = ConsoleUnitEventManager.getInstance().getEventBus();

            if (navigate != null) {
                if (navigate.getTo() != null) {
                    if (navigate.getTo().equalsIgnoreCase("previousscreen")) {
                        gestureHandled = true;
                        Screen prevScreen = panelService.getPreviousScreen(currentGroupId, currentScreenId);
                        if (prevScreen != null) {
                            loadDisplay(prevScreen, null);
                        }
                    } else if (navigate.getTo().equalsIgnoreCase("nextscreen")) {
                        gestureHandled = true;
                        Screen nextScreen = panelService.getNextScreen(currentGroupId, currentScreenId);
                        if (nextScreen != null) {
                            loadDisplay(nextScreen, null);
                        }
                    }
                }
                if (!gestureHandled
                        && (navigate.getToGroup() != currentGroupId || navigate.getToScreen() != currentScreenId)) {
                    gestureHandled = true;
                    eventBus.fireEvent(new NavigateEvent(navigate));
                }
            } else if (hasControlCommand != null && hasControlCommand) {
                gestureHandled = true;
                eventBus.fireEvent(new CommandSendEvent(commandId, "swipe", null));
            }
        }

        if (gestureHandled) {
            return;
        }

        switch (event.getDirection()) {
        case LEFT:
            Screen nextScreen = panelService.getNextScreen(currentGroupId, currentScreenId);
            if (nextScreen != null) {
                loadDisplay(nextScreen, null);
            }
            break;
        case RIGHT:
            Screen prevScreen = panelService.getPreviousScreen(currentGroupId, currentScreenId);
            if (prevScreen != null) {
                loadDisplay(prevScreen, null);
            }
            break;
        }
    }

    @Override
    public void onNavigate(NavigateEvent event) {
        Navigate navigate = event.getNavigate();
        if (navigate != null) {
            String to = navigate.getTo();
            Integer toGroupId = navigate.getToGroup();
            Integer toScreenId = navigate.getToScreen();
            List<DataValuePairContainer> data = navigate.getData();

            if (to != null && !to.equals("")) {
                EnumSystemScreen screen = EnumSystemScreen.getSystemScreen(to);
                if (screen != null) {
                    loadSettings(screen, data);
                }
            } else if (toGroupId != null) {
                Screen screen = null;
                if (toScreenId == null) {
                    screen = panelService.getDefaultScreen(toGroupId);
                } else {
                    screen = panelService.getScreenById(toScreenId, toGroupId);
                }
                loadDisplay(toGroupId, screen, data);
            }
        }
    }

    @Override
    public void onCommandSend(CommandSendEvent event) {
        if (event != null) {
            switch (event.getCommandId()) {

            case -1:
            case -1001: //Controller Discovery
                // Change tab bar search item image
                String imageSrc = BrowserUtils.getSystemImageDir() + "controller_searching.gif";
                consoleDisplay.getTabBar().getItems().get(0).setImageSrc(imageSrc);

                // Do RPC
                AutoDiscoveryRPCServiceAsync discoveryService = (AutoDiscoveryRPCServiceAsync) GWT
                        .create(AutoDiscoveryRPCService.class);
                AsyncControllerCallback<List<String>> callback = new AsyncControllerCallback<List<String>>() {
                    @Override
                    public void onSuccess(List<String> discoveredUrls) {
                        ControllerCredentialsList credsListObj = dataService.getControllerCredentialsList();
                        List<ControllerCredentials> credsList = new ArrayList<ControllerCredentials>();

                        if (credsListObj != null) {
                            credsList = credsListObj.getControllerCredentials();
                        }

                        for (String discoveredUrl : discoveredUrls) {
                            boolean alreadyExists = false;
                            for (ControllerCredentials creds : credsList) {
                                if (creds.getUrl().equalsIgnoreCase(discoveredUrl)) {
                                    alreadyExists = true;
                                    break;
                                }
                            }
                            if (!alreadyExists) {
                                AutoBean<ControllerCredentials> credentialsBean = AutoBeanService.getInstance()
                                        .getFactory().controllerCredentials();
                                credentialsBean.as().setUrl(discoveredUrl);
                                credsList.add(credentialsBean.as());
                            }
                        }

                        if (credsListObj != null) {
                            credsListObj.setControllerCredentials(credsList);
                            dataService.setControllerCredentialsList(credsListObj);
                        }

                        resetTabItemImage();
                    }

                    @Override
                    public void onFailure(Throwable exception) {
                        resetTabItemImage();
                        super.onFailure(exception);
                    }

                    private void resetTabItemImage() {
                        String imageSrc = BrowserUtils.getSystemImageDir() + "controller_search.png";
                        consoleDisplay.getTabBar().getItems().get(0).setImageSrc(imageSrc);
                    }
                };
                discoveryService.getAutoDiscoveryServers(callback);
                break;
            case -2:
            case -1002: // Load Controller
                String loadUrl = event.getCommand();
                ControllerCredentialsList credsList = dataService.getControllerCredentialsList();
                for (ControllerCredentials creds : credsList.getControllerCredentials()) {
                    if (creds.getUrl().equalsIgnoreCase(loadUrl)) {
                        loadController(creds);
                        break;
                    }
                }
                break;
            case -3:
            case -1003: // Clear Cache
                dataService.clearAllData();
                loadSettings(EnumSystemScreen.CONTROLLER_LIST, null);
                break;
            case -4:
            case -1004: // Load Panel
                String panelName = event.getCommand();
                loadPanel(panelName);
                break;
            case -5:
            case -1005: // Login
                InputElement userElem = DOM.getElementById("loginuserid").cast();
                InputElement passElem = DOM.getElementById("loginpassword").cast();

                // If we get here user is submitting login form
                Controller controller = controllerService.getController();
                String username = userElem.getValue().trim();
                controller.setUsername(username);
                String password = passElem.getValue().trim();
                controller.setPassword(password);

                //TODO: Test login credentials and notify on failure

                loadPanelSelection();
                break;
            case -6:
            case -1006: // Logout
                loadSettings(EnumSystemScreen.CONTROLLER_LIST, null);
                break;
            default:
                controllerService.sendCommand(event.getCommandId() + "/" + event.getCommand(),
                        new AsyncControllerCallback<Boolean>() {
                            @Override
                            public void onSuccess(Boolean result) {
                                if (!result) {
                                    BrowserUtils.showAlert("Command Send Failed!");
                                }
                            }

                            public void onFailure(Throwable exception) {
                                // DO NOTHING HERE AS CONTROLLER MAY BE ALIVE BUT NOT AGREE WITH THE COMMAND REQUEST BUT DOESN'T EXPLICITLY TELL US THAT
                            }
                        });
            }
        }
    }

    public void onError(EnumControllerResponseCode errorCode) {
        switch (errorCode) {
        case XML_CHANGED:
            // Try and reload the panel
            reloadControllerAndPanel();
            break;
        case COMPONENT_INVALID:
            // TODO: display message in alert popup
            if (!invalidWarningDisplayed) {
                BrowserUtils
                        .showAlert("Polling Failed!<br /><br />At least one command ID has not been recognised.");
                invalidWarningDisplayed = true;
            }
            break;
        case PANEL_NOT_FOUND:
            loadPanelSelection();
            break;
        case FORBIDDEN:
            BrowserUtils.showAlert(
                    "Security Error!<br /><br />Controller is secured and supplied credentials are invalid.");
        default:
            BrowserUtils.showAlert(
                    "Error!<br /><br />The following error occurred: -<br /><br />" + errorCode.getDescription());
            loadSettings(EnumSystemScreen.CONTROLLER_LIST, null);
        }
    }

    public void onError(EnumConsoleErrorCode errorCode) {
        onError(errorCode, null);
    }

    public void onError(EnumConsoleErrorCode errorCode, String additionalInfo) {
        String errorStr = errorCode.getDescription();

        if (additionalInfo != null && !additionalInfo.equals("")) {
            errorStr += "\n\nAdditional Info: " + additionalInfo;
        }
        switch (errorCode) {
        default:
            BrowserUtils.showAlert("Console Error:\n\n" + errorStr);
            currentScreenId = 0;
        }
        loadSettings(EnumSystemScreen.CONTROLLER_LIST, null);
    }
}