text: "use strict";
  module.exports = Method;
  
  // extends ReflectionObject
  var ReflectionObject = require("./object");
  ((Method.prototype = Object.create(ReflectionObject.prototype)).constructor = Method).className = "Method";
  
  var util = require("./util");
  
  /**
   * Constructs a new service method instance.
   * @classdesc Reflected service method.
   * @extends ReflectionObject
   * @constructor
   * @param {string} name Method name
   * @param {string|undefined} type Method type, usually `"rpc"`
   * @param {string} requestType Request message type
   * @param {string} responseType Response message type
   * @param {boolean|Object.<string,*>} [requestStream] Whether the request is streamed
   * @param {boolean|Object.<string,*>} [responseStream] Whether the response is streamed
   * @param {Object.<string,*>} [options] Declared options
   * @param {string} [comment] The comment for this method
   */
  function Method(name, type, requestType, responseType, requestStream, responseStream, options, comment) {
  
      /* istanbul ignore next */
      if (util.isObject(requestStream)) {
          options = requestStream;
          requestStream = responseStream = undefined;
      } else if (util.isObject(responseStream)) {
          options = responseStream;
          responseStream = undefined;
      }
  
      /* istanbul ignore if */
      if (!(type === undefined || util.isString(type)))
          throw TypeError("type must be a string");
  
      /* istanbul ignore if */
      if (!util.isString(requestType))
          throw TypeError("requestType must be a string");
  
      /* istanbul ignore if */
      if (!util.isString(responseType))
          throw TypeError("responseType must be a string");
  
      ReflectionObject.call(this, name, options);
  
      /**
       * Method type.
       * @type {string}
       */
      this.type = type || "rpc"; // toJSON
  
      /**
       * Request type.
       * @type {string}
       */
      this.requestType = requestType; // toJSON, marker
  
      /**
       * Whether requests are streamed or not.
       * @type {boolean|undefined}
       */
      this.requestStream = requestStream ? true : undefined; // toJSON
  
      /**
       * Response type.
       * @type {string}
       */
      this.responseType = responseType; // toJSON
  
      /**
       * Whether responses are streamed or not.
       * @type {boolean|undefined}
       */
      this.responseStream = responseStream ? true : undefined; // toJSON
  
      /**
       * Resolved request type.
       * @type {Type|null}
       */
      this.resolvedRequestType = null;
  
      /**
       * Resolved response type.
       * @type {Type|null}
       */
      this.resolvedResponseType = null;
  
      /**
       * Comment for this method
       * @type {string|null}
       */
      this.comment = comment;
  }
  
  /**
   * Method descriptor.
   * @interface IMethod
   * @property {string} [type="rpc"] Method type
   * @property {string} requestType Request type
   * @property {string} responseType Response type
   * @property {boolean} [requestStream=false] Whether requests are streamed
   * @property {boolean} [responseStream=false] Whether responses are streamed
   * @property {Object.<string,*>} [options] Method options
   */
  
  /**
   * Constructs a method from a method descriptor.
   * @param {string} name Method name
   * @param {IMethod} json Method descriptor
   * @returns {Method} Created method
   * @throws {TypeError} If arguments are invalid
   */
  Method.fromJSON = function fromJSON(name, json) {
      return new Method(name, json.type, json.requestType, json.responseType, json.requestStream, json.responseStream, json.options, json.comment);
  };
  
  /**
   * Converts this method to a method descriptor.
   * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
   * @returns {IMethod} Method descriptor
   */
  Method.prototype.toJSON = function toJSON(toJSONOptions) {
      var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
      return util.toObject([
          "type"           , this.type !== "rpc" && /* istanbul ignore next */ this.type || undefined,
          "requestType"    , this.requestType,
          "requestStream"  , this.requestStream,
          "responseType"   , this.responseType,
          "responseStream" , this.responseStream,
          "options"        , this.options,
          "comment"        , keepComments ? this.comment : undefined
      ]);
  };
  
  /**
   * @override
   */
  Method.prototype.resolve = function resolve() {
  
      /* istanbul ignore if */
      if (this.resolved)
          return this;
  
      this.resolvedRequestType = this.parent.lookupType(this.requestType);
      this.resolvedResponseType = this.parent.lookupType(this.responseType);
  
      return ReflectionObject.prototype.resolve.call(this);
  };
  