JSEditor = function()
{
    var assetRoot = ""

    function setAssetRoot(_assetRoot)
    {
        assetRoot = _assetRoot;
    }	

    function displayJSEditor(value, callback)
    {
        // We load these when we need them— no sense in loading more javascript and css if we're never using the editor.
        head.js(
            assetRoot + "css/codemirror.css",
            assetRoot + "css/codemirror-ambiance.css",
            assetRoot + "js/codemirror.js",
            function(){

                var exampleText = "// Example: Convert temp from C to F and truncate to 2 decimal places.\n// return (datasources[\"MyDatasource\"].sensor.tempInF * 1.8 + 32).toFixed(2);";

                // If value is empty, go ahead and suggest something
                if(!value)
                {
                    value = exampleText;
                }

                var codeWindow = $('<div class="code-window"></div>');
                var codeMirrorWrapper = $('<div class="code-mirror-wrapper"></div>');
                var codeWindowFooter = $('<div class="code-window-footer"></div>');
                var codeWindowHeader = $('<div class="code-window-header cm-s-ambiance">This javascript will be re-evaluated any time a datasource referenced here is updated, and the value you <code><span class="cm-keyword">return</span></code> will be displayed in the widget. You can assume this javascript is wrapped in a function of the form <code><span class="cm-keyword">function</span>(<span class="cm-def">datasources</span>)</code> where datasources is a collection of javascript objects (keyed by their name) corresponding to the most current data in a datasource.</div>');

                codeWindow.append([codeWindowHeader, codeMirrorWrapper, codeWindowFooter]);

                $("body").append(codeWindow);

                var codeMirrorEditor = CodeMirror(codeMirrorWrapper.get(0),
                    {
                        value: value,
                        mode:  "javascript",
                        theme: "ambiance",
                        indentUnit: 4,
                        lineNumbers: true,
                        matchBrackets: true,
                        autoCloseBrackets: true
                    }
                );

                var closeButton = $('<span id="dialog-cancel" class="text-button">Close</span>').click(function(){
                    if(callback)
                    {
                        var newValue = codeMirrorEditor.getValue();

                        if(newValue === exampleText)
                        {
                            newValue = "";
                        }

                        callback(newValue);
                        codeWindow.remove();
                    }
                });

                codeWindowFooter.append(closeButton);
        });
    }

    // Public API
    return {
        displayJSEditor : function(value, callback)
        {
            displayJSEditor(value, callback);
        },
        setAssetRoot : function(assetRoot)
        {
            setAssetRoot(assetRoot)
        }
    }
}
