content: package com.wm.remusic.proxy.utils;
  
  import android.content.Context;
  import android.util.Log;
  
  import com.wm.remusic.proxy.db.CacheFileInfoDao;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.net.HttpURLConnection;
  import java.net.Socket;
  import java.net.SocketException;
  import java.net.URISyntaxException;
  
  public class RequestDealThread extends Thread {
      private static final String LOG_TAG = RequestDealThread.class.getSimpleName();
  
      Socket client;
      HttpURLConnection request;
  
      ProxyFileUtils fileUtils;
      /**
       * MediaPlayer发出的原始请求Range Start
       */
      private int originRangeStart;
      /**
       * 和本地缓存判断后，需要发出的请求Range Start
       */
      private long realRangeStart;
  
      CacheFileInfoDao cacheDao;
      Context mContext;
  
      public RequestDealThread(Context context, HttpURLConnection request, Socket client) {
          this.request = request;
          this.client = client;
          cacheDao = CacheFileInfoDao.getInstance();
          mContext = context;
      }
  
      @Override
      public void run() {
          try {
              fileUtils = ProxyFileUtils.getInstance(mContext, request.getURL().toURI(), true);
              processRequest(request, client);
          } catch (IllegalStateException e) {
              e.printStackTrace();
          } catch (IOException e) {
              e.printStackTrace();
          } catch (URISyntaxException e) {
              e.printStackTrace();
          }
      }
  
      private int getRangeStart(HttpURLConnection request) {
          String value = request.getRequestProperty(Constants.RANGE);
          //	Header rangeHeader = request.getFirstHeader(Constants.RANGE);
          if (value != null) {
              return Integer.valueOf(value.substring(value.indexOf("bytes=") + 6, value.indexOf("-")));
          }
          return 0;
      }
  
      /**
       * 伪造Response Header，发送缓存内容
       *
       * @param rangeStart 数据起始位置（如果从头开始则为0）
       * @param rangeEnd   数据截止位置（一般为缓存长度-1）
       * @param fileLength 缓存文件长度
       * @param audioCache 缓存内容
       * @throws IOException
       */
      private void sendLocalHeaderAndCache(int rangeStart, int rangeEnd, int fileLength, byte[] audioCache)
              throws IOException {
          // 返回MediaPlayer Header信息
          String httpString = HttpUtils.genResponseHeader(rangeStart, rangeEnd, fileLength);
          byte[] httpHeader = httpString.toString().getBytes();
          client.getOutputStream().write(httpHeader, 0, httpHeader.length);
          // 返回Content
          if (audioCache != null && audioCache.length > 0) {
              client.getOutputStream().write(audioCache, 0, audioCache.length);
          }
      }
  
      private void processRequest(HttpURLConnection request, Socket client) throws IllegalStateException, IOException {
          if (request == null) {
              return;
          }
  
          try {
              byte[] audioCache = null;
              // 得到MediaPlayer原始请求Range起始
              originRangeStart = getRangeStart(request);
              Log.i(LOG_TAG, "原始请求Range起始值：" + originRangeStart + " 本地缓存长度：" + fileUtils.getLength());
              // 缓存的文件大小
              int cacheFileSize = cacheDao.getFileSize(fileUtils.getFileName());
              /*
               * 如果缓存完成，无需发送请求，本地缓存返回MediaPlayer。
  			 */
              if (fileUtils.isEnable() && fileUtils.getLength() == cacheFileSize) {
                  audioCache = fileUtils.read(originRangeStart, Constants.AUDIO_BUFFER_MAX_LENGTH);
                  sendLocalHeaderAndCache(originRangeStart, cacheFileSize - 1, cacheFileSize, audioCache);
                  return;
              }
              // TODO 这里可能需要网络判断
              /*
               * 请求Range起始值和本地缓存比对。如果有缓存，得到缓存内容，修改Range。 如果没有缓存，则Range不变。
  			 */
              if (fileUtils.isEnable() && originRangeStart < fileUtils.getLength()) {
                  audioCache = fileUtils.read(originRangeStart, Constants.AUDIO_BUFFER_MAX_LENGTH);
                  Log.i(LOG_TAG, "本地已缓存长度（跳过）:" + audioCache.length);
                  // 得到需要发送请求Range Start（本地缓存结尾位置+1=缓存长度）
                  realRangeStart = fileUtils.getLength();
                  // 替换请求Header
                  request.setRequestProperty(Constants.RANGE, Constants.RANGE_PARAMS + realRangeStart + "-");
                  //	request.removeHeaders(Constants.RANGE);
                  //	request.addHeader(Constants.RANGE, Constants.RANGE_PARAMS + realRangeStart + "-");
              } else {
                  realRangeStart = originRangeStart;
              }
              // 缓存是否已经到最大值（如果缓存已经到最大值，则只需要返回缓存）
              boolean isCacheEnough = (audioCache != null && audioCache.length == Constants.AUDIO_BUFFER_MAX_LENGTH) ? true
                      : false;
  
  			/*
               * 如果缓存足够，且本地有文件长度，则直接发送缓存,不发送请求。。。。。。。。。。。。。。。。。。。
  			 * 如果缓存足够，本地没有文件长度，则发送请求，使用ResponseHeader，返回缓存,!不接收ResponseContent
  			 * 如果缓存不足，则发送请求，使用ResponseHeader，返回缓存，!返回Response Content
  			 */
              // 缓存足够&&有文件大小
              if (isCacheEnough && cacheFileSize > 0) {
                  sendLocalHeaderAndCache(originRangeStart, cacheFileSize - 1, cacheFileSize, audioCache);
              }
              // 缓存不够。或者数据库没有文件大小
              else {
                  HttpURLConnection realResponse = null;
                  /*
  				 * 返回Header和Cache
  				 */
                  // 如果数据库没有存文件大小，则获取（处理数据库没有文件大小的情况）
                  if (cacheFileSize <= 0) {
                      Log.d(LOG_TAG, "数据库未包含文件大小，发送请求");
                      realResponse = HttpUtils.send(request);
                      if (realResponse == null) {
                          return;
                      }
                      cacheFileSize = getContentLength(realResponse);
                  }
                  sendLocalHeaderAndCache(originRangeStart, cacheFileSize - 1, cacheFileSize, audioCache);
                  // 如果缓存不足，返回Response Content（处理缓存不足的情况）
                  if (realResponse == null) {
                      Log.d(LOG_TAG, "缓存不足，发送请求");
                      realResponse = HttpUtils.send(request);
                      if (realResponse == null) {
                          return;
                      }
                  }
                  Log.d(LOG_TAG, "接收ResponseContent");
                  InputStream data = realResponse.getInputStream();
                  if (!isCacheEnough) {
                      byte[] buff = new byte[1024 * 40];
                      boolean isPrint = true;
                      int fileLength = 0;
                      int readBytes;
                      while (Thread.currentThread() == MediaPlayerProxy.downloadThread
                              && (readBytes = data.read(buff, 0, buff.length)) != -1) {
                          long fileBufferLocation = fileLength + realRangeStart;
                          fileLength += readBytes;
                          long fileBufferEndLocation = fileLength + realRangeStart;
                          // 保存文件
                          if (fileUtils.getLength() == fileBufferLocation) {
                              fileUtils.write(buff, readBytes);
                          }
                          // 打印缓存大小
                          if (System.currentTimeMillis() / 1000 % 2 == 0) {
                              if (isPrint) {
                                  Log.d(LOG_TAG, "Cache Size:" + readBytes + " File Start:" + fileBufferLocation
                                          + "File End:" + fileBufferEndLocation);
                                  isPrint = false;
                              }
                          } else {
                              isPrint = true;
                          }
                          client.getOutputStream().write(buff, 0, readBytes);
                      }
                  }
              }
          } catch (SocketException e) {
              Log.i(LOG_TAG, "连接被终止", e);
          } catch (Exception e) {
              Log.e(LOG_TAG, e.getMessage(), e);
          } finally {
              client.close();
              Log.i(LOG_TAG, "代理关闭");
          }
      }
  
      /**
       * 得到Content大小
       *
       * @param response
       * @return
       */
      private int getContentLength(HttpURLConnection response) {
          int contentLength = 0;
          String range = request.getHeaderField(Constants.RANGE);
          if (range != null) {
              contentLength = Integer.valueOf(range.substring(range.indexOf("-") + 1, range.indexOf("/"))) + 1;
          } else {
              contentLength = request.getContentLength();
          }
          if (contentLength != 0) {
              cacheDao.insertOrUpdate(fileUtils.getFileName(), contentLength);
          }
          return contentLength;
      }
  }
  