/*
    Copyright 2013 Adobe Systems Incorporated.  All rights reserved. 

    Purpose:
        Controller is responsible for 
        Creation of all the HUD Containers , HUD objects.
        Listens to events on Browser and Delegates the events to registered HUDs.
        Exception Handling
*/

/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, maxerr: 50 */
/*global DW_LIVEEDIT_CONSTANTS,EditableRegion,TextFormattingHud,LiveEditEvent,TextEditHud,DW_LIVEEDIT_EVENTS,globalController, DW_ICE_HEADLIGHTS, DW_EXTENSION_EVENT, liveEditResourcePath, Node, $dwJQuery, isDwLeInitialized, dwGetShouldFollowLinks*/

function Controller() {
    //member variables
    'use strict';
    this.m_liveEditDisabled = false;
    this.m_isDebugging = false;
    this.m_liveEditEvent = null; //Event handler 
    this.m_txtHud = null; // text hud instance
    this.m_currentEvent = null; // recent event occurred on liveview.
    this.m_curClickedElement = null; // element affected by recent event
    this.m_curElementUnderEdit = null; // This is the latest element that recieved click and editable
    this.m_parentContainer = null; // Container for everybody
    this.m_overlayDiv = null; // Overlay Div to show
    this.m_disableDWSelection = false;
    this.isFileDialogUp = false;// this is set from Text Formatting HUD
    //member functions
    /*
    This function for DEBUGGING purpose only.
    */
    this.logDebugMsg = function (msg) {

        if (this.m_isDebugging === true) {
            if (window.writeDWLog) {
                window.writeDWLog(msg);
            }
        }
    };
    /*
    This function returns localized string for a given string Id.
    */
    this.getLocalizedString = function (stringId) {
        var result = "";
        if ($dwJQuery !== 'undefined') {
            result = $dwJQuery.i18n.prop(stringId);
        }
        return result;
    };
    /*
        Initialization of all the HUDS and Event managers
        And creation of containers for each of the HUDS.
    */
    this.init = function () {
        this.m_currentEvent = null;
        this.m_curElementUnderEdit = null;

        var liveExtensionsConfigPath;
        if (window.location && window.location.protocol !== "file:") {
            //If it is not a file: URL, browser will not load file: URLs in iFrames due to cross origin policy.
            //So our extensions will not load in this case. Here we are faking that our extensions
            //are present in the remote host. We will provide these files from DW CEF resource loader
            ///when we get a load request. SO we need to identify our extension files in the URL.
            //Adding a placeholder here to identify our extension resources. DW CEF resource loader 
            //will look for this placeholder and replace as needed if found. And the browser will think
            //that this is coming from remote host, thus bypassing cross origin policy
            liveExtensionsConfigPath = window.location.protocol + "//" + window.location.hostname + "/";
            liveExtensionsConfigPath += DW_LIVEEDIT_CONSTANTS.ExtensionsResourcePathPlaceHolder;
        } else {
            liveExtensionsConfigPath = liveEditResourcePath + "/" + DW_LIVEEDIT_CONSTANTS.Extensions;
        }

        this.m_liveEditEvent = new LiveEditEvent();
        if ($dwJQuery !== 'undefined') {
            var stringsPath = liveExtensionsConfigPath + '/Strings/';
            $dwJQuery.i18n.properties({
                name: 'LiveEditStrings',
                language: ' ',
                path: stringsPath,
                mode: 'map',
                callback: function () {
                }
            });
        }
        // Create EditableRegion HUD only for template Instance.
        if (window.liveEditTemplateInstance) {
            this.m_editableRegionHud = new EditableRegion(this.m_liveEditEvent);
            if (window.liveViewExtensionsObject && window.liveViewExtensionsObject.dwObject) {
                window.liveViewExtensionsObject.dwObject.logHeadlightsData(DW_ICE_HEADLIGHTS.OTH_ELV, DW_ICE_HEADLIGHTS.TemplateEdited);
            }
        }
        // Initialize other HUDs.
        this.m_txtHud = new TextEditHud(this.m_liveEditEvent);
        // Initialize Containers for HUDs.
        this.createContainers();
    };

    /*
    create containers for all the HUDS.
    <dw-container-div>
        <style type="text/css"> OVERLAYCSS ( that got attached during bridging</style>
        <dw-div id="dw_liveedit_text_hud" ></dw-div> 
        <dw-div id="dw_liveedit_overlay_div" ></dw-div> 
    </dw-container-div>  ---> block events on this div so that it will not reach body.
    */
    this.createContainers = function () {
        var bodyDiv = document.body || document.getElementsByTagName('body')[0];
        var containerAlreadyExisting = document.getElementsByTagName(DW_LIVEEDIT_CONSTANTS.GlobalContainerDiv)[0];
        if (containerAlreadyExisting) {
            containerAlreadyExisting.parentNode.removeChild(containerAlreadyExisting);
        }
        var parentContainer = document.createElement(DW_LIVEEDIT_CONSTANTS.GlobalContainerDiv);
        //set position property to default value to override * selector
        parentContainer.style.cssText = "position:static;";

        this.m_overlayDiv = document.createElement(DW_LIVEEDIT_CONSTANTS.ContainerDiv);
        var overlayStyleTag = document.createElement('style');
        overlayStyleTag.setAttribute("ID", DW_LIVEEDIT_CONSTANTS.TextEditScriptStyleID);
        overlayStyleTag.type = 'text/css';
        overlayStyleTag.innerHTML = window.liveEditOverlayCss;


        this.m_parentContainer = parentContainer;
        parentContainer.appendChild(overlayStyleTag);
        parentContainer.appendChild(this.m_overlayDiv);
        bodyDiv.appendChild(parentContainer);

        // Initialize EditableRegion HUD. This HUD is created only for template Instance.
        if (this.m_editableRegionHud) {
            // Create & set Container DIV for EditableRegion HUD.
            var editableRegionContainer = document.createElement(DW_LIVEEDIT_CONSTANTS.ContainerDiv);
            parentContainer.appendChild(editableRegionContainer);
            this.m_editableRegionHud.setHudContainer(editableRegionContainer);
            // Initizliae Editable Regions
            this.m_editableRegionHud.initER();
        }

        this.m_txtHud.setOverlayDiv(this.m_overlayDiv);

    };

    this.reloadOverlayStyles = function () {
        var overlayStyle = document.getElementById(DW_LIVEEDIT_CONSTANTS.TextEditScriptStyleID);
        if (overlayStyle && overlayStyle.parentNode) {
            overlayStyle.parentNode.removeChild(overlayStyle);
        }
        var overlayStyleTag = document.createElement('style');
        overlayStyleTag.setAttribute("ID", DW_LIVEEDIT_CONSTANTS.TextEditScriptStyleID);
        overlayStyleTag.type = 'text/css';
        overlayStyleTag.innerHTML = window.liveEditOverlayCss;
        this.m_parentContainer.appendChild(overlayStyleTag);
    };

    this.setEvent = function (evt) {
        this.m_currentEvent = evt;
        this.m_curClickedElement = evt.target;
    };
    this.getEvent = function () {
        return this.m_currentEvent;
    };
   /*
        argument: type = "single" | "double"
        This is the core part of controller.
        for any clicks this is the flow:
        Click would have got to controller ONLY if it is outside our HUDS. ( Reiterating the fact that HUDS Should block events to propagate from them to body).
        1. Ask all the HUDS currently visible to commit themself.
        2. Ask all the HUDS currently visible to Destroy themself.
        3. Now check if the current click needs any action by checking if it is editable
            if (editable) fire corresponding event to everybody
            if (not editable) show non editable feedback.(It itself can be treated as one more HUD)
    */
    this.clickOccurred = function (type) {
        if (this.shouldHandleEvent() === false) {
            return;
        }
        this.m_liveEditEvent.fire({
            type: DW_LIVEEDIT_EVENTS.Commit
        });
        this.m_liveEditEvent.fire({
            type: DW_LIVEEDIT_EVENTS.Destroy,
			click: type
        });
        this.m_curElementUnderEdit = this.m_curClickedElement;

        if (type === DW_LIVEEDIT_EVENTS.SingleClick) {
            this.m_liveEditEvent.fire({
                type: DW_LIVEEDIT_EVENTS.SingleClick
            });
        } else if (type === DW_LIVEEDIT_EVENTS.DoubleClick) {
            this.m_liveEditEvent.fire({
                type: DW_LIVEEDIT_EVENTS.DoubleClick
            });
        }

        // If Template instance loaded we have to always check whether the click is in editable region or not.
        // this.m_editableRegionHud is initialized only for Template instance.
        this.selectionInEditableRegion = true;
        if (this.m_editableRegionHud) {
            this.selectionInEditableRegion = this.m_editableRegionHud.isClickInEditableRegion(this.m_currentEvent, type);
            //for template instance pages, we do not send selection change events from DW to live view since the selection will not be on the clicked element
            //so we update our selection from here.
            if (type === DW_LIVEEDIT_EVENTS.SingleClick && window.liveViewExtensionsObject && window.liveViewExtensionsObject.setSelectionInTemplateInstance) {
                window.liveViewExtensionsObject.setSelectionInTemplateInstance(this.m_curClickedElement);
            }
        }

        this.m_liveEditEvent.fire({
            type: DW_LIVEEDIT_EVENTS.SetElement,
            element: this.m_curElementUnderEdit,
            event: this.m_currentEvent,
            isInEditableRegion: this.selectionInEditableRegion
        });
        this.m_liveEditEvent.fire({
            type: DW_LIVEEDIT_EVENTS.Draw
        });
    };
    /*
       Global escape event handler. 
       fire an event to all HUDS
    */
    this.escapeEvent = function () {
        this.m_liveEditEvent.fire({
            type: DW_LIVEEDIT_EVENTS.Escape
        });
        this.m_liveEditEvent.fire({
            type: DW_LIVEEDIT_EVENTS.POSTEscape
        });
    };
	/*
       Function to enter Live Text editing mode with the passed node 
    */
    this.enterIntoTextEditing = function (targetNode) {
        //check whether valid element
        if (!targetNode || targetNode.nodeType !== Node.ELEMENT_NODE ||
                targetNode.tagName.toLowerCase() === DW_LIVEEDIT_CONSTANTS.ImgTagName) {
            return;
        }

        //dismiss other HUDS and try to edit
        window.CommitAndCloseHud();
        if (this.m_txtHud.enterIntoTextEditing(targetNode)) {
            window.focus();
        }
    };
    /*
      Global resize Event Handler. 
      fire an event to all HUDS
    */
    this.resizeEvent = function () {
        this.m_curClickedElement = this.m_curElementUnderEdit;

		// If Template instance loaded we have to reposition all ER HUDs and Overlays.
        if (this.m_editableRegionHud) {
            this.m_editableRegionHud.repositionAllER();
        }

		this.clickOccurred(DW_LIVEEDIT_EVENTS.SingleClick);
    };
    /*
      This is to tell controller if it needs to withdraw from handling certain clicks 
      For example: click is on our injected elements.
    */
    this.shouldHandleEvent = function () {
        if (this.m_liveEditDisabled === true) {
            return false;
        }
        if (this.isInjectedElement() === true) {
            return false;
        }
        if (this.m_txtHud && this.m_txtHud.isEventInsideTextEditContext(this.m_currentEvent)) {
			// We are here because we clicked out side the text area, but inside the text HUD overlay rectangle.
			// While blocking this event from processing further by controller, we have to make sure to position
			// IBeam, so that text selection can happen from the nearest text area.
			this.m_txtHud.positionIBeam(this.m_currentEvent);
            return false;
        }
        return true;
    };
    /*
      This is just a sanity check as inejcted elements would block events and controller will not get to this click
    */
    this.isInjectedElement = function () {
        if (this.m_curClickedElement) {
            var curElement = this.m_curClickedElement;
            
            while (curElement) {
                var curTagName = (curElement && curElement.nodeType === Node.ELEMENT_NODE) ? curElement.tagName : null;

                if (curTagName && (curTagName === "BODY" || curTagName === "HTML")) {
                    break;
                }
                if (curElement === this.m_parentContainer || curTagName === DW_LIVEEDIT_CONSTANTS.TextContainer) {
                    return true;
                }
                curElement = curElement.parentNode;
            }
            //if we get a null element, that means the passed element was not 
            //in the HTML>BODY hierarchy
            if (!curElement) {
                return true;
            }
        }
        return false;
    };

    /*
      things to be done in order to get rid of stale content
    */
    this.clear = function () {
        this.m_currentEvent = null;
        this.m_curElementUnderEdit = null;
    };
}
/*
    This is the starting point for the controller
*/
window.globalController = new Controller();
globalController.init();

// In case of Text area, we should not let users type content inside. Because when they hit backspace by delete, whole element gets deleted.
window.addEventListener("click", function (evt) {
    'use strict';
    if (globalController && !globalController.m_liveEditDisabled) {
        var elem = evt.target;
        if (elem && elem.nodeType === Node.ELEMENT_NODE) {
            if (elem.tagName === DW_LIVEEDIT_CONSTANTS.TextAreaTagName) {
                evt.target.blur();
            } else if (elem.tagName === DW_LIVEEDIT_CONSTANTS.InputTagName && elem.getAttribute("type") === 'file') {
                //do not bring up file browse dialog
                evt.preventDefault();
            } else if (dwGetShouldFollowLinks && !dwGetShouldFollowLinks()) {
                //if follow links is disabled in live view
                //get the enclosing 'a' tag if any
                while (elem && elem.tagName !== "A" && elem.tagName !== "BODY") {
                    elem = elem.parentElement;
                }
                if (elem && elem.tagName === "A") {
                    //check whether it is an anchor navigation
                    //if it is, then we should block it here,
                    //as we do not get a callback from cef for anchor navigation
                    var hrefStr = elem.getAttribute("href");
                    if (hrefStr && hrefStr.charAt(0) === '#') {
                        event.preventDefault();
                    }
                }
            }
        }
    }
}, false);


var isAnyAuxHudVisible = function () {
    'use strict';
    
    var hud, auxHuds = [DW_LIVEEDIT_CONSTANTS.DwImageHud, DW_LIVEEDIT_CONSTANTS.DwTextHud, DW_LIVEEDIT_CONSTANTS.DwSelectorHud];
    if (window.liveViewExtensionsObject) {
        for (hud in auxHuds) {
            if (auxHuds.hasOwnProperty(hud)) {
                if (window.liveViewExtensionsObject.isExtensionVisible(hud)) {
                    return true;
                }
            }
        }
    }
    return false;
};
//before double click gets fired single click gets fired. (So having at timer of 400 seconds)
var dwLiveEditClickCount = 0;
var singleClickTimer = null;

var onMouseDownHandler = function (evt) {
    'use strict';
    var messageDetails = {};

    dwLiveEditClickCount++;
    if (dwLiveEditClickCount === 1) {
        singleClickTimer = setTimeout(function () {
            dwLiveEditClickCount = 0;
            if (globalController.m_disableDWSelection || window.liveEditTemplateInstance) {
                globalController.setEvent(evt);
                globalController.clickOccurred(DW_LIVEEDIT_EVENTS.SingleClick);
            }
            //When someone clicks an empty area and image hud is up we don't get a selection change from Dw.
            //But we still need to dismiss the HUD. Doing that here.
            if (isAnyAuxHudVisible() && evt.target && evt.target.tagName !== DW_LIVEEDIT_CONSTANTS.HTMLTagName) {
                messageDetails.type = DW_EXTENSION_EVENT.HIDE_AUX_HUD;
                messageDetails.commit = true;
                window.liveViewExtensionsObject.messageToExtensions(messageDetails);
            }
        }, DW_LIVEEDIT_CONSTANTS.ThresholdForDoubleClick);
    } else if (dwLiveEditClickCount === 2) {
        clearTimeout(singleClickTimer);
        singleClickTimer = null;
        dwLiveEditClickCount = 0;
    }
};

var onDblClickHandler = function (evt) {
    'use strict';

    var shouldResetIBeam = false;
    var ignoreEval = false;

    if (globalController.m_disableDWSelection && (globalController.m_curClickedElement !== null) && (globalController.m_curClickedElement !== evt.target)) {
        // check for one case here.

        if (globalController.m_txtHud !== null) {
            if (globalController.m_txtHud.isElementInsideParent(globalController.m_curClickedElement, evt.target)) {
                ignoreEval = true;
            }
        }
    }

    if (!ignoreEval && (globalController.m_curClickedElement !== evt.target || !globalController.m_disableDWSelection)) {

        shouldResetIBeam = true;
    }

    globalController.setEvent(evt);

    globalController.clickOccurred(DW_LIVEEDIT_EVENTS.DoubleClick);

    if (shouldResetIBeam && globalController.m_disableDWSelection && (globalController.m_txtHud !== null)) {
        globalController.m_txtHud.positionIBeam(evt);
    }
};

//we will handle the mousedown event in the capture phase
//so that we will always get the event
window.addEventListener('mousedown', onMouseDownHandler, true);
window.addEventListener('dblclick', onDblClickHandler, true);

/*
when live view resizes we need to destroy all huds.
*/
window.addEventListener("resize", function () {
    'use strict';
    globalController.resizeEvent();
}, true);

/*
Support Scrolling..
*/
window.addEventListener("scroll", function () {
    'use strict';
    window.scrollVmqView(window.scrollX);
}, true);


window.addEventListener("keydown",  function (evt) {
    'use strict';
    evt = evt || window.event;

    if (evt.keyCode === DW_LIVEEDIT_CONSTANTS.EscapeKeyCode) {

        globalController.setEvent(evt);
        globalController.escapeEvent();
    } else if (evt.keyCode === DW_LIVEEDIT_CONSTANTS.TabKeyCode) {
        if (!globalController.m_txtHud.getVisibility() && window.liveViewExtensionsObject && window.liveViewExtensionsObject.isExtensionVisible(DW_LIVEEDIT_CONSTANTS.DwEshHud)) {
			// document should not tab to next anchor element on tab instead give the focus to esh and let esh know that tab key is pressed.
            if (!isAnyAuxHudVisible()) {
                var esh = document.getElementById(DW_LIVEEDIT_CONSTANTS.DwEshHud);
                if (esh) {
                    esh.focus();
                    var messageDetails = {};
                    messageDetails.type = DW_EXTENSION_EVENT.SET_SELECTION_ON_ESH;
                    window.liveViewExtensionsObject.messageToExtensions(messageDetails);
                    evt.preventDefault();
                    evt.stopPropagation();
                }
            }
        }
    }
}, true);

window.SaveDocumentPostCommitAndCloseHud = function () {
    'use strict';
    if (globalController && globalController.m_liveEditEvent) {
        globalController.m_liveEditEvent.fire({
            type: DW_LIVEEDIT_EVENTS.SaveDocument
        });
    }
    window.CommitAndCloseHud();
};


// Utility Method called from C++ layer for committing the current text editing session.
window.CommitAndCloseHud = function () {
    'use strict';
    if (globalController && globalController.m_liveEditEvent) {
        globalController.m_liveEditEvent.fire({
            type: DW_LIVEEDIT_EVENTS.Commit
        });
        globalController.m_liveEditEvent.fire({
            type: DW_LIVEEDIT_EVENTS.Destroy
        });
    }
};

window.SaveDocumentPostCommitHud = function () {
    'use strict';
    if (globalController && globalController.m_liveEditEvent) {
        globalController.m_liveEditEvent.fire({
            type: DW_LIVEEDIT_EVENTS.SaveDocument
        });
    }
    window.CommitHud();
};

//Method to refresh document after commiting hud
window.RefreshDocumentPostCommitHud = function () {
    'use strict';
    if (globalController && globalController.m_liveEditEvent) {
        globalController.m_liveEditEvent.fire({
            type: DW_LIVEEDIT_EVENTS.RefreshDocument
        });
    }
    window.CommitHud();
};

// Utility Method called from C++ layer for committing the current text editing session.
window.CommitHud = function () {
    'use strict';
    if (globalController && globalController.m_liveEditEvent) {
        globalController.m_liveEditEvent.fire({
            type: DW_LIVEEDIT_EVENTS.Commit
        });
    }
};

// this should be moved to initLiveEditInfrastcture
window.DocumentQueryCommandState = function () {
    'use strict';
    var query = "Bold";
    var queryState;
    try {
        queryState = document.queryCommandState(query);
        window.DWDocumentQueryCommandState(query, queryState);
    } catch (e1) {
        // eat the exception
    }

    query = "Italic";
    try {
        queryState = document.queryCommandState(query);
        window.DWDocumentQueryCommandState(query, queryState);
    } catch (e2) {
        // eat the exception
    }
    
    query = "underline";
    try {
        queryState = document.queryCommandState(query);
        window.DWDocumentQueryCommandState(query, queryState);
    } catch (e3) {
        // eat the exception
    }
    
    query = "strikeThrough";
    try {
        queryState = document.queryCommandState(query);
        window.DWDocumentQueryCommandState(query, queryState);
    } catch (e4) {
        // eat the exception
    }
};

//Utility function to send a ViewLostFocus event to the HUDS
window.ViewLostFocus = function () {
    'use strict';

    if (globalController && !globalController.isFileDialogUp &&  globalController.m_liveEditEvent) {
        window.writeDWLog("viewlostfocus has been called");
        globalController.m_liveEditEvent.fire({
            type: DW_LIVEEDIT_EVENTS.ViewLostFocus
        });
    }
};

//Utility function to send a ViewLostFocus event to the HUDS
window.TurnOnLiveEditMode = function () {
    'use strict';
    if (globalController) {
        window.writeDWLog("TurnOnLiveEditMode has been called");
        globalController.m_liveEditDisabled = false;
        globalController.clickOccurred(DW_LIVEEDIT_EVENTS.SingleClick);
    }
};

//Utility function to send a ViewLostFocus event to the HUDS
window.TurnOffLiveEditMode = function () {
    'use strict';
    if (globalController) {
        window.writeDWLog("TurnOffLiveEditMode has been called");
        if (window.liveViewExtensionsObject && window.liveViewExtensionsObject.dwObject) {
            if (globalController.m_txtHud && globalController.m_txtHud.getVisibility && globalController.m_txtHud.getVisibility()) {
                window.liveViewExtensionsObject.dwObject.logHeadlightsData(DW_ICE_HEADLIGHTS.OTH_ELV, DW_ICE_HEADLIGHTS.ToolingToggledInOrangeHUD);
            }

        }
        globalController.m_liveEditDisabled = true;
        window.CommitAndCloseHud();
    }
};

//Utility function to send a ViewLostFocus event to the HUDS
window.RecalcTextEditOverlayFeedback = function () {
    'use strict';
    if (globalController && globalController.m_txtHud) {
        window.writeDWLog("window.RecalcTextEditOverlayFeedback has been called");
		globalController.m_txtHud.showTextEditingFeedback();
    }
};
/*
 Function IsRightClickInsideOrangeBox - Checks whether the element at the incoming points
 is the child of dw-span. 
 
 This is invoked from DWBrowserViewWEF::OnContextMenu() to distinguish whether the right click
 was inside orange box or outside.
*/

window.IsRightClickInsideOrangeBox = function (x, y) {
    'use strict';

	if (!x || x < 0) {
		return false;
	}

	if (!y || y < 0) {
		return false;
	}

	if (globalController && globalController.m_txtHud) {
		var elementUnderMousePoint = document.elementFromPoint(x, y);
		if (elementUnderMousePoint) {
			return globalController.m_txtHud.isElementInsideParent(globalController.m_txtHud.m_elementUnderCurrentEditingSession, elementUnderMousePoint);
		}
	}

	return false;
};


//Function to reintitialize EditableRegion HUDs in case some DOM change had happened
window.reInitializeEditableRegions = function () {
    'use strict';
    if (globalController && globalController.m_editableRegionHud && globalController.m_editableRegionHud.initER) {
        //first remove the existing injected elements from doc
        if (globalController.m_editableRegionHud.getHudContainer) {
            var editableRegionsContainer = globalController.m_editableRegionHud.getHudContainer();
            if (editableRegionsContainer) {
                editableRegionsContainer.innerHTML = "";
            }
        }
        globalController.m_editableRegionHud.initER();
    }
};

/* Function to bring Element back into view if it is outside the current viewable area */
window.ScrollElementIntoViewIfNeeded = function (uniqNodeId, selectorString) {
    //get the element in live dom
    'use strict';
    var targetElement = null;
    var querySelectorString = "";
    if (uniqNodeId && uniqNodeId.length > 0) {
        //in case we have a dw node id, then use query selector to get the element with attribute
        querySelectorString = '[' + DW_LIVEEDIT_CONSTANTS.DWUniqueId + '="' + uniqNodeId + '"]';
    } else if (selectorString && selectorString.length > 0) {
        querySelectorString = selectorString;
    }
    if (querySelectorString.length > 0) {
        try {
            var elems = document.querySelectorAll(querySelectorString);
            if (elems && elems.length > 0) {
                targetElement = elems[0];
            }
        } catch (e) {
        }
    }

    if (targetElement) {
        //get where our element is
        // Calculate rect
        var range = document.createRange();
        range.selectNode(targetElement);
        var elemRect = range.getBoundingClientRect();
        if (!elemRect) {
            elemRect = targetElement.getBoundingClientRect();
        }

        //if our element is not within the viewable window, lets scroll
        if (elemRect.left > window.innerWidth || elemRect.right < 0 ||
                elemRect.top > window.innerHeight || elemRect.bottom < 0) {
            targetElement.scrollIntoView();
        }
    }
};

window.IsMarqueeSelected = function () {
    'use strict';
    if (isDwLeInitialized) {
        var sel = window.getSelection();
        if (sel && sel.rangeCount > 0) {
            var range = sel.getRangeAt(0);
            /* if range is not collapsed or range.startOffset is not matching witht range.endOffset
               then it is not ip */
            if (range && (!range.collapsed || range.startOffset !== range.endOffset)) {
                return true;
            }
        }
    }
    return false;
};
// to know whether already event listeners are added and infrastructure is ready
window.isDwLeInitialized = true;
