/**
  * Issues a CURL request via HTTP/HTTPS and returns the response.
  *
  * @param Request $request
  * @return Response
  * @throws UG_404_NotFound
  * @throws UG_403_Forbidden
  * @throws UGException
  * @throws UG_500_ServerError
  * @throws UG_401_Unauthorized
  * @throws UG_400_BadRequest
  */
 public function request(Request $request)
 {
     $method = $request->get_method();
     $endpoint = $request->get_endpoint();
     $body = $request->get_body();
     $query_string_array = $request->get_query_string_array();
     if ($this->get_auth_type() == AUTH_APP_USER) {
         if ($token = $this->get_oauth_token()) {
             $query_string_array['access_token'] = $token;
         }
     } else {
         $query_string_array['client_id'] = $this->get_client_id();
         $query_string_array['client_secret'] = $this->get_client_secret();
     }
     foreach ($query_string_array as $key => $value) {
         $query_string_array[$key] = urlencode($value);
     }
     $query_string = http_build_query($query_string_array);
     if ($request->get_management_query()) {
         $url = $this->url . '/' . $endpoint;
     } else {
         $url = $this->url . '/' . $this->org_name . '/' . $this->app_name . '/' . $endpoint;
     }
     //append params to the path
     if ($query_string) {
         $url .= '?' . $query_string;
     }
     $curl = curl_init($url);
     if ($method == 'POST' || $method == 'PUT' || $method == 'DELETE') {
         curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
     }
     if ($method == 'POST' || $method == 'PUT') {
         $body = json_encode($body);
         curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Length: ' . strlen($body), 'Content-Type: application/json'));
         curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
     }
     curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
     curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
     curl_setopt($curl, CURLOPT_FOLLOWLOCATION, FALSE);
     curl_setopt($curl, CURLOPT_MAXREDIRS, 10);
     curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
     $response = curl_exec($curl);
     $meta = curl_getinfo($curl);
     curl_close($curl);
     $response_array = @json_decode($response, TRUE);
     $response_obj = new Response();
     $response_obj->set_curl_meta($meta);
     $response_obj->set_data($response_array);
     $response_json = $response;
     $response_obj->set_json($response_json);
     if ($meta['http_code'] != 200) {
         //there was an API error
         $error_code = $response_array['error'];
         $description = isset($response_array['error_description']) ? $response_array['error_description'] : '';
         $description = isset($response_array['exception']) ? $response_array['exception'] : $description;
         $this->write_log('Error: ' . $meta['http_code'] . ' error:' . $description);
         $response_obj->set_error(TRUE);
         $response_obj->set_error_code($error_code);
         $response_obj->set_error_message($description);
         if ($this->use_exceptions) {
             switch ($meta['http_code']) {
                 case 400:
                     throw new UG_400_BadRequest($description, $meta['http_code']);
                     break;
                 case 401:
                     throw new UG_401_Unauthorized($description, $meta['http_code']);
                     break;
                 case 403:
                     throw new UG_403_Forbidden($description, $meta['http_code']);
                     break;
                 case 404:
                     throw new UG_404_NotFound($description, $meta['http_code']);
                     break;
                 case 500:
                     throw new UG_500_ServerError($description, $meta['http_code']);
                     break;
                 default:
                     throw new UGException($description, $meta['http_code']);
                     break;
             }
         }
     } else {
         $response_obj->set_error(FALSE);
         $response_obj->set_error_message(FALSE);
     }
     return $response_obj;
 }