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

Purpose:
Initialization of LiveEdit Feature and Liveview Bridging

*/
/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, maxerr: 50, evil:true */
/*global GenericLiveEditBridger,TextHudLiveViewBridger,ExtensionsBridgeFunctions,dw,DWfile,DWLE_FILEPATHS, DW_LIVEEDIT_CONSTANTS, DW_ICE_HEADLIGHTS, DW_LIVEEDIT_DEBUGGING, SelectorHudBridger, RESPONSIVE_FRAMEWORK, LVSelectionSyncBridger, DevicePreviewBridger */

function LiveEditBridgingObject(browser, documentDOM, isFluidGridDoc) {
    /*
        Member variables : browser, browser object window and dreamweaver configuration path 
    */
    'use strict';
    this.m_browser = browser;
    this.m_context = this;
    this.m_browserWindow = browser.getWindow();
    this.m_isFluidGridDoc = false;
	this.m_appConfigPath = dw.getConfigurationPath() + DWLE_FILEPATHS.AppLiveEditPath;
	this.m_appExtensionPath = this.m_appConfigPath + DWLE_FILEPATHS.ExtensionsFolder;
    this.m_liveConfigPath = dw.getUserConfigurationPath() + DWLE_FILEPATHS.UserLiveEditPath;
    this.m_extensionPath = this.m_liveConfigPath + DWLE_FILEPATHS.ExtensionsFolder;
    this.m_TextHudLEBridger = new TextHudLiveViewBridger(documentDOM);
    this.m_ExtensionsBridgeFunctions = new ExtensionsBridgeFunctions(documentDOM);
    this.m_LVSelectionSyncBridger = new LVSelectionSyncBridger(documentDOM);
    this.m_SelectorHudBridger = new SelectorHudBridger(documentDOM);
    this.m_DevicePreviewBridger = new DevicePreviewBridger(documentDOM);
    
    this.m_customBridgeFunctions = {};
	this.m_dom = documentDOM;
    if (isFluidGridDoc) {
        this.m_isFluidGridDoc = true;
    }

    // Is it DW template instance
    var theDOM = documentDOM;
    this.liveEditTemplateInstance = false;
    if (theDOM && theDOM.isTemplateInstance()) {
        this.liveEditTemplateInstance = true;
    }
}

/*
    Two major steps
    1. attachDwFunctions : attaching dw js APIS to browser, so that we can call them from browser
    2. evaluateLiveEditJS : evalJs on browser all the required scripts that we need.
    
    Note: Please keep your functions organized.
    Utility functions that can be used across all the huds should be kept at begining.
*/

/*
        This function attaches DW functionalitties to browser
*/
LiveEditBridgingObject.prototype.attachConstantsToBrowser = function () {

    'use strict';
    if (!this.m_browserWindow) {
        return;
    }
    /*
            these are the constants that are need on browser instance.
    */

    var JSEvalString = "";
    
    JSEvalString += "window.liveEditResourcePath = '" + this.m_liveConfigPath + "';\n";
    
    // all live edit resources are kept under this folder.
    // Please make sure that the string generated from read files is done properly
    JSEvalString += "window.liveEditOverlayCss = ' " + DWfile.read(this.m_liveConfigPath + DWLE_FILEPATHS.OverLayCss, "", true) + " ';\n";
    // this is css we need for the overlay (etc orange border for text editing )    

    // Set Editable Region's CSS only for template instance.
    JSEvalString += "window.liveEditTemplateInstance = false;\n";
    if (this.liveEditTemplateInstance) {
        JSEvalString += "window.liveEditTemplateInstance = true;\n";
        JSEvalString += "window.liveEditableRegionCss = ' " + DWfile.read(this.m_liveConfigPath + DWLE_FILEPATHS.EditableRegionCss, "", true) + " ';\n";
    }
    
    JSEvalString += "window.liveEditFGInstance = false;\n";
    if (this.m_isFluidGridDoc) {
        JSEvalString += "window.liveEditFGInstance = true;\n";
    }
    
    JSEvalString += "window.doctype = '';\n";
    if (this.m_dom) {
        JSEvalString += "window.doctype = '" + this.m_dom.documentType + "';\n";
    }
    
    JSEvalString += "window.extensionsResourcePath = '" + this.m_extensionPath + "';\n";
    JSEvalString += "window.appLanguage = '" + dw.getAppLanguage() + "';\n";
    
    //read extensions details
    JSEvalString += "window.extensionsDetail = JSON.parse('" + JSON.stringify(this.readExtensionsDetail()) + "');\n";

    this.m_browser.evalJS(JSEvalString);
};

/*
    populateResponsiveLayoutFramework - populate the XML which provide all information for the supported responsive framework
*/
LiveEditBridgingObject.prototype.populateResponsiveLayoutFrameworks = function () {
    "use strict";
    var folderForResource = this.m_extensionPath + RESPONSIVE_FRAMEWORK.frameworkPath,
        i = 0;
    try {
        var supportedResponsiveFrameworkInfo = DWfile.listFolder(folderForResource, "files"); // array of xml files present
		if (supportedResponsiveFrameworkInfo.length === 0) {
			// if the user configuration path for some reason is not present pick from the app configuration folder
			folderForResource = this.m_appExtensionPath + RESPONSIVE_FRAMEWORK.frameworkPath;
			supportedResponsiveFrameworkInfo = DWfile.listFolder(folderForResource, "files"); // array of xml files present
		}
        for (i = 0; i < supportedResponsiveFrameworkInfo.length; i++) {
            var filePath = folderForResource + supportedResponsiveFrameworkInfo[i];
            var fileStr = DWfile.read(filePath, "", true);
            supportedResponsiveFrameworkInfo[i] =  {
                "filepath": filePath,
                "fileStr": fileStr
            };
        }
        if (supportedResponsiveFrameworkInfo.length > 0) {
            this.m_browserWindow.supportedResponsiveFrameworkInfo = supportedResponsiveFrameworkInfo;
        }
    } catch (e) {
        this.logDebugMsg("Exception in reading the supported frameworks for Responsive Layout Extension "  + e);
    }
};

/*
    readExtensionsDetail - read deatils about the extensions to be loaded from config file and return the array of extensions
    details : path to the html file to be loaded, id of extension
*/
LiveEditBridgingObject.prototype.readExtensionsDetail = function () {
    'use strict';
    var i,
        extensionsXml = dw.getDocumentDOM(this.m_liveConfigPath + DWLE_FILEPATHS.LiveViewExtensionsListFile, false),
        liveviewExtensions = [],
        responsiveLayoutExtensionPresent = false;
    if (extensionsXml) {
        var extensions = extensionsXml.getElementsByTagName('extension');
        for (i = 0; i < extensions.length; i++) {
            var src = extensions[i].getAttribute("src");
            var id = extensions[i].getAttribute("id");
            var type = extensions[i].getAttribute("type");
            var customBridger = extensions[i].getAttribute("dwbridger");
            if (src && id) {
                var extensionEntry = {};
                extensionEntry.src = src;
                extensionEntry.id = id;
                if (id === "ResponsiveLayout") {
                    responsiveLayoutExtensionPresent = true;
                }
                if (type) {
                    extensionEntry.type = type;
                    if (type === "auxiliary") {
                        var tags = extensions[i].getAttribute("tags");
                        if (tags) {
                            extensionEntry.tags = tags;
                        }
                    }
                }
                if (customBridger) {
                    extensionEntry.customBridger = customBridger;
                }
                liveviewExtensions[i] = extensionEntry;
            }
        }
    }
    
    if (responsiveLayoutExtensionPresent) {
        this.populateResponsiveLayoutFrameworks();
    }
    this.m_liveviewExtensions = liveviewExtensions;
    return liveviewExtensions;
};

/*
    logDebugMsg - for SM layer to log messages in log file.
*/

/*
        This function attaches DW functionalitties to browser
*/
LiveEditBridgingObject.prototype.attachDwFunctions = function () {
    'use strict';
    if (!this.m_browserWindow) {
        return;
    }
    var thisContext = this,
        i = 0;

	// Initialize Log
	var writeDWLog = function (content) {
        if (DW_LIVEEDIT_DEBUGGING === true) {
            dw.logDebugMsg(content);
        }
    };
	this.logDebugMsg = writeDWLog;
	this.m_browserWindow.writeDWLog = writeDWLog;

    this.m_browserWindow.scrollVmqView = function (scrollx) {
        dw.vmq.setScrollPosVMQ(scrollx);
    };
	    
    // Load Custom Bridgers for Extensions
	for (i = 0; i < this.m_liveviewExtensions.length; i++) {
        if (this.m_liveviewExtensions[i].customBridger !== "undefined" && this.m_liveviewExtensions[i].customBridger) {
            var customBridgeName = this.m_liveviewExtensions[i].customBridger;
            var customBridger = DWfile.read(this.m_liveConfigPath + "/LiveEditBridging/" + customBridgeName + ".js", "", true);
            eval(customBridger);
            var newCustomBridger = null;
            eval("newCustomBridger  = new " + this.m_liveviewExtensions[i].customBridger + "(this.m_dom)");
            this.m_customBridgeFunctions[customBridgeName] = newCustomBridger;
            if (customBridgeName === "FluidGridBridger") {
                if (this.m_isFluidGridDoc) {
                    this.fluidGridData = newCustomBridger.getFluidStyleSheetData();
                }
            }
        }
    }

    this.m_browserWindow.DWLECallJsBridgingFunction = function (type, fnName, args, stopEditOp) {
		if (!thisContext.m_dom) {
			thisContext.logDebugMsg('ERROR - ******NO DOM or DOM is already in EDIT ******* dom = ' + thisContext.m_dom);
			return;
		}

		// if we are not in LiveView when we get the bridge call
		// We should not proceed further.
		if (thisContext.m_dom.getDesignViewMode() !== "live") {
			thisContext.logDebugMsg('ERROR - Not in Live View when recieved Bridge call = ' + fnName);
			return;
		}

		var currentBridge = null;
        try {
            if (stopEditOp === true) {
                // Mark this DOM update as Live Edit change.
                dw.setLiveEditBasedEditOpInProgress(true);
            }
			// Choose the bridge.
            if (type === DW_LIVEEDIT_CONSTANTS.HudTextEdit) {
				currentBridge = thisContext.m_TextHudLEBridger;
            } else if (type === DW_LIVEEDIT_CONSTANTS.Extensions) {
                currentBridge = thisContext.m_ExtensionsBridgeFunctions;
            } else if (type === DW_LIVEEDIT_CONSTANTS.SelectionSyncBridge) {
                currentBridge = thisContext.m_LVSelectionSyncBridger;
            } else if (type === DW_LIVEEDIT_CONSTANTS.HudSelectorHud) {
                currentBridge = thisContext.m_SelectorHudBridger;
            } else if (type === DW_LIVEEDIT_CONSTANTS.DevicePreview) {
                currentBridge = thisContext.m_DevicePreviewBridger;
            } else {
                if (type && thisContext.m_customBridgeFunctions && thisContext.m_customBridgeFunctions[type] !== "undefined") {
                    currentBridge = thisContext.m_customBridgeFunctions[type];
                }
            }

			// Call the bridge function.
			if (currentBridge) {
				currentBridge[fnName](args);
			}
		} catch (e) {
			thisContext.logDebugMsg('ERROR message : ' + e.message);
			thisContext.logDebugMsg('ERROR Info : ' + e.stack);
			if (stopEditOp) {
				dw.showInfoBarMessage('liveview/infobar/liveEditCommitFailed', 'warning', 'Editable Live View');
				if (thisContext.m_browser) {
					thisContext.m_browser.cancelLiveViewOperationState();
				}
				if (currentBridge) {
					currentBridge.rollBackFailedChanges();
				}
				if (thisContext.m_browser) {
					thisContext.m_browser.refreshPage();
				}
                dw.logEvent(DW_ICE_HEADLIGHTS.OTH_ELV, DW_ICE_HEADLIGHTS.CommitFailed);
            }
        } finally {
            // Done with Live Edit change.
            dw.setLiveEditBasedEditOpInProgress(false);
        }

    };
};

/*
	This function eval's given file onto the browser instance
*/
LiveEditBridgingObject.prototype.evaluateFileOnBrowser = function (file) {
    "use strict";
    var fileContent = DWfile.read(this.m_liveConfigPath + file, "", true);
    if (fileContent) {
        this.m_browser.evalJS(fileContent);
    }
};
/*
    this function eval's our javascript on live view browser.
*/
LiveEditBridgingObject.prototype.evaluateLiveEditJS = function () {
    'use strict';
    var fileContent = null,
        i = 0;

    if (!this.m_browser || !this.m_browserWindow) {
        return;
    }
    try {
        if (this.m_isFluidGridDoc && this.fluidGridData) {
            var JSEvalString = "";
            JSEvalString += 'var bisFluidGridDoc = true;\n';
            var fDataString = JSON.stringify(this.fluidGridData.gridData);
            JSEvalString += "var gFluidGridData = JSON.parse('" + fDataString + "');\n";
            JSEvalString += "window.gFluidGridUrl = '" + this.fluidGridData.fileUrl + "';\n";
            this.m_browser.evalJS(JSEvalString);
            this.logDebugMsg(this.fluidGridData.fileUrl);
        } else {
            this.m_browser.evalJS('var bisFluidGridDoc = false;');
        }
    } catch (e) {
        this.logDebugMsg("Exception in recognizing FluidGrid stuff " + e);
    }
    
    //Set the theme variable that will be used by liveviewextensionsobject for init.
    this.m_browser.evalJS('window.DWCurrentTheme = "' + this.m_browser.getCurrentTheme() + '";');
    
    //make our own jQuery instance for use so that it wont conflict with user's jQuery
    //we should use '$dwJQuery' instead of '$' in our jQuery plugins
    // evaluating it seperately from loop so that remaining files can use jquery
    this.evaluateFileOnBrowser("/jquery-1.11.1.min.js");
    this.m_browser.evalJS('var $dwJQuery = jQuery.noConflict(true);');
    
    // These files have tight dependency. Controller.js and initLiveViewExtensionsInfrastructure.js both need to be almost at the end ,
    // as these files try to instantiate/use objects in remaining files 
    var files = ["/jquery.i18n.properties-1.0.9.js",
                 "/Constants.js",
                 "/LiveEditEvent.js",
                 "/Extensions/dwUtility.js",
                 "/GenericHud.js",
                 "/TextEditUtils.js",
                 "/TextEdit.js",
                 "/PartialRefresh/HTMLSimpleDOM.js",
                 "/PartialRefresh/HTMLDOMDiff.js",
                 "/PartialRefresh/murmurhash3_gc.js",
                 "/PartialRefresh/RemoteFunctions.js",
                 "/PartialRefresh/HTMLTokenizer.js",
                 "/PartialRefresh/LiveUpdateTools.js",
                 // Eval Editable region javascript before Controller execution.
                 "/TemplateInstanceEditableRgn.js",
                 // Controller must be evaled at end
                 "/Controller.js",
                 // Extension Layer Includes
                 "/Extensions/ResponsiveLayout/assets/js/ResponsiveConstants.js",
                 "/Extensions/ResponsiveLayout/assets/js/FrameworkLookup.js",
                 "/Extensions/Utils/DebugUtils.js",
                 "/InitLiveViewExtensionsInfrastructure.js",
                 "/SelectionSync/SelectionSyncUtils.js",
                 "/DevicePreview/DevicePreviewLiveViewHandlers.js",
                 "/InspectMode/InspectModeUtils.js"
                ];

    for (i = 0; i < files.length; i++) {
        this.evaluateFileOnBrowser(files[i]);
    }
};
