﻿<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>data8 Lookup+ Search Form Configuration</title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" type="text/css">
    <style type="text/css">
        html, body {
            font-family: Segoe UI, Tahoma, Arial;
            font-size: 12px;
            cursor: default;
            color: #444;
        }

        input, select {
            font-family: Segoe UI, Tahoma, Arial;
            font-size: 12px;
            color: #444;
        }

        h2 {
            color: black;
            font-size: 21px;
            font-weight: bold;
        }

        h3 {
            color: #1160b7;
            font-size: 15px;
            font-weight: normal;
        }

        .mappingRow {
            padding-top: 10px; 
            border-top: 1px solid; 
            border-color: #ccc;
        }

        .row-odd {

        }

        .row-even {
            background-color: #eee;
        }

        .row-new {
            background-color: #FFB5B5;
        }

    </style>
</head>
<body>
    <div id="form" class="container-fluid">
        <h2>data<span style="color: #FF7C22">8</span> Lookup+ Search Form Configuration</h2>        
        <div id="loading" align="center">
            <img src="/_imgs/AdvFind/progress.gif" /><br />
            Loading...
        </div>
        <div id="error" style="display: none;">
            <h3>Please save the record to enable the configuration window</h3>
        </div>
        <div id="noRule" style="display: none;">
            <h3>No dedupe+ rule is specified, this lookup will default to your global search (if available)</h3>
        </div>
        <div id="titleRow" class="row" style="display: none;">
            <div class="col-sm-3">
                <h3>Display Name</h3>
            </div>
            <div class="col-sm-3">
                <h3>Display Type</h3>
            </div>
            <div class="col-sm-6">
                <h3>Maps To</h3>
            </div>
        </div>
    </div>

    <script type="text/javascript" src="ClientGlobalContext.js.aspx"></script>
    <script src="https://code.jquery.com/jquery-3.2.1.min.js" type="text/javascript"></script>
    <script src="https://use.fontawesome.com/f00756e2fe.js"></script>   
    <script type="text/javascript">
        var orgUrl = Xrm.Page.context.getClientUrl();
        var oDataEndpoint = orgUrl + "/api/data/v8.0/";

        var formFormat = {};
        var possibleFieldMappings;
        var lookupPlusId;

        $(document).ready(function () {            
            lookupPlusId = Xrm.Page.data.entity.getId();
            if (!lookupPlusId) {
                $("#loading").hide();
                $("#error").show();
                return;
            }
            var actionData = {};
            actionData.LookupPlusId = lookupPlusId;
            actionData.ConfigForm = true;

            $.ajax(oDataEndpoint + "data8_InitializeGlobalSearch",
                {
                    type: "POST",
                    contentType:"application/json; charset=utf-8",
                    dataType:"json",
                    data: JSON.stringify(actionData),
                    success: function (result) {
                        if (!result.JsonResponse) {
                            $("#loading").hide();
                            $("#noRule").show();
                            return;
                        }

                        var formattedJson = JSON.parse(result.JsonResponse);
                        formFormat.FieldMappings = formattedJson.GlobalSearchMappings;
                        possibleFieldMappings = formattedJson.UnmappedFields;
                        $("#titleRow").show();
                        $("#loading").hide();
                        RenderConfig(formFormat);
                    }
            });
        });

        function RemoveThisMapping(e) {
            var mappingDiv = $(e).parent().parent();
            var entityMapSelect = mappingDiv.find('.field-mapping-entity');
            var mappedEntity = entityMapSelect.children("option:selected").val();

            var attrMapSelect = mappingDiv.find('.field-mapping-attr');
            var mappedAttr = attrMapSelect.children("option:selected").val();

            var fieldDiv = mappingDiv.parent().parent().parent();
            var fieldMapSelect = fieldDiv.find('.field-mapping-label');
            var fieldMapped = fieldMapSelect.val();

            RemoveFieldMapping(fieldMapped, mappedEntity, mappedAttr);
        }

        function AddMapping(e) {
            if (possibleFieldMappings.length === 0) {
                alert("All fields used in Dedupe+ rules are currently mapped");
            } else {
                var mappingListDiv = $(e).parent().parent();

                var htmlRow = '<div class="row" style="margin-bottom: 10px;">';
                htmlRow = htmlRow + '<div class="form-group">';
                htmlRow = htmlRow + '<div class="col-sm-4">';
                htmlRow = htmlRow +
                    '<select class="form-control field-mapping-entity" onchange="UpdateFieldMappings(this)">';
                var i;
                for (i = 0; i < possibleFieldMappings.length; i++) {
                    htmlRow = htmlRow + '<option>' + possibleFieldMappings[i].EntityName + '</option>';
                }
                htmlRow = htmlRow + '</select>';
                htmlRow = htmlRow + '</div>';
                htmlRow = htmlRow + '<div class="col-sm-4">';
                htmlRow = htmlRow + '<select class="form-control field-mapping-attr">';
                var topRow = possibleFieldMappings[0];
                for (i = 0; i < topRow.AttributeNames.length; i++) {
                    htmlRow = htmlRow + '<option>' + topRow.AttributeNames[i] + '</option>';
                }
                htmlRow = htmlRow + '</select>';
                htmlRow = htmlRow + '</div>';
                htmlRow = htmlRow + '<div class="col-sm-4">';
                htmlRow = htmlRow + '<button type="button" class="btn btn-primary" onclick="SaveNewMapping(this)">Save</button>';
                htmlRow = htmlRow + '<button type="button" class="btn btn-primary" onclick="CancelNewMapping(this)" style="margin-left:15px;">Cancel</button>';
                htmlRow = htmlRow + '</div>';
                htmlRow = htmlRow + '</div>';
                htmlRow = htmlRow + '</div>';

                mappingListDiv.append(htmlRow);
                $(e).parent().hide();
            }
        }

        function UpdateFieldMappings(e) {
            var possibleFields = [];
            var i;
            for (i = 0; i < possibleFieldMappings.length; i++) {
                if (possibleFieldMappings[i].EntityName === $(e).val()) {
                    possibleFields = possibleFieldMappings[i].AttributeNames;
                }
            }
            
            var parentDiv = $(e).parent().parent();
            var attrMapSelect = parentDiv.find('.field-mapping-attr');
            attrMapSelect.empty();

            for (i = 0; i < possibleFields.length; i++) {
                attrMapSelect.append('<option>' + possibleFields[i] + '</option>');
            }
        }

        function RemoveFieldMapping(mappingVal, entityVal, attrVal) {
            var i;
            for (i = 0; i < formFormat.FieldMappings.length; i++) {
                var formField = formFormat.FieldMappings[i];
                if (formField.Label === mappingVal) {
                    for (var mapping in formField.MapsTo) {
                        if (formField.MapsTo.hasOwnProperty(mapping)) {
                            var data = formField.MapsTo[mapping];
                            if (data.length === 1 && Object.keys(formField.MapsTo).length === 1) {
                                formFormat.FieldMappings.splice(i, 1);
                            } else {
                                if (data.length === 1) {
                                    delete formField.MapsTo[entityVal];
                                } else {
                                    var j;
                                    for (j = 0; j < data.length; j++) {
                                        if (mapping === entityVal && data[j] === attrVal) {
                                            data.splice(j, 1);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            var matchFound = false;
            for (i = 0; i < possibleFieldMappings.length; i++) {
                if (possibleFieldMappings[i].EntityName === entityVal) {
                    matchFound = true;
                    possibleFieldMappings[i].AttributeNames.push(attrVal);
                } 
            }

            if (!matchFound) {
                var newMapping = {
                    "EntityName": entityVal,
                    "AttributeNames" : [ attrVal ]
                }
                possibleFieldMappings.push(newMapping);
            }

            RenderConfig(formFormat);
        }

        function SaveNewMapping(e) {
            var parentDiv = $(e).parent().parent();
            var entityMapSelect = parentDiv.find('.field-mapping-entity');
            var mappedEntity = entityMapSelect.children("option:selected").val();

            var attrMapSelect = parentDiv.find('.field-mapping-attr');
            var mappedAttr = attrMapSelect.children("option:selected").val();

            var fieldDiv = parentDiv.parent().parent().parent();
            var fieldMapSelect = fieldDiv.find('.field-mapping-label');

            SaveMapping(fieldMapSelect.val(), mappedEntity, mappedAttr);
        }

        function CancelNewMapping(e)
        {
            RenderConfig(formFormat);
        }

        function SaveMapping(mappingVal, entityVal, attrVal) {
            if (mappingVal === "") {
                alert("Please enter a valid field name");
                return;
            }

            var i;
            var existingField = false; 
            if (formFormat === null) {
                formFormat = [];
            };

            for (i = 0; i < formFormat.length; i++) {
                var formField = formFormat[i];
                if (formField.Label === mappingVal) {
                    existingField = true;
                    var matchFound = false;
                    for (var mapping in formField.MapsTo) {
                        if (formField.MapsTo.hasOwnProperty(mapping) && mapping === entityVal) {
                            matchFound = true;
                            formField.MapsTo[mapping].push(attrVal);
                        }
                    }
                    if (!matchFound) {
                        formField.MapsTo[entityVal] = [attrVal];

                    }
                }
            }

            if (!existingField) {
                var newFormat = {};
                newFormat.Name = guidGenerator();
                newFormat.Label = mappingVal;
                newFormat.Type = "text";
                newFormat.MapsTo = {};
                newFormat.MapsTo[entityVal] = [attrVal];

                formFormat.FieldMappings.push(newFormat);
            }

            var availableMappings = [];
            for (i = 0; i < possibleFieldMappings.length; i++) {
                if (possibleFieldMappings[i].EntityName === entityVal) {
                    var j;
                    var availableAttrs = [];
                    for (j = 0; j < possibleFieldMappings[i].AttributeNames.length; j++) {
                        if (possibleFieldMappings[i].AttributeNames[j] !== attrVal) {
                            availableAttrs.push(possibleFieldMappings[i].AttributeNames[j]);
                        }
                    }

                    if (availableAttrs.length > 0) {
                        possibleFieldMappings[i].AttributeNames = availableAttrs;
                        availableMappings.push(possibleFieldMappings[i]);
                    }
                } else {
                    availableMappings.push(possibleFieldMappings[i]);
                }
            }
            possibleFieldMappings = availableMappings;
            
            RenderConfig();
        }

        function AddFinalRow() {
            $('#form').append('<div id="saveRow" class="row mappingRow" style="margin-bottom: 10px;">' +
                '<button type="button" class="btn btn-primary save-row" style="margin-left: 15px;" onclick="AddField(this)">+ Add New Field</button>' +
                '<button type="button" class="btn btn-danger cancel-row" style="margin-left: 15px; display:none;" onclick="RenderConfig()">- Cancel New Field</button>' +
                '<span id="ValidationStatus" style="padding-left:10px;"></span><div style="margin-top: 1em" id="ValidationDetails"></div>' + 
                '</div>');
        }

        function AddField(e) {
            $(".save-row").hide();
            $(".cancel-row").show();

            var htmlRow = '<div class="row mappingRow row-new">';
            htmlRow = htmlRow + '<div class="col-sm-3">';
            htmlRow = htmlRow + '<div class="form-group">';
            htmlRow = htmlRow + '<input class="form-control field-mapping-label" type="text" placeholder="Field Name" value="">';
            htmlRow = htmlRow + ' </div>';
            htmlRow = htmlRow + '</div>';
            htmlRow = htmlRow + '<div class="col-sm-3">';
            htmlRow = htmlRow + '<div class="form-group">';
            htmlRow = htmlRow + '<select class="form-control">';
            htmlRow = htmlRow + '<option>Text</option>';
            htmlRow = htmlRow + '<option>Email</option>';
            htmlRow = htmlRow + '<option>Telephone</option>';
            htmlRow = htmlRow + '</select>';
            htmlRow = htmlRow + '</div>';
            htmlRow = htmlRow + '</div>';
            htmlRow = htmlRow + '<div class="col-sm-6 mapping-list">';
            htmlRow = htmlRow + '<div class="row manage-mapping" style="margin-bottom: 10px;">';
            htmlRow = htmlRow + '<button type="button" class="btn btn-primary" style="margin-left: 15px;" onclick="AddMapping(this)">+ Add New Mapping</button>';
            htmlRow = htmlRow + '</div>';
            htmlRow = htmlRow + '</div>';
            htmlRow = htmlRow + '</div>';

            $('#saveRow').before(htmlRow);
        };

        function RenderConfig() {
            $('.mappingRow').remove();
            SaveForm();

            if (formFormat !== null && formFormat.FieldMappings !== null) {
                var i;
                for (i = 0; i < formFormat.FieldMappings.length; i++) {
                    var formField = formFormat.FieldMappings[i];
                    var rowType = "row-odd";
                    if (i % 2 === 0) {
                        rowType = "row-even";
                    }

                    var htmlRow = '<div class="row mappingRow ' + rowType + '">';
                    htmlRow = htmlRow + '<div class="col-sm-3">';
                    htmlRow = htmlRow + '<div class="form-group">';
                    htmlRow = htmlRow +
                        '<input name = "' +
                        formField.Name +
                        '" class="form-control field-mapping-label" type="text" placeholder="' +
                        formField.Label +
                        '" value="' +
                        formField.Label +
                        '">';
                    htmlRow = htmlRow + ' </div>';
                    htmlRow = htmlRow + '</div>';
                    htmlRow = htmlRow + '<div class="col-sm-3">';
                    htmlRow = htmlRow + '<div class="form-group">';
                    htmlRow = htmlRow +
                        '<select class="form-control" data-fieldname="' +
                        formField.Name +
                        '" onchange="UpdateFieldType(this)">';
                    htmlRow = htmlRow + '<option' + (formField.Type === "Text" ? " selected" : "") + '>Text</option>';
                    htmlRow = htmlRow + '<option' + (formField.Type === "Email" ? " selected" : "") + '>Email</option>';
                    htmlRow = htmlRow +
                        '<option' +
                        (formField.Type === "Telephone" ? " selected" : "") +
                        '>Telephone</option>';
                    htmlRow = htmlRow + '</select>';
                    htmlRow = htmlRow + '</div>';
                    htmlRow = htmlRow + '</div>';
                    htmlRow = htmlRow + '<div class="col-sm-6 mapping-list">';
                    for (var mapping in formField.MapsTo) {
                        if (formField.MapsTo.hasOwnProperty(mapping)) {
                            var data = formField.MapsTo[mapping];
                            var j;
                            for (j = 0; j < data.length; j++) {
                                var dataMapping = data[j];

                                htmlRow = htmlRow + '<div class="row existing-mapping" style="margin-bottom: 10px;">';
                                htmlRow = htmlRow + '<div class="form-group">';
                                htmlRow = htmlRow + '<div class="col-sm-4">';
                                htmlRow = htmlRow +
                                    '<select class="form-control field-mapping-entity" disabled="disabled">';
                                htmlRow = htmlRow + '<option>' + mapping + '</option>';
                                htmlRow = htmlRow + '</select>';
                                htmlRow = htmlRow + '</div>';
                                htmlRow = htmlRow + '<div class="col-sm-4">';
                                htmlRow = htmlRow +
                                    '<select class="form-control field-mapping-attr" disabled="disabled">';
                                htmlRow = htmlRow + '<option>' + dataMapping + '</option>';
                                htmlRow = htmlRow + '</select>';
                                htmlRow = htmlRow + '</div>';
                                htmlRow = htmlRow + '<div class="col-sm-4">';
                                htmlRow = htmlRow +
                                    '<button type="button" class="btn btn-danger removemapping" onclick="RemoveThisMapping(this)">Remove</button>';
                                htmlRow = htmlRow + '</div>';
                                htmlRow = htmlRow + '</div>';
                                htmlRow = htmlRow + '</div>';
                            }
                        }
                    }
                    htmlRow = htmlRow + '<div class="row manage-mapping" style="margin-bottom: 10px;">';
                    htmlRow = htmlRow +
                        '<button type="button" class="btn btn-primary" style="margin-left: 15px;" onclick="AddMapping(this)">+ Add New Mapping</button>';
                    htmlRow = htmlRow + '</div>';
                    htmlRow = htmlRow + '</div>';
                    htmlRow = htmlRow + '</div>';

                    $('#form').append(htmlRow);
                }
            }
            AddFinalRow();
            
        }

        function UpdateFieldType(e) {
            var fieldName = $(e).attr("data-fieldname");
            var i;
            for (i = 0; i < formFormat.FieldMappings.length; i++) {
                var formField = formFormat.FieldMappings[i];
                if (formField.Name === fieldName) {
                    formFormat[i].Type = e[e.selectedIndex].text;
                }
            }
        }

        function guidGenerator() {
            var S4 = function() {
                return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
            };
            return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
        }

        function onlyUnique(value, index, self) {
            return self.indexOf(value) === index;
        }

        function SaveForm() {
            var entityTypes = [];
            for (i = 0; i < formFormat.FieldMappings.length; i++) {
                const thisRow = formFormat.FieldMappings[i];
                var mapsTo = Object.keys(thisRow.MapsTo); 
                for (let j = 0; j < mapsTo.length; j++) {
                    const element = mapsTo[j];
                    entityTypes.push(element);
                }               
            }
            formFormat.EntityTypes = entityTypes.filter(onlyUnique);   
            parent.Xrm.Page.getAttribute("data8_fieldmappings").setValue(JSON.stringify(formFormat));
        }

    </script>
</body>
</html>