content: //
  //  Copyright (c) 2014 VK.com
  //
  //  Permission is hereby granted, free of charge, to any person obtaining a copy of
  //  this software and associated documentation files (the "Software"), to deal in
  //  the Software without restriction, including without limitation the rights to
  //  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  //  the Software, and to permit persons to whom the Software is furnished to do so,
  //  subject to the following conditions:
  //
  //  The above copyright notice and this permission notice shall be included in all
  //  copies or substantial portions of the Software.
  //
  //  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  //  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  //  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  //  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  //  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  //  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  //
  
  package com.vk.sdk.api.httpClient;
  
  import com.vk.sdk.api.VKError;
  
  import org.apache.http.Header;
  import org.apache.http.HttpResponse;
  import org.apache.http.client.methods.HttpUriRequest;
  
  import java.io.ByteArrayOutputStream;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.io.UnsupportedEncodingException;
  import java.util.zip.GZIPInputStream;
  
  /**
   * Class for loading any data by HTTP request
   */
  public class VKHttpOperation extends VKAbstractOperation {
  	/**
       * Request initialized this object
       */
      private final HttpUriRequest mUriRequest;
      /**
       * Last exception throws while loading or parsing
       */
      protected Exception mLastException;
      /**
       * Bytes of HTTP response
       */
      private byte[] mResponseBytes;
  
      /**
       * Stream for output result of HTTP loading
       */
      public OutputStream outputStream;
      /**
       * Standard HTTP response
       */
      public HttpResponse response;
  
      /**
       * String representation of response
       */
      private String mResponseString;
  
      /**
       * Create new operation for loading prepared Http request. Requests may be prepared in VKHttpClient
       *
       * @param uriRequest Prepared request
       */
      public VKHttpOperation(HttpUriRequest uriRequest) {
          mUriRequest = uriRequest;
      }
  
  
      /**
       * Start current prepared http-operation for result
       */
      @Override
      public void start() {
          setState(VKOperationState.Executing);
          try {
              if (mUriRequest.isAborted()) return;
              response = VKHttpClient.getClient().execute(mUriRequest);
              InputStream inputStream = response.getEntity().getContent();
              Header contentEncoding = response.getFirstHeader("Content-Encoding");
              if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) {
                  inputStream = new GZIPInputStream(inputStream);
              }
  
              if (outputStream == null) {
                  outputStream = new ByteArrayOutputStream();
              }
  
              byte[] buffer = new byte[1024];
              int bytesRead;
              while ((bytesRead = inputStream.read(buffer)) != -1)
                  outputStream.write(buffer, 0, bytesRead);
              inputStream.close();
              outputStream.flush();
              if (outputStream instanceof ByteArrayOutputStream) {
                  mResponseBytes = ((ByteArrayOutputStream) outputStream).toByteArray();
              }
              outputStream.close();
          } catch (Exception e) {
              mLastException = e;
          }
          setState(VKOperationState.Finished);
      }
  
      @Override
      public void finish() {
          postExecution();
          super.finish();
      }
  
      /**
       * Calls before providing result, but after response loads
       * @return true is post execution succeed
       */
      protected boolean postExecution() {
          return true;
      }
  
      /**
       * Cancel current operation execution
       */
      @Override
      public void cancel() {
          VKHttpClient.cancelHttpOperation(this);
          super.cancel();
      }
  
  	/**
  	 * Returns request associated with current operation
  	 * @return URI request
  	 */
  	public HttpUriRequest getUriRequest() { return mUriRequest; }
  
      /**
       * Get operation response data
       * @return Bytes of response
       */
      public byte[] getResponseData() {
          return mResponseBytes;
      }
  
      /**
       * Get operation response string, if possible
       * @return Encoded string from response data bytes
       */
      public String getResponseString() {
          if (mResponseBytes == null)
              return null;
          if (mResponseString == null) {
              try {
                  mResponseString = new String(mResponseBytes, "UTF-8");
              } catch (UnsupportedEncodingException e) {
                  mLastException = e;
              }
          }
          return mResponseString;
      }
  
      /**
       * Generates VKError about that request fails
       * @param e Exception for error
       * @return New generated error
       */
      protected VKError generateError(Exception e) {
          VKError error;
          if (state() == VKOperationState.Canceled) {
              error = new VKError(VKError.VK_CANCELED);
          } else {
              error = new VKError(VKError.VK_REQUEST_HTTP_FAILED);
          }
          if (e != null) {
              error.errorMessage = e.getMessage();
              if (error.errorMessage == null)
                  error.errorMessage = e.toString();
              error.httpError = e;
          }
          return error;
      }
  
      /**
       * Set listener for current operation
       * @param listener Listener subclasses VKHTTPOperationCompleteListener
       */
      public void setHttpOperationListener(final VKHTTPOperationCompleteListener listener) {
          this.setCompleteListener(new VKOperationCompleteListener() {
              @Override
              public void onComplete() {
                  if (VKHttpOperation.this.state() != VKOperationState.Finished || mLastException != null) {
                      listener.onError(VKHttpOperation.this, generateError(mLastException));
                  } else {
                      listener.onComplete(VKHttpOperation.this, mResponseBytes);
                  }
              }
          });
      }
  
      /**
       * Class representing operation listener for VKHttpOperation
       */
      public static abstract class VKHTTPOperationCompleteListener extends VKAbstractCompleteListener<VKHttpOperation, byte[]>
      {
          @Override
          public void onComplete(VKHttpOperation operation, byte[] response) {
          }
  
          @Override
          public void onError(VKHttpOperation operation, VKError error) {
          }
      }
  }
  