@model Disco.Web.Areas.Config.Models.DocumentTemplate.ExpressionBrowserModel
@{
    Authorization.Require(Claims.Config.Show);
    
    ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Document Templates", MVC.Config.DocumentTemplate.Index(null), "Expression Browser");
    Html.BundleDeferred("~/Style/jQueryUI/dynatree");
    Html.BundleDeferred("~/ClientScripts/Modules/jQueryUI-DynaTree");
}
<div id="configurationDocumentTemplateExpressionBrowser">
    Expressions within Disco are based on the <a href="http://www.springframework.net/"
        target="_blank">Spring.NET Framework</a>. Please refer to the <a href="http://www.springframework.net/doc-latest/reference/html/expressions.html"
            target="_blank">Expression Evaluation</a> documentation.
    <h2 id="DeviceScope">
        Device Scope</h2>
    <div id="deviceScopeTree" class="expressionTree">
    </div>
    <h2 id="JobScope">
        Job Scope</h2>
    <div id="jobScopeTree" class="expressionTree">
    </div>
    <h2 id="UserScope">
        User Scope</h2>
    <div id="userScopeTree" class="expressionTree">
    </div>
    <h2 id="Variables">
        Variables
    </h2>
    <div id="variableScopeTree" class="expressionTree">
    </div>
    <h2 id="ExtensionLibraries">
        Extension Libraries</h2>
    <div id="extScopeTree" class="expressionTree">
    </div>
</div>
<script type="text/javascript">
    $(function () {
        if (!document.DiscoFunctions) {
            document.DiscoFunctions = {};
        }

        var typeLib = {};
        var loadTypeUrl = '@(Url.Action(MVC.Config.DocumentTemplate.ExpressionBrowser()))';
        var deviceScopeTree = $('#deviceScopeTree');
        var jobScopeTree = $('#jobScopeTree');
        var userScopeTree = $('#userScopeTree');
        var variableScopeTree = $('#variableScopeTree');
        var extScopeTree = $('#extScopeTree');

        var lazyLoadNode = function (node) {
            if (node.data.expressionType) {
                node.setLazyNodeStatus(DTNodeStatus_Loading);
                loadType(node, node.data.expressionType, node.data.staticDeclaredMembersOnly);
            } else {
                if (node.data.memberDescriptor) {
                    loadMember(node);
                } else {
                    node.setLazyNodeStatus(DTNodeStatus_Ok);
                }
            }
        }
        var loadMember = function (memberNode) {
            var previousUpdateMode = memberNode.tree.enableUpdate(false);
            var memberDescriptor = memberNode.data.memberDescriptor;
            // Return Type
            memberNode.addChild({ title: 'Returns: ' + memberDescriptor.ReturnType, tooltip: memberDescriptor.ReturnExpressionType, isFolder: true, expressionType: memberDescriptor.ReturnExpressionType, isLazy: true, addClass: 'object' });
            // Parameters
            var parametersNode = memberNode.addChild({ title: 'Parameters', isFolder: true, addClass: 'parameter' });
            for (var i = 0; i < memberDescriptor.Parameters.length; i++) {
                var p = memberDescriptor.Parameters[i];
                parametersNode.addChild({ title: p.Name + ' [' + p.ReturnType + ']', tooltip: p.ReturnExpressionType, addClass: 'object' });
            }
            memberNode.setLazyNodeStatus(DTNodeStatus_Ok);
            memberNode.tree.enableUpdate(previousUpdateMode);
        }
        var typeLoaded = function (parentNode, typeDescriptor) {
            var previousUpdateMode = parentNode.tree.enableUpdate(false);
            for (var i = 0; i < typeDescriptor.Members.length; i++) {
                var memberDescriptor = typeDescriptor.Members[i];
                parentNode.addChild({ title: memberDescriptor.Name, tooltip: memberDescriptor.ReturnType, isFolder: true, addClass: memberDescriptor.Kind, memberDescriptor: memberDescriptor, isLazy: true });
            }
            parentNode.setLazyNodeStatus(DTNodeStatus_Ok);
            parentNode.tree.enableUpdate(previousUpdateMode);
        }

        var loadType = function (parentNode, type, staticDeclaredMembersOnly) {
            if (typeLib[type]) {
                typeLoaded(parentNode, typeLib[type]);
            } else {
                var requestData = { type: type, StaticDeclaredMembersOnly: staticDeclaredMembersOnly };
                $.getJSON(loadTypeUrl, requestData, function (data) {
                    typeLib[type] = data;
                    typeLoaded(parentNode, data);
                });
            }
        }

        var initVariable = function (name, type) {
            variableScopeTree.dynatree('getRoot').addChild({ title: name, tooltip: type, isFolder: true, addClass: 'object', expressionType: type, isLazy: true });
        }
        var initExpressionLibrary = function (name, type) {
            extScopeTree.dynatree('getRoot').addChild({ title: name, tooltip: type, isFolder: true, addClass: 'object', expressionType: type, staticDeclaredMembersOnly: true, isLazy: true });
        }

        // Init
        deviceScopeTree.dynatree({ onLazyRead: lazyLoadNode });
        loadType(deviceScopeTree.dynatree('getRoot'), '@(Model.DeviceType)');

        jobScopeTree.dynatree({ onLazyRead: lazyLoadNode });
        loadType(jobScopeTree.dynatree('getRoot'), '@(Model.JobType)');

        userScopeTree.dynatree({ onLazyRead: lazyLoadNode });
        loadType(userScopeTree.dynatree('getRoot'), '@(Model.UserType)');

        variableScopeTree.dynatree({ onLazyRead: lazyLoadNode });
        document.DiscoFunctions.expressionInitVariable = initVariable;
        
        extScopeTree.dynatree({ onLazyRead: lazyLoadNode });
        document.DiscoFunctions.expressionInitExpressionLibrary = initExpressionLibrary;
    });
</script>
    <script type="text/javascript">
        $(function () {
@{
foreach (var variable in Model.Variables)
{
           <text>document.DiscoFunctions.expressionInitVariable('@(variable.Key)', '@variable.Value');</text>
}
foreach (var variable in Model.ExtensionLibraries)
{
           <text>document.DiscoFunctions.expressionInitExpressionLibrary('@(variable.Key)', '@variable.Value');</text>
}
}
        });
    </script>