#pragma once
#include "LibLsp/lsp/location_type.h"


enum class lsSymbolKind : uint8_t {
        Unknown = 0,

        File = 1,
        Module = 2,
        Namespace = 3,
        Package = 4,
        Class = 5,
        Method = 6,
        Property = 7,
        Field = 8,
        Constructor = 9,
        Enum = 10,
        Interface = 11,
        Function = 12,
        Variable = 13,
        Constant = 14,
        String = 15,
        Number = 16,
        Boolean = 17,
        Array = 18,
        Object = 19,
        Key = 20,
        Null = 21,
        EnumMember = 22,
        Struct = 23,
        Event = 24,
        Operator = 25,

        // For C++, this is interpreted as "template parameter" (including
        // non-type template parameters).
        TypeParameter = 26,

        // cquery extensions
        // See also https://github.com/Microsoft/language-server-protocol/issues/344
        // for new SymbolKind clang/Index/IndexSymbol.h clang::index::SymbolKind
        TypeAlias = 252,
        Parameter = 253,
        StaticMethod = 254,
        Macro = 255,
};
MAKE_REFLECT_TYPE_PROXY(lsSymbolKind);

typedef  lsSymbolKind SymbolKind;

// A document highlight kind.
enum class lsDocumentHighlightKind {
  // A textual occurrence.
  Text = 1,
  // Read-access of a symbol, like reading a variable.
  Read = 2,
  // Write-access of a symbol, like writing to a variable.
  Write = 3
};
MAKE_REFLECT_TYPE_PROXY(lsDocumentHighlightKind);

// A document highlight is a range inside a text document which deserves
// special attention. Usually a document highlight is visualized by changing
// the background color of its range.
struct lsDocumentHighlight {
  // The range this highlight applies to.
  lsRange range;

  // The highlight kind, default is DocumentHighlightKind.Text.
  optional<lsDocumentHighlightKind>  kind ;

  MAKE_SWAP_METHOD(lsDocumentHighlight, range, kind)
};
MAKE_REFLECT_STRUCT(lsDocumentHighlight, range, kind);

struct lsSymbolInformation {

/**
 * The name of this symbol.
 */
  std::string name;
  /**
   * The kind of this symbol.
   */
  lsSymbolKind kind;
  /**
* Indicates if this symbol is deprecated.
*/
  optional<bool> deprecated;
  /**
   * The location of this symbol. The location's range is used by a tool
   * to reveal the location in the editor. If the symbol is selected in the
   * tool the range's start information is used to position the cursor. So
   * the range usually spans more then the actual symbol's name and does
   * normally include things like visibility modifiers.
   *
   * The range doesn't have to denote a node range in the sense of a abstract
   * syntax tree. It can therefore not be used to re-construct a hierarchy of
   * the symbols.
   */
  lsLocation location;
  /**
 * The name of the symbol containing this symbol. This information is for
 * user interface purposes (e.g. to render a qualifier in the user interface
 * if necessary). It can't be used to re-infer a hierarchy for the document
 * symbols.
 */
  optional<std::string>  containerName;


  MAKE_SWAP_METHOD(lsSymbolInformation, name, kind, deprecated, location, containerName);
};
MAKE_REFLECT_STRUCT(lsSymbolInformation, name, kind, deprecated, location, containerName);


struct lsDocumentSymbol {
        /**
         * The name of this symbol.
         */

        std::string name;

        /**
         * The kind of this symbol.
         */

        lsSymbolKind kind = lsSymbolKind::Unknown;

        /**
         * The range enclosing this symbol not including leading/trailing whitespace but everything else
         * like comments. This information is typically used to determine if the clients cursor is
         * inside the symbol to reveal in the symbol in the UI.
         */

        lsRange range;

        /**
         * The range that should be selected and revealed when this symbol is being picked, e.g the name of a function.
         * Must be contained by the `range`.
         */

        lsRange selectionRange;

        /**
         * More detail for this symbol, e.g the signature of a function. If not provided the
         * name is used.
         */
        optional< std::string >  detail;

        /**
         * Indicates if this symbol is deprecated.
         */
        optional< bool > deprecated;

        /**
         * Children of this symbol, e.g. properties of a class.
         */
        optional < std::vector<lsDocumentSymbol> > children;

        //internal use
        int flags=0;

        MAKE_SWAP_METHOD(lsDocumentSymbol, name, kind, range, selectionRange, detail, deprecated, children, flags);
};
MAKE_REFLECT_STRUCT(lsDocumentSymbol, name, kind, range, selectionRange, detail, deprecated, children, flags);
