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

Purpose-
This file has the implementation of Adding new selectors to an element in live view
*/

/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, maxerr: 50 */
/*global $, DwSelectorHud, AuxiliaryExtensionObject, liveViewObject, dwObject, liveExtensionsConfigPath, KEYCODES, dwExtensionController, DW_EXTENSION_EVENT */

var CONSTANTS = {
    ExtensionID: "dwSelectorHud",
    ContainerTopLeftOffset: 20
};

var HEADLIGHTS = {
	ELV_SSH: "ELV SSH",
    DEFINE_IN_PAGE: "SSH DefineInPage",
    DEFINE_IN_EXISTING: "SSH DefineInExisting",
    DEFINE_IN_NEW_FILE: "SSH DefineInNewFile",
    DEFINE_IN_EXISTING_MQ: "SSH DefineInExistingMQ"
};

var DWLE_IDS = {
    IdSource: "source",
    IdMedia: "mediaquery",
    IdLabelSource : "labelSource",
    IdLabelMQ : "labelMQ",
    IdHudContent : "hudContent"
};

var DWLE_VALUES = {
    ValNewCSS : "newCSS",
    ValNewMQ : "newMQ",
    ValInPage : "inPage",
    ValStyleTag : "<style>"
};

var DWLE_SELECTOR_CLASS = {
    Container: "wrapper",
    ContainerRight: "wrapperRight",
    ContainerLeft: "wrapperLeft",
    ContainerTop: "wrapperTop",
    ContainerTopLeft: "wrapperTopLeft",
    ContainerBottom: "wrapperBottom"
};

DwSelectorHud.prototype = new AuxiliaryExtensionObject();
DwSelectorHud.prototype.constructor = DwSelectorHud;
DwSelectorHud.prototype.baseClass = AuxiliaryExtensionObject.prototype.constructor;

function DwSelectorHud() {
    'use strict';
    //initialize variables
    this.m_hudName = CONSTANTS.HudSelectorHud;
}

DwSelectorHud.prototype.getHudTag = function () {
    'use strict';
    return "selectorIcon";
};
DwSelectorHud.prototype.toggleAuxHud = function (message) {
    'use strict';
    AuxiliaryExtensionObject.prototype.toggleAuxHud.call(this, message);
    if (!this.getVisibility()) {
        this.m_hudContentDiv.style.visibility = "hidden";
        if (this.m_hudSourceDiv.items.length) {
            this.m_hudSourceDiv.items.clear();
        }
        if (this.m_hudMediaDiv.items.length) {
            this.m_hudMediaDiv.items.clear();
        }
        
        if (parent && parent.DW_LiveEdit_ResumePartialRefreshIfSuspended) {
		    parent.DW_LiveEdit_ResumePartialRefreshIfSuspended();
	    }
    }
};

DwSelectorHud.prototype.getExtensionId = function () {
    'use strict';
    return CONSTANTS.ExtensionID;
};

DwSelectorHud.prototype.getHudContainer = function () {
    'use strict';
    return this.m_hudContainer;
};

DwSelectorHud.prototype.initialize = function () {
    'use strict';
    AuxiliaryExtensionObject.prototype.initialize.call(this);
    this.globalController = window.parent.globalController;
    
    this.m_hudSourceDiv = document.getElementById(DWLE_IDS.IdSource);
    this.m_hudMediaDiv = document.getElementById(DWLE_IDS.IdMedia);
    
    this.m_hudLabelSource = document.getElementById(DWLE_IDS.IdLabelSource);
    this.m_hudLabelMQ = document.getElementById(DWLE_IDS.IdLabelMQ);
    
    this.m_hudContentDiv = document.getElementById(DWLE_IDS.IdHudContent);
    this.cssdialogopened = false;
    this.mqdialogopened = false;
    this.stopHide = false;
    this.currentElement = null;
    this.doCommit = false;
    this.newMQAdded = false;
    this.newCSSAdded = false;
    
    this.m_hudLabelSource.innerHTML = (this.globalController.getLocalizedString('ESH_SelectorSource') + ":");
    this.m_hudLabelMQ.innerHTML = (this.globalController.getLocalizedString('ESH_SelectMQ') + ":");
};


DwSelectorHud.prototype.shouldHide = function () {
    'use strict';
    if (this.stopHide) {
        return false;
    }
    
    return true;
};

DwSelectorHud.prototype.performCommit = function () {
    'use strict';
    if (this.doCommit) {
        this.doCommit = false;
        this.commit();
    }
};

/*
function:destroyAndRestoreFocusBackToESH - destroy hud and set focus back on ESH

Arguments: None

Return : None
*/
DwSelectorHud.prototype.destroyAndRestoreFocusBackToESH = function () {
    'use strict';
    
    this.m_hudSourceDiv._hideOptions();
    this.m_hudMediaDiv._hideOptions();
    
    //hide ourself
    dwExtensionController.sendMessage({type: DW_EXTENSION_EVENT.SET_SELECTION_ON_ESH});
    this.hideAuxHud({commit: false});
    //clear browser dom modifications we have done, so that undo will go to DW document
    //and revert this operaion
    liveViewObject.clearBrowserUndoRedos();
    
    if (parent && parent.DW_LiveEdit_ResumePartialRefreshIfSuspended) {
		parent.DW_LiveEdit_ResumePartialRefreshIfSuspended();
	}
};
/*
function:escapeKeyPressed - handler for escape key press

Arguments: None

Return : None
*/
DwSelectorHud.prototype.escapeKeyPressed = function () {
    'use strict';
    this.destroyAndRestoreFocusBackToESH();
};

DwSelectorHud.prototype.populateContent = function () {
    'use strict';
    
    this.currentElement = liveViewObject.getCurrentSelectedElement();
    
    /* Main Container Div*/
    var containerEle = this.m_hudContentDiv;
    containerEle.onkeydown = function (e) {
        if (!liveViewObject.isExtensionVisible(CONSTANTS.ExtensionID)) {
            if (e.keyCode === KEYCODES.Tab) {
                var messageDetails = {};
                messageDetails.type = DW_EXTENSION_EVENT.SET_SELECTION_ON_ESH;
                dwExtensionController.sendMessage(messageDetails);
            }
        } else {
            if (e.keyCode === KEYCODES.Escape) {
                this.escapeKeyPressed();
            } else if (e.keyCode === KEYCODES.Enter) {
                this.commit();
            } else if (e.keyCode === KEYCODES.Tab) {
                if (document.activeElement.parentElement === this.m_hudSourceDiv) {
                    this.m_hudMediaDiv.focus();
                } else if (document.activeElement.parentElement === this.m_hudMediaDiv) {
                    this.m_hudSourceDiv.focus();
                }
                e.preventDefault();
                e.stopPropagation();
            }
        }
    }.bind(this);
    
    /*Css Files drop down*/
    this.createSourceDropDown();
    
    var cssSorcElement = this.m_hudSourceDiv;
    cssSorcElement.addEventListener("change", function () {
        if (this.cssdialogopened) {
            return;
        }
        if (cssSorcElement.selectedItem.value === DWLE_VALUES.ValNewCSS) {
            var argObj = {};
            argObj.callback = function (value) {
                this.stopHide = false;
                this.cssdialogopened = false;
                if (value && value.length === 2 && value[0] && value[0].length > 0) {
                    var isCSSExtension = false;
                    if (value[0].length > 3) {
                        isCSSExtension = (value[0].toLowerCase().lastIndexOf('.css') === value[0].length - 4);
                    }
                    //JsLint flags below regex as insecure
                    //This is fine in our case since we are just removing the matched content
                    var fileName = value[0].replace(/^\.*[\\\/]/, '');
                    if (fileName.length > 0 && !isCSSExtension) {
                        fileName += ".css";
                    }
                    this.createSourceDropDown(fileName);
                    this.newCSSAdded = true;
                } else {
                    this.createSourceDropDown();
                    this.createMQDropDown(-1);
                }
            }.bind(this);
			
			if (parent && parent.DW_LiveEdit_SuspendPartialRefresh) {
				parent.DW_LiveEdit_SuspendPartialRefresh();
			}
			
            this.stopHide = true;
            var messageDetails = {type: DW_EXTENSION_EVENT.IGNORE_SELECTION_CHANGE};
            messageDetails.isIgnore = true;
            dwExtensionController.sendMessage(messageDetails);
            dwObject.dwGetNewCSSDialog(argObj, false);
            this.cssdialogopened = true;
        }
        this.createMQDropDown(-1);
    }.bind(this));
    
    //cssSorcElement.focus();
    
    /* Media Query drop down*/
    var mediaElement = this.m_hudMediaDiv;
    mediaElement.addEventListener("change", function () {
        if (mediaElement.selectedItem.value === DWLE_VALUES.ValNewMQ) {
            if (this.mqdialogopened) {
                return;
            }
            var argObj = {};
            argObj.callback = function (value) {
                this.stopHide = false;
                this.mqdialogopened = false;
                if (value && value.length > 0) {
                    this.newMQAdded = true;
                    this.createMQDropDown(this.m_hudMediaDiv.items.length <= 2 ? this.m_hudMediaDiv.items.length - 1 : this.m_hudMediaDiv.items.length - 2);
                    this.doCommit = true;
                } else if (!value) {
                    this.createMQDropDown(-1);
                    // Dropdown does not resets , hence just changing and bringing back the focus, so that dropdown works just as new
                    // Bug #3819879
                    this.m_hudMediaDiv.blur();
                    this.m_hudMediaDiv.focus();
                }
            }.bind(this);
            
            this.stopHide = true;

            if (this.m_hudSourceDiv.selectedItem) {
                this.m_hudSourceDiv.selectedIndex = this.m_hudSourceDiv.selectedItem.self_index;
            }
            argObj.cssIndex = this.m_hudSourceDiv.selectedIndex;
            argObj.isStyleTagDefined = true;

            if (this.m_hudSourceDiv.selectedItem.value === DWLE_VALUES.ValInPage) {
                argObj.isStyleTagDefined = false;
                
                // Account for separator in case there is no <style> tag and there is other css source. The new style tag goes above separator.
                if (this.m_hudSourceDiv.items.length > 2) {
                    argObj.cssIndex -= 1;
                }
            }
            
			if (parent && parent.DW_LiveEdit_SuspendPartialRefresh) {
				parent.DW_LiveEdit_SuspendPartialRefresh();
			}
			
            var messageDetails = {type: DW_EXTENSION_EVENT.IGNORE_SELECTION_CHANGE};
            messageDetails.isIgnore = true;
            dwExtensionController.sendMessage(messageDetails);
            dwObject.dwGetNewMeidaQueryDialog(argObj, false);
            this.mqdialogopened = true;
        }
    }.bind(this));

    this.createMQDropDown(-1);
};

DwSelectorHud.prototype.getSelectorText = function () {
    'use strict';
    var selectorTextValue = this.eshDetails.InputText;
    if (!selectorTextValue) {
        return "";
    }
    selectorTextValue.trim();
    if (selectorTextValue[0] !== "." && selectorTextValue[0] !== "#") {
        selectorTextValue = "." + selectorTextValue;
    }
    return selectorTextValue;
};

DwSelectorHud.prototype.applyNewSelectors = function (newSelector) {
    'use strict';
    var currEle = this.currentElement; //liveViewObject.getCurrentSelectedElement();
    if (currEle && newSelector && newSelector.length > 0) {
        var selectorsArray = newSelector.split(' ');
        var idToApply = "";
        var classesToApply = [];
        var i;
        //get ID to apply and classes to apply
        //if multiple ids are provided, then we will apply the last one.
        //if selector starts with '#' then its an id, else it is a class
        for (i = 0; i < selectorsArray.length; i++) {
            var currentSelector = selectorsArray[i];
            if (currentSelector.charAt(0) === '#') {
                var currentID = currentSelector.slice(1);
                if (currentID.length > 0) {
                    idToApply = currentID;
                }
            } else {
                var currentClass = (currentSelector.charAt(0) === '.' ? currentSelector.slice(1) : currentSelector);
                if (currentClass.length > 0) {
                    classesToApply.push(currentClass);
                }
            }
        }
        
        //apply the ID
        if (idToApply.length > 0) {
            //apply to current element
            currEle.setAttribute('id', idToApply);
            //propogate to Document
            dwObject.updateDWDocumentElementAttr(currEle, 'id', idToApply);
        }
        
        //apply classes
        if (classesToApply.length > 0) {
            var curClasses = currEle.getAttribute('class');
            if (curClasses && curClasses.length > 0) {
                curClasses = curClasses + ' ' + classesToApply.join(' ');
            } else {
                curClasses = classesToApply.join(' ');
            }
                
            //apply to current element
            currEle.setAttribute('class', curClasses);
            dwObject.updateDWDocumentElementAttr(currEle, 'class', curClasses);
        }
    }
};

DwSelectorHud.prototype.positionHud = function () {
    'use strict';
    
    // by default try to position on right ---> top remains the same as element and width is elementleft + elementwidth
    this.m_hudContentDiv.style.top = (this.eshDetails.addBtnTop) + 'px';
    this.m_hudContentDiv.style.left = (this.eshDetails.addBtnRight + 10) + 'px';
    
    // right Side Check contains max horizontal position needed to place the hud on right side
    var rightSideCheck = this.eshDetails.addBtnRight + this.m_hudContentDiv.offsetWidth - window.parent.pageXOffset;
    // height Check contains max vertical position takes to place the hud at same level
    var heightCheck = this.eshDetails.addBtnBottom - window.parent.scrollY + this.m_hudContentDiv.offsetHeight;
    
    /*
     if our right side position is greater than current screen horizontal bounds or height is more than current screen vertical bound
     explore other options
     if there is no space on right or element Hud is taking more space than the elmenet width then place it in other position
    */
    this.m_hudContentDiv.removeAttribute("class");
    window.setCoralThemeForElement(this.m_hudContentDiv, this.m_currentTheme);
    this.m_hudContentDiv.classList.add(DWLE_SELECTOR_CLASS.Container);
    if (rightSideCheck > window.parent.innerWidth || heightCheck > window.parent.innerHeight) {
        if (heightCheck > window.parent.innerHeight) {
            this.m_hudContentDiv.style.top = (this.eshDetails.addBtnTop - 116) + 'px';
            
            if ((this.eshDetails.addBtnRight - this.m_hudContentDiv.offsetWidth) < 0) {
                this.m_hudContentDiv.style.left = this.eshDetails.addBtnLeft - CONSTANTS.ContainerTopLeftOffset + 'px';
                this.m_hudContentDiv.classList.add(DWLE_SELECTOR_CLASS.ContainerTopLeft);
            } else {
                this.m_hudContentDiv.style.left = (this.eshDetails.addBtnRight - this.m_hudContentDiv.offsetWidth) + 'px';
                this.m_hudContentDiv.classList.add(DWLE_SELECTOR_CLASS.ContainerTop);
            }
        } else {
            this.m_hudContentDiv.style.top = (this.eshDetails.addBtnBottom + 10) + 'px';
            this.m_hudContentDiv.style.left = (this.eshDetails.addBtnRight - this.m_hudContentDiv.offsetWidth) + 'px';
            this.m_hudContentDiv.classList.add("class", DWLE_SELECTOR_CLASS.ContainerBottom);
        }
    } else {
        this.m_hudContentDiv.classList.add("class", DWLE_SELECTOR_CLASS.ContainerRight);
    }
    
    this.m_hudContentDiv.style.visibility = "visible";
    this.m_hudSourceDiv.focus();
};

DwSelectorHud.prototype.addItem = function (component, valueId, innerHtmlText, is_disabled, is_selected, index) {
    'use strict';
    var Elem = component.items.add({
        value: valueId,
        content : {
            innerHTML: innerHtmlText,
            innerText: innerHtmlText
        },
        disabled : is_disabled,
        selected : is_selected,
        self_index : index
    });
    return Elem;
};

DwSelectorHud.prototype.createSourceDropDown = function (elementToSelect) {
    'use strict';
    var argObj = {};
    argObj.callback = function (value) {
        var srcElement = this.m_hudSourceDiv;
        if (srcElement) {
            if (srcElement.items.length) {
			    srcElement.items.clear();
		    }
        }
        var mycount = this.m_hudSourceDiv.items.length;
        if (value && srcElement) {
            var inPage = true;
            var i = 0;
            var indexToSelect = -1;
            for (i = 0; i < value.length; ++i) {
                var name = value[i].name;
                var isReadOnly = value[i].val;
                this.addItem(srcElement, name, name, isReadOnly, false, mycount++);
                if (!isReadOnly && indexToSelect < 0) {
                    indexToSelect = i;
                }
                if (name.indexOf(DWLE_VALUES.ValStyleTag) >= 0) {
                    inPage = false;
                }
                if (elementToSelect && name === elementToSelect && !isReadOnly) {
                    indexToSelect = i;
                }
            }
            var cnt = value.length;
            if (cnt > 0) {
                this.addItem(srcElement, '', "--------------------", true, false, mycount++);
                cnt++;
            }
            if (inPage) {
                var inPageStr = this.globalController.getLocalizedString('ESH_InPage');
                this.addItem(srcElement, DWLE_VALUES.ValInPage, inPageStr, false, false, mycount++);
                if (indexToSelect < 0) {
                    indexToSelect = cnt;
                }
                cnt += 1;
            }
            
            var newCssStr = this.globalController.getLocalizedString('ESH_CreateCSS');
            this.addItem(srcElement, DWLE_VALUES.ValNewCSS, newCssStr, false, false, mycount++);
            cnt += 1;
            
            //make sure that the dropdown is focused
            srcElement.blur();
            srcElement.focus();
            if (indexToSelect >= 0) {
                var selectitem = srcElement.items.getAll()[indexToSelect];
                selectitem.setAttribute('selected', 'true');
            }
            srcElement.selectedIndex = indexToSelect;
            this.createMQDropDown(-1);
        }
    }.bind(this);
    
    // Reset the selected index
    if (this.m_hudSourceDiv.items.length > 0) {
        var selectitem = this.m_hudSourceDiv.items.getAll()[0];
        selectitem.setAttribute('selected', 'true');
    }
    this.m_hudSourceDiv.selectedIndex = 0;
    
    dwObject.dwGetRelatedCSSFiles(argObj, true);
};

DwSelectorHud.prototype.createMQDropDown = function (index) {
    'use strict';
    var argObject;
    argObject = {};
    argObject.callback = function (value) {
        var mediaElement = this.m_hudMediaDiv;
        if (mediaElement) {
            if (mediaElement.items.length) {
			    mediaElement.items.clear();
		    }
        }
        var mycount = mediaElement.items.length;
        if (mediaElement) {
            var defaultMQStr = this.globalController.getLocalizedString('ESH_SelectMQ');
            var mediaElem = this.addItem(mediaElement, defaultMQStr, defaultMQStr, false, true, mycount++);
            mediaElem.style.display = 'none';
            if (value) {
                var j = 0;
                for (j = 0; j < value.length; ++j) {
                    this.addItem(mediaElement, value[j], value[j], false, false, mycount++);
                }
                var cnt = value.length;
                if (cnt > 0) {
                    this.addItem(mediaElement, '', "--------------------", true, false, mycount++);
                    cnt++;
                }
                var newMQStr = this.globalController.getLocalizedString('ESH_CreateMQ');
                this.addItem(mediaElement, DWLE_VALUES.ValNewMQ, newMQStr, false, false, mycount++);
                if (index >= 0) {
                    mediaElement.selectedIndex = index;
                    var mediaItem = mediaElement.items.getAll()[index];
                    mediaItem.setAttribute('selected', 'true');
                } else {
                    mediaElement.selectedIndex = 0;
                }
                this.performCommit();
            }
        }
    }.bind(this);
     
    if (this.m_hudSourceDiv.selectedItem) {
        this.m_hudSourceDiv.selectedIndex = this.m_hudSourceDiv.selectedItem.self_index;
    } else {
        this.m_hudSourceDiv.selectedIndex = 0;
    }
    argObject.index = this.m_hudSourceDiv.selectedIndex;
    if (argObject.index < 0) {
        argObject.index = 0;
    }
    
    var mediaElement = this.m_hudMediaDiv;
    if (mediaElement) {
		if (mediaElement.items.length) {
			mediaElement.items.clear();
		}
    }
    
    dwObject.dwGetRelatedMediaQueries(argObject, true);
};

DwSelectorHud.prototype.commit = function () {
    'use strict';
    
    if (!this.m_hudSourceDiv.selectedItem) {
        return;
    }
    var argObj = {};
    var definedInPage = false, defferedAddCssRule = false;
    if (this.m_hudSourceDiv.selectedItem) {
        this.m_hudSourceDiv.selectedIndex = this.m_hudSourceDiv.selectedItem.self_index;
    }
    if (this.m_hudMediaDiv.selectedItem) {
        this.m_hudMediaDiv.selectedIndex = this.m_hudMediaDiv.selectedItem.self_index;
    } else {
        this.m_hudMediaDiv.selectedIndex = 0;
    }
    argObj.cssIndex = this.m_hudSourceDiv.selectedIndex;
    argObj.mediaIndex = this.m_hudMediaDiv.selectedIndex - 1;
    argObj.selectorText = this.getSelectorText();
    
    argObj.callback = function (value) {
        if (value === true) {
            this.destroyAndRestoreFocusBackToESH();
        }
    }.bind(this);
    
    // Don't allow selection change handler to do anythin, once the selector is added
    // as we want to rtain editable selector hud.
    // Bug #3820837
    var messageDetails = {type: DW_EXTENSION_EVENT.IGNORE_SELECTION_CHANGE};
    messageDetails.isIgnore = true;
    dwExtensionController.sendMessage(messageDetails);
    
    if (this.m_hudSourceDiv.selectedItem.value === DWLE_VALUES.ValInPage && !this.newMQAdded) {
        dwObject.dwDefineCSSRuleInPage(argObj, false);
        definedInPage = true;
    } else {
        // Account for separator in case there is no <style> tag and there is other css source. The new style tag goes above separator.
        if (this.m_hudSourceDiv.selectedItem.value === DWLE_VALUES.ValInPage && this.m_hudSourceDiv.items.length > 2) {
            definedInPage = true;
            argObj.cssIndex -= 1;
        } else if (this.m_hudSourceDiv.selectedItem.value === DWLE_VALUES.ValStyleTag && this.m_hudSourceDiv.items.length > 2) {
            definedInPage = true;
        }
        defferedAddCssRule = true;
    }
    
    //The order of this if-else-if matters <start>
    if (definedInPage) {
        dwObject.logHeadlightsData(HEADLIGHTS.ELV_SSH, HEADLIGHTS.DEFINE_IN_PAGE);
    } else {
        if (this.newCSSAdded) {
            // if it is not defined in page, see if a new css file was added before we conclude that it is defined in an external css. 
            dwObject.logHeadlightsData(HEADLIGHTS.ELV_SSH, HEADLIGHTS.DEFINE_IN_NEW_FILE);
        } else {
            dwObject.logHeadlightsData(HEADLIGHTS.ELV_SSH, HEADLIGHTS.DEFINE_IN_EXISTING);
        }
    }
    //The order of the above if-else-if matters <END>
    
    if (argObj.mediaIndex >= 0) {
        dwObject.logHeadlightsData(HEADLIGHTS.ELV_SSH, HEADLIGHTS.DEFINE_IN_EXISTING_MQ);
    }
    
    this.newMQAdded = false;
    this.newCSSAdded = false;
    
    if (defferedAddCssRule) {
        //Add Css rule results in page reload at times; so differing for the above headlights loging to happen.
        dwObject.dwAddCssRule(argObj, false);
    }
};


var initDwSelectorHud = function () {
    'use strict';
    window.DwSelectorHudObj = new DwSelectorHud();
    window.DwSelectorHudObj.initialize();
};
