define([], function() {

    //Format information in the tooltips by assigning the right values under the observable values (ko) in the html.
    function SymbolTooltipCompleter(){

        var _this               = this;
        _this.accessor          = ko.observable();
        _this.returnType        = ko.observable();
        _this.returnTypeCategory= ko.observable();
        _this.categoryColor     = ko.observable();
        _this.fullTypeName      = ko.observable();
        _this.symbolName        = ko.observable();
        _this.genericParameters = ko.observable([]);
        _this.parameters        = ko.observableArray([]);
        _this.obsolete          = ko.observable();
        _this.warning           = ko.observable();
        _this.summary           = ko.observable();
        _this.examples          = ko.observable();
        _this.remarks           = ko.observable();
        _this.returns           = ko.observable();
        _this.category          = ko.observable();
        _this.overloadsCount    = ko.observable();
        _this.methodOrIndexer   = ko.observable();
        _this.overloadIndex     = ko.observable();
        _this.url               = ko.observable();

        _this.formatText = function(text){
            if(!text){return text;}
            text = text.replace(/\t/g, "&nbsp;&nbsp;&nbsp;&nbsp;"); //change tabs to non-breakable space
            text = text.replace(/\<see cref=".:(.*?)".\/\>/g, "(see \$1)"); // replace <cref='content'/> tags by (see 'content').
            text = text.replace(/(\<code.*?\>)/g, "<pre>\$1"); // replace <cref='content'/> tags by (see 'content').
            text = text.replace(/(\<\/code\>)/g, "\$1</pre>"); // replace <cref='content'/> tags by (see 'content').
            // text = text.replace(/\</g, "&lt;");
            // text = text.replace(/\>/g, "&gt;");
            text = text.replace(/(\r\n)|[\r\n]/g, "<br>");
            return text;
        };

        /** Updates content of the tooltip
         * @param {object} symbolDescriptor The symbol containing the information to put in the tooltip.
         * @param {number} overloadsCount The number of overloads for the specific Symbol Descriptor.
         * @param {number} overloadIndex The index of the overload to display (default = 0).
         * @param {string} methodOrIndexer Specifies wether the information should be displayed for an indexer or a method.
         */
        _this.updateInfo = function(symbolDescriptor, overloadsCount, overloadIndex, methodOrIndexer){
            // init all tags.
            _this.accessor("");
            _this.returnType(symbolDescriptor.TypeName || "");
            _this.fullTypeName("");
            _this.symbolName(symbolDescriptor.Name || "");
            _this.parameters([]);
            _this.summary("");
            _this.obsolete("");
            _this.warning("");
            _this.examples("");
            _this.remarks("");
            _this.returns("");
            _this.genericParameters([]);
            _this.overloadsCount(overloadsCount);
            _this.category(symbolDescriptor.Category);
            _this.methodOrIndexer(methodOrIndexer || "");
            _this.overloadIndex(overloadIndex || 0);

            // returns if does not fullfil the conditions.
            if(!symbolDescriptor) return;
            var symbolCategory = symbolDescriptor.Category;

            switch (symbolDescriptor.TypeCategory) {
            case "Enum":
                metadata = "E";
                break;
            case "Class":
                if(symbolCategory === "Namespace"){
                    // Namespaces are considered as a type by the IronPython
                    metadata = "N";
                } else if (symbolCategory === "Python")
                    metadata = "";
                else {
                    metadata = "C";
                }
                break;
            case "Struct":
                metadata = "S";
                break;
            case "Interface":
                metadata = "I";
                break;
            case "Primitive":
                metadata = "";
                break;
            default:
                metadata = "";
                break;
            }
            _this.returnTypeCategory(metadata);

            if(symbolCategory === "Variable" || symbolCategory === "Namespace" || symbolCategory === "Type" || symbolCategory === "Enum"){return;}
            var documentation  = symbolDescriptor.Documentation || null;

            if(symbolCategory === "Python" && documentation){
                _this.summary(documentation.Summary);
                return;
            }

            switch(symbolCategory){
            case "Property":
                if (symbolDescriptor.CanRead && symbolDescriptor.CanWrite)
                {
                    _this.accessor("get/set: ");
                }
                else if (symbolDescriptor.CanRead)
                {
                    _this.accessor("get: ");
                }
                else if (symbolDescriptor.CanWrite)
                {
                    _this.accessor("set: ");
                }
                break;

            case "Method":
                var parameters = [];
                for (var i=0; i < symbolDescriptor.Parameters.length; i++){
                    var parameterHelp = "";
                    var parameterType = symbolDescriptor.Parameters[i].TypeName;
                    var parameterName = symbolDescriptor.Parameters[i].Name;
                    var parameterFullTypeName = symbolDescriptor.Parameters[i].FullTypeName;
                    if(documentation && documentation.Parameters){
                        parameterHelp = documentation.Parameters[parameterName];
                    }
                    parameters.push({parameterType: parameterType, parameterName: parameterName, parameterFullTypeName: parameterFullTypeName, parameterDescription: parameterHelp});
                }
                _this.parameters(parameters);

                if(symbolDescriptor.ContainsGenericParameters){
                    _this.genericParameters(symbolDescriptor.GenericParameters);
                }
                break;
            }


            if(methodOrIndexer === "indexer" && symbolDescriptor.IndexParameters){
                var indexParameters = [];
                for (var j=0; j < symbolDescriptor.IndexParameters.length; j++){
                    var indexParameterType = symbolDescriptor.IndexParameters[j].TypeName;
                    var indexParameterFullTypeName = symbolDescriptor.IndexParameters[j].FullTypeName;
                    var indexParameterName = symbolDescriptor.IndexParameters[j].Name;
                    indexParameters.push({parameterType: indexParameterType, parameterName: indexParameterName, parameterFullTypeName: indexParameterFullTypeName});
                }
                _this.parameters(indexParameters); 
            }

            var summary = "";
            if(documentation){
                summary = documentation.Summary;
                if(summary){
                    summary = _this.formatText(summary);
                }
                _this.obsolete(documentation.ObsoleteMessage);
                var returns = _this.formatText(documentation.Returns);
                _this.returns(returns);

                _this.remarks(documentation.Remarks.map(
                    function(remark){
                        return _this.formatText(remark);
                    }
                ));

                _this.examples(documentation.Examples.map(function(example){
                    return _this.formatText(example);
                }));
            }
            _this.summary(summary);


            /**
             * Warns users that the completion may not be complete.
             * @param {object} returnType The return type of the current symbolDescriptor.
             * @returns {boolean} 
             */
            var hasMissingSuggestions = function(symbolDescriptor){
                if(symbolDescriptor.FullTypeName &&
                   symbolDescriptor.FullTypeName.indexOf("Ansys.ACT.Automation")>-1 &&
                   (symbolDescriptor.IsAbstract || symbolDescriptor.FullTypeName === "Ansys.ACT.Automation.Mechanical.DataModelObject")){
                    return true;
                }
                return false;
            };

            if(hasMissingSuggestions(symbolDescriptor)){
                _this.warning("The suggestions following this member may not be complete. Assign the command to a variable to see the full suggestions.");
            }
        };

    }


    return SymbolTooltipCompleter;
});
