function finalSelection() {
    const URL_REST_INTERFACE = "/catalogPortlet.web/rest/private/";
    const URL_FINAL_SELECTION_REST_INTERFACE = URL_REST_INTERFACE + "contractStructureRestService/";
    const URL_FINAL_SELECTION_SAVE = URL_FINAL_SELECTION_REST_INTERFACE + "saveAnswer/";
    const URL_FINAL_SELECTION_ANSWERS_HISTORY = URL_FINAL_SELECTION_REST_INTERFACE + "answersHistory/";
    const URL_FINAL_SELECTION_LOG2DB = URL_FINAL_SELECTION_REST_INTERFACE + "log2DB/";

    var TOKEN;
    var USER_ID;
    var RESPONSE_DATA;
    var RESPONSE_MESSAGES;

    this.init = function(token, userId) {
        TOKEN = token;
        USER_ID = userId;
    }

    this.save = function(element, answerId, organizationId, processStepFormId, questionId, tenderId) {
        const newError = new Error();
        const stackArray = newError.stack.split('\n');
        if (stackArray.length > 4) return true;

        var value = getValue(element);
        var jsonRequest = {"token": TOKEN, "userId": USER_ID, "value": value, "answerId": answerId,
                           "organizationId": organizationId, "processStepFormId": processStepFormId, "questionId": questionId,
                           "tenderId": tenderId
                          };
        var success = loadJson(URL_FINAL_SELECTION_SAVE, jsonRequest);
        if (success) {
            element.classList.add("outputValueTwoSaved");
        }
        return true;
    }

    this.loadAnswersHistory = function(element, organizationId, processStepFormId, questionId, rowIndex) {
        if (element.innerHTML == "") {
            var jsonRequest = {"token": TOKEN,
                               "organizationId": organizationId,
                               "processStepFormId": processStepFormId,
                               "questionId": questionId,
                               "rowIndex": rowIndex
                              };
            var success = loadJson(URL_FINAL_SELECTION_ANSWERS_HISTORY, jsonRequest);
            if (success) {
                showAnswerHistory(element);
            }
        } else {
            removeAnswerHistory(element);
        }
        return true;
    }

    this.loadLog2DB = function(element, serviceProviderId, tenderProjectId, tpspmId, type) {
        if (element.innerHTML == "") {
            var jsonRequest = {"token": TOKEN,
                "serviceProviderId": serviceProviderId,
                "tenderProjectId": tenderProjectId,
                "tpspmId": tpspmId,
                "type": type
            };
            var success = loadJson(URL_FINAL_SELECTION_LOG2DB, jsonRequest);
            if (success) {
                showLog2DB(element);
            }
        } else {
            removeLog2DB(element);
        }
        return true;
    }


    this.getResponseData = function() {
        return RESPONSE_DATA;
    }

    this.getResponseMessages = function() {
        return RESPONSE_MESSAGES;
    }

    // ------------------------------  private stuff starts here  ------------------------------

    var getValue = function(element)  {
        if (element.nodeName == 'SELECT' && element.type == 'select-one') {
            return element.options.item(element.selectedIndex).value;
        } else if (element.nodeName == 'INPUT' && element.type == 'checkbox') {
            return element.checked;
        } else {
            return element.value;
        }
    }

    var showAnswerHistory = function(element) {
        var htm = "";
        if (RESPONSE_DATA.result) {
            htm += "<div class='showAnswerHistoryDiv'>";
            htm += "  <table>";
            htm += "    <tr>";
            htm += "      <th>Value</th>";
            htm += "      <th>Modified By</th>";
            htm += "      <th>Modified At</th>";
            htm += "    </tr>";
            for (var i = 0; i < RESPONSE_DATA.result.length; i++) {
                var resultNode = RESPONSE_DATA.result[i];
                let value = (resultNode.value != null) ? resultNode.value : "";
                let modifiedBy = (resultNode.modifiedBy != null) ? " (ID: " + resultNode.modifiedBy + ")" : "";
                htm += "    <tr class='" + (i%2 == 0 ? "even" : "odd") + "'>";
                htm += "      <td>" + value + "</td>";
                htm += "      <td>" + resultNode.emailAddress + modifiedBy + "</td>";
                htm += "      <td>" + resultNode.modifiedAt + "</td>";
                htm += "    </tr>";
            }
            htm += "  </table>";
            htm += "</div>";
            element.innerHTML = htm;

            element.classList.remove("showAnswerHistoryButton");
            element.classList.add("closeAnswerHistoryButton");
        }
    }

    var removeAnswerHistory = function(element)  {
        element.innerHTML = "";

        element.classList.remove("closeAnswerHistoryButton");
        element.classList.add("showAnswerHistoryButton");
    }

    var showLog2DB = function(element) {
        var htm = "";
        if (RESPONSE_DATA.result) {
            htm += "<div class='showLog2DBDiv'>";
            htm += "  <table>";
            htm += "    <tr>";
            htm += "      <th>Value</th>";
            htm += "      <th>Modified By</th>";
            htm += "      <th>Modified At</th>";
            htm += "    </tr>";
            for (var i = 0; i < RESPONSE_DATA.result.length; i++) {
                var resultNode = RESPONSE_DATA.result[i];
                htm += "    <tr class='" + (i%2 == 0 ? "even" : "odd") + "'>";
                htm += "      <td>" + extractWorkflowType(resultNode.logMessage,"New Status = ", ", Removed") + "</td>";
                htm += "      <td>" + resultNode.emailAddress + " (ID: " + resultNode.userId + ")" + "</td>";
                htm += "      <td>" + resultNode.createdDate + "</td>";
                htm += "    </tr>";
            }
            htm += "  </table>";
            htm += "</div>";
            element.innerHTML = htm;

            element.classList.remove("showLog2DBButton");
            element.classList.add("closeLog2DBButton");
        }
    }

    // source: https://gist.github.com/GuillaumeJasmin/9119436
    function extractWorkflowType(logMessage, left, right) {
        var value = logMessage;
        var i = value.indexOf(left);
        if (i >= 0) {
            value = value.substring(i + left.length);
        } else {
            return '';
        }
        if (right) {
            i = value.indexOf(right);
            if (i >= 0) {
                value = value.substring(0, i);
            } else {
                return '';
            }
        }
        return value;
    }

    var removeLog2DB = function(element)  {
        element.innerHTML = "";

        element.classList.remove("closeLog2DBButton");
        element.classList.add("showLog2DBButton");
    }

    var loadJson = function(jsonUrl, jsonRequest)  {
        RESPONSE_DATA = {};
        RESPONSE_MESSAGES = {};

        var success = ajaxPut(jsonUrl, jsonRequest);
        if (success) {
            if (RESPONSE_DATA) {
                return RESPONSE_DATA;
            } else {
                success = false;
                showMessages();
            }
        }
        return success;
    }

    var showMessages = function() {
        var htm = "";
        if (RESPONSE_MESSAGES && RESPONSE_MESSAGES.length > 0) {
            htm += RESPONSE_MESSAGES[0].type + ": " + RESPONSE_MESSAGES[0].text;
        }
    }

    var ajaxPut = function(restURL, requestJson) {
        var isOk = true;
        var ajaxOptions = getAjaxPutOptions(restURL, requestJson);
        var ajaxCall = util.ajax.blocked2(ajaxOptions);
        ajaxCall.done(function(responseJson) {
            try {
                if (responseJson) {
                    TOKEN = responseJson.token;
                    RESPONSE_MESSAGES = responseJson.messages;
                    RESPONSE_DATA = responseJson.responseData;
                }
            } catch (e) {
                util.log.error("Putting HTTP request failed: " + e);
                isOk = false;
            }
        });
        return isOk;
    }

    var getAjaxPutOptions = function(restURL, requestJson) {
        var ajaxOptions = {
            data: JSON.stringify(requestJson),
            url: restURL
        };
        return ajaxOptions;
    }

}
