public function call($name, $arguments, $expectedClass = null)
  {
    if (! isset($this->methods[$name])) {
      $this->client->getLogger()->error(
          'Service method unknown',
          array(
              'service' => $this->serviceName,
              'resource' => $this->resourceName,
              'method' => $name
          )
      );

      throw new Google_Exception(
          "Unknown function: " .
          "{$this->serviceName}->{$this->resourceName}->{$name}()"
      );
    }
    $method = $this->methods[$name];
    $parameters = $arguments[0];

    // postBody is a special case since it's not defined in the discovery
    // document as parameter, but we abuse the param entry for storing it.
    $postBody = null;
    if (isset($parameters['postBody'])) {
      if ($parameters['postBody'] instanceof Google_Model) {
        // In the cases the post body is an existing object, we want
        // to use the smart method to create a simple object for
        // for JSONification.
        $parameters['postBody'] = $parameters['postBody']->toSimpleObject();
      } else if (is_object($parameters['postBody'])) {
        // If the post body is another kind of object, we will try and
        // wrangle it into a sensible format.
        $parameters['postBody'] =
            $this->convertToArrayAndStripNulls($parameters['postBody']);
      }
      $postBody = (array) $parameters['postBody'];
      unset($parameters['postBody']);
    }

    // TODO: optParams here probably should have been
    // handled already - this may well be redundant code.
    if (isset($parameters['optParams'])) {
      $optParams = $parameters['optParams'];
      unset($parameters['optParams']);
      $parameters = array_merge($parameters, $optParams);
    }

    if (!isset($method['parameters'])) {
      $method['parameters'] = array();
    }

    $method['parameters'] = array_merge(
        $this->stackParameters,
        $method['parameters']
    );

    foreach ($parameters as $key => $val) {
      if ($key != 'postBody' && ! isset($method['parameters'][$key])) {
        $this->client->getLogger()->error(
            'Service parameter unknown',
            array(
                'service' => $this->serviceName,
                'resource' => $this->resourceName,
                'method' => $name,
                'parameter' => $key
            )
        );
        throw new Google_Exception("($name) unknown parameter: '$key'");
      }
    }

    foreach ($method['parameters'] as $paramName => $paramSpec) {
      if (isset($paramSpec['required']) &&
          $paramSpec['required'] &&
          ! isset($parameters[$paramName])
      ) {
        $this->client->getLogger()->error(
            'Service parameter missing',
            array(
                'service' => $this->serviceName,
                'resource' => $this->resourceName,
                'method' => $name,
                'parameter' => $paramName
            )
        );
        throw new Google_Exception("($name) missing required param: '$paramName'");
      }
      if (isset($parameters[$paramName])) {
        $value = $parameters[$paramName];
        $parameters[$paramName] = $paramSpec;
        $parameters[$paramName]['value'] = $value;
        unset($parameters[$paramName]['required']);
      } else {
        // Ensure we don't pass nulls.
        unset($parameters[$paramName]);
      }
    }

    $this->client->getLogger()->info(
        'Service Call',
        array(
            'service' => $this->serviceName,
            'resource' => $this->resourceName,
            'method' => $name,
            'arguments' => $parameters,
        )
    );

    // build the service uri
    $url = $this->createRequestUri(
        $method['path'],
        $parameters
    );

    // NOTE: because we're creating the request by hand,
    // and because the service has a rootUrl property
    // the "base_uri" of the Http Client is not accounted for
    $request = new Request(
        $method['httpMethod'],
        $url,
        ['content-type' => 'application/json'],
        $postBody ? json_encode($postBody) : ''
    );

    // support uploads
    if (isset($parameters['data'])) {
      $mimeType = isset($parameters['mimeType'])
        ? $parameters['mimeType']['value']
        : 'application/octet-stream';
      $data = $parameters['data']['value'];
      $upload = new Google_Http_MediaFileUpload($this->client, $request, $mimeType, $data);

      // pull down the modified request
      $request = $upload->getRequest();
    }

    // if this is a media type, we will return the raw response
    // rather than using an expected class
    if (isset($parameters['alt']) && $parameters['alt']['value'] == 'media') {
      $expectedClass = null;
    }

    // if the client is marked for deferring, rather than
    // execute the request, return the response
    if ($this->client->shouldDefer()) {
      // @TODO find a better way to do this
      $request = $request
        ->withHeader('X-Php-Expected-Class', $expectedClass);

      return $request;
    }

    return $this->client->execute($request, $expectedClass);
  }