var DOC_COOKIES_NAME = "docCookies";

// Declare functions used to save and retrieve the scrolling state
// These functions are defined in scrollHandler.js
var saveScroll, restoreScroll, addScrollListener;

// Get basic info about this .js file for usage later on.
// 'document.currentScript' is supported by all major recent browsers to provide the info we need
// but Internet Explorer 11 and older versions do not. To workaround this, we implement
// the following function.
var currentScript = document.currentScript || (function() {
    var scripts = document.getElementsByTagName('script');
    return scripts[scripts.length - 1];
})();

/**
 * Finds and returns the product name if it is contained within the path.
 * @return the name of the product installed according to the path
 */
function getProductFromPath() {
    //"Inspect" has to precede "Avizo" since its full name is "AvizoForIndustrialInspection":
    //searching for "Avizo" within the string would also find the "Inspect" version
    var products = ["PerGeos", "Inspect", "Avizo", "Amira"];

    for (var currProd in products)
        if (currentScript.src.search(products[currProd]) != -1)
            return products[currProd];

    return null;
}

/**
 * Allows getting a standard cookie
 * @param cname is the name of the cookie to get.
 * @return the value of the cookie.
 */
function getCookieImpl(cname)
{
    if (localStorage[cname] == undefined)
        return "null"

    // The following line is equivalent to "var c = ca[i].trim()" (for browser that do not support this method)
    var c = localStorage[cname].replace(/^\s+|\s+$/gm,'');

    return decodeURI(c);
}

/**
 * Allows getting the value of a element stored into "docCookies".
 * @param cname is the name of the element to get.
 * @return the value of the element.
 */
function getDocCookie(cname)
{
    // Get the cookie named "docCookies"
    var docCookiesStr = getCookieImpl(DOC_COOKIES_NAME);

    // Transform the string into a map.
    var docCookieMap = JSON.parse(docCookiesStr);

    // Get the value of the key cname
    if (cname in docCookieMap)
        return docCookieMap[cname];
    else
        return "null";
}

/**
 * Allows setting a standard cookie
 * @param cname is the name of the cookie to set.
 * @param cvalue is the value of the cookie to set.
 */
function setCookieImpl(cname,cvalue)
{
    localStorage[cname] = encodeURI(cvalue);
}

/**
 * Allows getting, if the browser is compatible, the value of a element stored into "docCookies".
 * Else, return "Avizo" if we ask for "isProduct", "StandardEdition" if we ask for "isEdition"
 * and "1" in all other cases.
 * @param cname is the name of the element to get.
 * @return the value of the element.
 */
function getCookie(cname)
{
    // Case of Avizo/Amira browser: we retrieve the element normally
    if ( getCookieImpl("browser") != "null" )
    {
        return getDocCookie(cname);
    }

    // Case of external browser
    else
    {
        // Try to set a cookie. If it doesn't work, the browser is not compatible. In incompatible
        // browser case, "isProduct" will be set to "Avizo" and "isEdition" to "Avizo3DEdition".
        setCookieImpl("testBrowserCompat", "ok");

        if ( getCookieImpl("testBrowserCompat") == "ok" )
        {
            // Compatible browser. We try to get the element "cname" normally.
            return getDocCookie(cname);
        }
        else
        {
            // Incompatible browser. "isProduct"="Avizo" and "isEdition=Avizo3DEdition".
            if ( cname == "isProduct")
                return "Avizo";
            else if ( cname == "isEdition")
                return "Avizo3DEdition";
            else
                return "1";   // All license tests will succeed.
        }
    }
}

/**
 * Allows adding a element into "docCookies".
 * @param cname is the name of the element to get.
 * @param cvalue is the value of the element to set.
 */
function setCookie(cname,cvalue)
{
    // Get the cookie named "docCookies"
    var docCookiesStr = getCookieImpl(DOC_COOKIES_NAME);

    // If there is no cookie "docCookies", we create a new one, with only {cname:cvalue}
    if ( docCookiesStr == "null" )
    {
        var docCookieMap = {};
        docCookieMap[cname] = cvalue;
        setCookieImpl(DOC_COOKIES_NAME, JSON.stringify(docCookieMap));
    }

    // Else, we parse the current value (transform it into a map), add the pair cname=cvalue,
    // re-transform it into a string, and we set the value of "docCookies".
    else
    {
        var docCookieMap = JSON.parse(docCookiesStr);
        docCookieMap[cname] = cvalue
        var newDocCookiesStr = JSON.stringify(docCookieMap);
        setCookieImpl(DOC_COOKIES_NAME, JSON.stringify(docCookieMap));
    }
}

/**
 * Set all the license cookies, defined in commonLicenses, avizo(FEI)Licenses and amira(FEI)Licenses.
 * @param product is the name of the product ("Avizo" or "Amira").
 * @param edition is the name of the edition).
 */
function setAllLicenseCookie( product, edition )
{
    // Common Licenses between Amira and Avizo
    for ( i = 0 ; i < commonLicenses.length ; i++ )
        setCookie( commonLicenses[i], "1" );

    // Reset all licenses
    // Avizo-only Licenses
    for ( i = 0 ; i < avizoLicenses.length ; i++ )
        setCookie( avizoLicenses[i], "0" );

    // Amira-only Licenses
    for ( i = 0 ; i < amiraLicenses.length ; i++ )
        setCookie( amiraLicenses[i], "0" );

    // AvizoFEI-only Licenses
    for ( i = 0 ; i < avizoFEILicenses.length ; i++ )
        setCookie( avizoFEILicenses[i], "0" );

    // AmiraFEI-only Licenses
    for ( i = 0 ; i < amiraFEILicenses.length ; i++ )
        setCookie( amiraFEILicenses[i], "0" );

    // PerGeos-only Licenses
    for ( i = 0 ; i < pergeosLicenses.length ; i++ )
        setCookie(pergeosLicenses[i], "0");

    // Enable licenses only for active product
    var isAvizo = ( product === "Avizo" );
    var isAmira = ( product === "Amira" );
    var isPergeos = ( product === "PerGeos" );

    // Avizo-only Licenses
    if ( isAvizo )
    {
        for ( i = 0 ; i < avizoLicenses.length ; i++ )
            setCookie( avizoLicenses[i], "1" );
    }

    // Amira-only Licenses
    if ( isAmira )
    {
        for ( i = 0 ; i < amiraLicenses.length ; i++ )
            setCookie( amiraLicenses[i], "1" );
    }

    // PerGeos-only Licenses
    if ( isPergeos )
    {
        for ( i = 0 ; i < pergeosLicenses.length ; i++ )
            setCookie(pergeosLicenses[i], "1");
    }

    // Set also the custom cookies
    setCustomLicenseCookie();
}

/**
 * Set the custom license cookie using the value of the other cookies
 */
function setCustomLicenseCookie()
{
    for ( i = 0 ; i < customLicenses.length ; i++ )
    {
        // Get the description of the custom cookie given in config.js
        var customCookieStr = customLicenses[i][1];

        // Evaluate the value of the custom cookie
        var reg=new RegExp( "([a-zA-Z0-9]*License)", "g" );
        customCookieStr = customCookieStr.replace( reg, "Number(getCookie(\"$1\"))" );
        var customCookieValue = eval(customCookieStr);

        // Set the custom cookie
        setCookie( customLicenses[i][0], customCookieValue );
    }
}

/**
 * Set, in "docCookies", the value of isAmiraAvizo.
 * @param product is the name of the product. If the product is Avizo or Amira, the coockie is set to "true".
 */
function setIsAmiraAvizoCookie( product )
{
    if ( product == "Amira" || product == "Avizo" )
        setCookie("isAmiraAvizo","true");
    else
        setCookie("isAmiraAvizo","false");
}

/**
 * Display the combo box, which allows selecting the product/edition.
 */
function displayComboBox()
{
    var browser=getCookieImpl("browser");

    if ( browser == "null" )
    {
        // Try to set a cookie. If it doesn't work, the browser is not compatible and a
        // message is displayed.
        setCookieImpl("testBrowserCompat", "ok");
        if ( getCookieImpl("testBrowserCompat") != "ok" )
        {
            document.write("<b><p>Your browser is not compatible with this documentation.\
            Avizo 3D documentation will be displayed.</b>\
            <p>Known compatible browsers are: Internet Explorer, Mozilla Firefox, Google Chrome and Microsoft Edge");
            return;
        }

        // Else, a combo-box is created to let the user select the edition.
        document.write("Please choose your product: <div style=\"text-align:left;\">");
        document.write("<form name=\"editioncombo\">");
        document.write("<select name=\"edition\" size=\"1\" onChange=\"updateDoc()\">");
        document.write("<option value=\"Avizo/Avizo3DEdition\">Avizo</option>");
        document.write("<option value=\"Avizo/InspectEdition\">Avizo for Industrial Inspection</option>");
        document.write("<option value=\"Amira/Amira\">Amira</option>");
        document.write("<option value=\"PerGeos\">PerGeos</option>");

        document.write("</select>");
        document.write("</form>");
        document.write("</div>");

        // Set the combo box value using the last one if available, otherwise the default one
        var shortcut=document.editioncombo;
        var selectedProduct = getCookieImpl("selectedProduct");
        if (selectedProduct != "null")
            shortcut.edition.selectedIndex=selectedProduct;
        else {
            switch(getProductFromPath()) {
                case "Avizo":
                    shortcut.edition.selectedIndex=0;
                    break;
                case "Inspect":
                    shortcut.edition.selectedIndex=1;
                    break;
                case "Amira":
                    shortcut.edition.selectedIndex=2;
                    break;
                case "PerGeos":
                    shortcut.edition.selectedIndex=3;
                    break;
                default:
                    shortcut.edition.selectedIndex=0;
                    break;
            }

            updateDoc();
        }
    }
}

/**
 * Called if the value of the combo box has changed. Update the cookies.
 */
function updateDoc()
{
    // Save the index of the combo box
    var shortcut=document.editioncombo
    setCookieImpl("selectedProduct",shortcut.edition.selectedIndex);

    // Get the pair "product/edition" of the combo box, and set the cookies
    var comboValue = shortcut.edition.options[shortcut.edition.selectedIndex].value;
    var comboValuePair = comboValue.split('/');
    setCookie("isProduct",comboValuePair[0]);
    setCookie("isEdition",comboValuePair[1]);

    // Set all the license cookie for the given product and edition
    setAllLicenseCookie(comboValuePair[0],comboValuePair[1]);
    // Set isAmiraAvizo cookie
    setIsAmiraAvizoCookie(comboValuePair[0]);

    // Reload the page.
    location.reload();
}

/**
 * Displays the list of licenses using checkboxes, which allows changing the value of license cookies.
 */
function displayLicenseList()
{
    // "highlightEnabled" cookie will be used to know in which state the highlighting is.
    // When we navigate through the documentation, the state of the highlight
    // won't change/won't be re-initialized.
    if ( getCookieImpl("highlightEnabled") == "null" )
        setCookieImpl( "highlightEnabled", "true" );

    // Create the doc review banner.
    // It will contain the lists of licenses, the buttons, the product combo boxes, etc.
    document.write( "<div id=\"docReviewBanner\" class=\"docReviewTools\">" );
    // In doc review mode, the product combobox is included in the doc review banner.
    // In standard mode, the combo box is on the top of each page.
    displayComboBox();

    document.write( "<div id=\"listOfLicenses\" class=\"docReviewLicensesContainer\">" );

    var product = getCookie( "isProduct" );
    var allProductLicenses;

    // List all licenses available for a product
    if ( product == "Avizo" )
    {
        allProductLicenses = commonLicenses.concat( avizoLicenses );
        allProductLicenses = allProductLicenses.concat( avizoFEILicenses );
    }
    if ( product == "Amira" )
    {
        allProductLicenses = commonLicenses.concat( amiraLicenses );
        allProductLicenses = allProductLicenses.concat( amiraFEILicenses );
    }
    if ( product == "PerGeos" )
    {
        allProductLicenses = commonLicenses.concat( pergeosLicenses );
    }

    // Sort the licenses alphabetically
    allProductLicenses.sort();

    //Create a checkbox for each licenses
    for ( i = 0 ; i < allProductLicenses.length ; i++ )
    {
        var val = ( getCookie(allProductLicenses[i]) == "1" ) ? "checked" : "";
        document.write( "<input type=\"checkbox\" id=\"" + allProductLicenses[i] + "\" onclick=\"updateLicenses()\" " + val + "/>" + allProductLicenses[i] + "<br />" );
    }

    document.write( "</div>" );

    // Create "Select All" and "Deselect All" buttons
    document.write( "<p><input type=\"button\" name=\"selectButton\" value=\"Select All\" onclick=\"selectAll(true)\">" );
    document.write( "<input type=\"button\" name=\"deselectButton\" value=\"Deselect All\" onclick=\"selectAll(false)\">" );
    document.write( "<input type=\"button\" name=\"highlightButton\" id=\"highlightButton\" value=\"Disable Highlighting\" onclick=\"toggleHighlight()\">" );

    // Add the button "Edit" and "Rebuild" if the browser is IE.
    // execNotepad() and buildPage() is defined in fastEditionIE.js file
    if ( navigator.appName.indexOf("Internet Explorer") != -1 || navigator.appName.indexOf("Netscape") != -1 )
    {
        document.write( "<input type=\"button\" name=\"editFile\" id=\"editFile\" value=\"Edit File\" onclick=\"execNotepad()\">" );
        document.write( "<input type=\"button\" name=\"rebuildFile\" id=\"rebuildFile\" value=\"Rebuild\" onclick=\"buildPage()\">" );
    }

    // Field used by displayUsedCookies() method.
    document.write( "<div id=\"requiredCookieList\">\n<b>Content filtered by:</b> <!-- tobereplaced --></div>" );
    document.write( "</div>\n" );

    // Get the vertical offset to apply to the whole page
    // Without this offset, the banner will hide the documentation content.
    var offsetHeight = document.getElementById( "docReviewBanner" ).offsetHeight + 40;
    var verticalSpace = "<p style=\"margin-top:" + offsetHeight + "px\">\n";
    document.write( verticalSpace );

    // Add on scroll event listener for the list of checkboxes
    addScrollListener( document.getElementById("listOfLicenses"), saveScroll );
}

/**
 * Allows selecting or deselecting all the licenses (without update)
 * This method is called when "Select All" or "Deselect All" is hit.
 * @param isSelected is the new state of the checkboxes. isSelected=true: everything is selected.
 */
function selectAll( isSelected )
{
    var product = getCookie( "isProduct" );
    var allProductLicenses;

    // List all licenses available for the product
    if ( product == "Avizo" )
    {
        allProductLicenses = commonLicenses.concat( avizoLicenses );
        allProductLicenses = allProductLicenses.concat( avizoFEILicenses );
    }
    if ( product == "Amira" )
    {
        allProductLicenses = commonLicenses.concat( amiraLicenses );
        allProductLicenses = allProductLicenses.concat( amiraFEILicenses );
    }
    if ( product == "PerGeos" )
    {
        allProductLicenses = commonLicenses.concat( pergeosLicenses );
    }

    // Change the state of all checkboxes
    for ( i = 0 ; i < allProductLicenses.length ; i++ )
        document.getElementById(allProductLicenses[i]).checked = isSelected;

    // Then update the license cookies
    updateLicenses();
}


/**
 * Updates the license cookies depending on the checkboxes values.
 * This method is called when "Update" is hit.
 */
function updateLicenses()
{
    var product = getCookie( "isProduct" );

    // Set the value of the common licenses cookies
    for ( i = 0 ; i < commonLicenses.length ; i++ )
    {
        var licValue = ( document.getElementById(commonLicenses[i]).checked == true ) ? "1" : "0";
        setCookie( commonLicenses[i], licValue );
    }

    var allAvizoLicenses = avizoLicenses.concat( avizoFEILicenses );
    var allAmiraLicenses = amiraLicenses.concat( amiraFEILicenses );
    var useAvizoLicenses = ( product == "Avizo" );
    var useAmiraLicenses = ( product == "Amira" );
    var usePerGeosLicenses = ( product == "PerGeos" );

    // Set the value of Avizo's licenses cookies
    if ( useAvizoLicenses )
    {
        for ( i = 0 ; i < allAvizoLicenses.length ; i++ )
        {
            var licValue = ( useAvizoLicenses && document.getElementById(allAvizoLicenses[i]).checked == true ) ? "1" : "0";
            setCookie( allAvizoLicenses[i], licValue );
        }
    }

    // Set the value of Amira's licenses cookies
    if ( useAmiraLicenses )
    {
        for ( i = 0 ; i < allAmiraLicenses.length ; i++ )
        {
            var licValue = ( useAmiraLicenses && document.getElementById(allAmiraLicenses[i]).checked == true ) ? "1" : "0";
            setCookie( allAmiraLicenses[i], licValue );
        }
    }

    // Set the value of PerGeos's licenses cookies
    if ( usePerGeosLicenses )
    {
        for ( i = 0 ; i < pergeosLicenses.length ; i++ )
        {
            var licValue = ( usePerGeosLicenses && document.getElementById(pergeosLicenses[i]).checked == true ) ? "1" : "0";
            setCookie( pergeosLicenses[i], licValue );
        }
    }

    // Reload the page and set the custom cookies.
    location.reload();
    setCustomLicenseCookie();
}

/**
 * Search all results of a regular expression applied on a content.
 * @param regularExpression is the RegExp to use.
 * @param content is the content in which the search will be done.
 * @return an array with the list of the results.
 */
function getRegExpResult( regularExpression , content)
{
    var resultList = new Array();
    var hasResult = regularExpression.test( content );

    while ( hasResult )
    {
        var matchResult = regularExpression.exec( content );

        // Add the result to resultList.
        if ( resultList.indexOf(matchResult[1]) == -1 )
            resultList.push( matchResult[1] );

        // Remove the matched line from the content, to avoid re-matching it again
        content = content.replace( matchResult[0], "" );
        hasResult = regularExpression.test( content );
    }

    return resultList;
}

/**
 * Parse the current HTML page and search for the cookies needed.
 * The list of cookies required is written below the list of checkboxes.
 */
function displayUsedCookies()
{
    // Get the content of the current page
    var pageContent = document.body.innerHTML;
    var content = pageContent;

    // cookieRegExp matches "if (cookiename00 == "<ProductName>")" or "if (cookiename00 == "<EditionName>)""
    var cookieRegExp = new RegExp( "if \\\(cookiename[0-9]* == \"([a-zA-Z0-9]*)\"\\\)" );

    // Search for all cookiename00 == "<cookieValue>" and save all <cookieValue>
    var productEditionCookies = getRegExpResult( cookieRegExp , content );

    // licenseCookieRegExp matches licensename00=getCookie("<LicenseCookie>")
    var licenseCookieRegExp = new RegExp( "licensename[0-9]*=getCookie\\\(\"([a-zA-Z0-9]*License)\"\\\);" );

    // Search for all licensename00=getCookie("<LicenseCookie>") and save all <LicenseCookie>
    var licenseCookies = getRegExpResult( licenseCookieRegExp , content );

    // Create a string, displaying all product/edition/licenses cookies
    // used by the current page.
    var cookiesList = "";
    var productListColor = "#006633";  // The list of product/edition cookies will be written in green
    var licenseListColor = "#000099";  // The list of license cookies will be written in blue
    var otherListColor = "#990000";    // the other cookies will be written in red

    // List of product/edition cookie used
    if ( productEditionCookies.length )
    {
        cookiesList += "(Products) ";
        for ( i = 0 ; i < productEditionCookies.length ; i++ )
        {
            var highlightColor = pkgColorMap["default"];
            if ( productEditionCookies[i] in pkgColorMap )
                highlightColor = pkgColorMap[productEditionCookies[i]];

            cookiesList += "<font color=\"" + productListColor + "\">" + "<span style=\"background:" + highlightColor + "\">" + productEditionCookies[i] + "</span></font>";
            if ( i < productEditionCookies.length - 1) cookiesList += ", "; else cookiesList += ". ";
        }
    }
    // List of license cookies used
    if ( licenseCookies.length )
    {
        cookiesList += "(Licenses) ";
        for ( i = 0 ; i < licenseCookies.length ; i++ )
        {
            var highlightColor = pkgColorMap["default"];
            if ( licenseCookies[i] in pkgColorMap )
                highlightColor = pkgColorMap[licenseCookies[i]];

            cookiesList += "<font color=\"" + licenseListColor + "\">" + "<span style=\"background:" + highlightColor + "\">" + licenseCookies[i] + "</span></font>";
            if ( i < licenseCookies.length - 1 ) cookiesList += ", "; else cookiesList += ". ";
        }
    }

    // Display this string below the list of comboboxes
    if ( cookiesList == "" )
        cookiesList = "None"

    var str = document.getElementById( "requiredCookieList" ).innerHTML;
    document.getElementById( "requiredCookieList" ).innerHTML = str.replace( "<!-- tobereplaced -->", cookiesList );

    // Update also the state of the highlighting
    var highlightEnabled = getCookieImpl("highlightEnabled");

    // Highlight that should be disabled at the reload of the page:
    // need to call setHighlight
    if ( highlightEnabled == "false" )
        setHighlight( false );
}

/**
 * Change the state of highlighting. Used when the highlight toogle button is clicked.
 * @param enableHighlight is the new state of the highlighting. If enableHighlight=true,
 * the highlight will be added. Else, it will be removed.
 */
function setHighlight( enableHighlight )
{
    // Case 1: the content is highlighten and we want to remove the highlight.
    if ( !enableHighlight )
    {
        // Regular expression corresponding to the tag used to begin an highlight region
        var divRegExp = new RegExp( "<div ((?!>).)*id=(\\\\)?\\\"highlight(\\\\)?\\\"((?!>).)*>" );
        var bodyValue = document.body.innerHTML;

        // Remove the <div id="highlight"> tags
        var hasResult = divRegExp.test( bodyValue );
        while ( hasResult )
        {
            var matchResult = divRegExp.exec( bodyValue );
            bodyValue = bodyValue.replace( matchResult[0], "" );
            hasResult = divRegExp.test( bodyValue );
        }

        // Remove also the </div id="highlight"> tags
        while ( bodyValue.indexOf("</div id=\\\"highlight\\\">") != -1 )
        {
            bodyValue = bodyValue.replace( "</div id=\\\"highlight\\\">", "" );
        }

        document.body.innerHTML = bodyValue;

        // The value of the product combobox changes when we set
        // manually document.body.innerHTML.
        // We need to re-set it to its correct value.
        if ( getCookieImpl("browser") == "null" )
        {
            var shortcut=document.editioncombo;
            var selectedProduct = getCookieImpl("selectedProduct");
            if (selectedProduct != "null")
                shortcut.edition.selectedIndex=selectedProduct;
        }

        // Change the value of highlightEnabled cookie, since the highlight state has changed
        setCookieImpl( "highlightEnabled", "false" );
        document.getElementById("highlightButton").value="Enable Highlight";

        // The page has been manually modified. We need to set the scroll state.
        restoreScroll();
    }
    else
    {
        // Change the value of highlightEnabled cookie
        setCookieImpl( "highlightEnabled", "true" );

        // Then reload the page. By default, the text will be highlighten.
        location.reload();
    }
}

/**
 * Toggles the state of the highlighting, using the value of "highlightEnabled" cookies.
 */
function toggleHighlight()
{
    var isHighlightEnabled = ( getCookieImpl( "highlightEnabled" ) == "true" )
    setHighlight( !isHighlightEnabled ) ;
}
