private void update(final MessageSnapshot snapshot) {
    setStatus(snapshot.getStatus());
    this.isLargeFile = snapshot.isLargeFile();

    switch (snapshot.getStatus()) {
      case FileDownloadStatus.pending:
        this.soFarBytes = snapshot.getLargeSofarBytes();
        this.totalBytes = snapshot.getLargeTotalBytes();

        // notify
        getMessenger().notifyPending(snapshot);
        break;
      case FileDownloadStatus.started:
        // notify
        getMessenger().notifyStarted(snapshot);
        break;
      case FileDownloadStatus.connected:
        this.totalBytes = snapshot.getLargeTotalBytes();
        this.resuming = snapshot.isResuming();
        this.etag = snapshot.getEtag();

        markStartDownload();

        // notify
        getMessenger().notifyConnected(snapshot);
        break;
      case FileDownloadStatus.progress:
        this.soFarBytes = snapshot.getLargeSofarBytes();
        calcSpeed(snapshot.getLargeSofarBytes());

        // notify
        getMessenger().notifyProgress(snapshot);
        break;
        //            case FileDownloadStatus.blockComplete:
        /** Handled by {@link FileDownloadList#removeByCompleted(BaseDownloadTask)} */
        //                break;
      case FileDownloadStatus.retry:
        this.soFarBytes = snapshot.getLargeSofarBytes();
        this.ex = snapshot.getThrowable();
        _setRetryingTimes(snapshot.getRetryingTimes());

        resetSpeed();
        // notify
        getMessenger().notifyRetry(snapshot);
        break;
      case FileDownloadStatus.error:
        this.ex = snapshot.getThrowable();
        this.soFarBytes = snapshot.getLargeSofarBytes();

        calcAverageSpeed(this.soFarBytes);
        // to FileDownloadList
        FileDownloadList.getImpl().remove(this, snapshot);

        break;
      case FileDownloadStatus.paused:
        /** Handled by {@link #pause()} */
        break;
      case FileDownloadStatus.completed:
        this.isReusedOldFile = snapshot.isReusedDownloadedFile();
        if (snapshot.isReusedDownloadedFile()) {
          this.etag = snapshot.getEtag();
        }
        // only carry total data back
        this.soFarBytes = snapshot.getLargeTotalBytes();
        this.totalBytes = snapshot.getLargeTotalBytes();

        calcAverageSpeed(this.soFarBytes);
        // to FileDownloadList
        FileDownloadList.getImpl().remove(this, snapshot);

        break;
      case FileDownloadStatus.warn:
        resetSpeed();
        final int count = FileDownloadList.getImpl().count(getId());
        if (count <= 1) {
          // 1. this progress kill by sys and relive,
          // for add at least one listener
          // or 2. pre downloading task has already completed/error/paused
          // request status
          final int currentStatus = _getStatusFromServer(downloadId);
          FileDownloadLog.w(
              this,
              "warn, but no listener to receive progress, " + "switch to pending %d %d",
              getId(),
              currentStatus);

          //noinspection StatementWithEmptyBody
          if (FileDownloadStatus.isIng(currentStatus)) {
            // ing, has callbacks
            // keep and wait callback

            setStatus(FileDownloadStatus.pending);
            this.totalBytes = snapshot.getLargeTotalBytes();
            this.soFarBytes = snapshot.getLargeSofarBytes();

            markStartDownload();

            ((MessageSnapshot.IWarnMessageSnapshot) snapshot).turnToPending();
            getMessenger().notifyPending(snapshot);
            break;
          } else {
            // already over and no callback
          }
        }

        // to FileDownloadList
        FileDownloadList.getImpl().remove(this, snapshot);
        break;
    }
  }
  /** @param transfer In order to optimize some of the data in some cases is not back */
  void update(final FileDownloadTransferModel transfer) {
    switch (transfer.getStatus()) {
      case FileDownloadStatus.pending:
        if (getStatus() == FileDownloadStatus.pending) {
          FileDownloadLog.w(this, "already pending %d", getDownloadId());
          break;
        }
        this.setStatus(transfer.getStatus());
        this.setSoFarBytes(transfer.getSoFarBytes());
        this.setTotalBytes(transfer.getTotalBytes());

        // notify
        getDriver().notifyPending();
        break;
      case FileDownloadStatus.connected:
        if (getStatus() == FileDownloadStatus.connected) {
          FileDownloadLog.w(this, "already connected %d", getDownloadId());
          break;
        }

        setStatus(transfer.getStatus());
        setTotalBytes(transfer.getTotalBytes());
        setSoFarBytes(transfer.getSoFarBytes());
        this.isContinue = transfer.isContinue();
        this.etag = transfer.getEtag();

        // notify
        getDriver().notifyConnected();
        break;
      case FileDownloadStatus.progress:
        if (getStatus() == FileDownloadStatus.progress
            && transfer.getSoFarBytes() == getLargeFileSoFarBytes()) {
          FileDownloadLog.w(this, "%d unused values! by process callback", getDownloadId());
          break;
        }

        setStatus(transfer.getStatus());
        setSoFarBytes(transfer.getSoFarBytes());

        // notify
        getDriver().notifyProgress();
        break;
      case FileDownloadStatus.blockComplete:
        /** Handled by {@link FileDownloadList#removeByCompleted(BaseDownloadTask)} */
        break;
      case FileDownloadStatus.retry:
        if (getStatus() == FileDownloadStatus.retry
            && getRetryingTimes() == transfer.getRetryingTimes()) {
          FileDownloadLog.w(
              this,
              "%d already retry! %d %d %s",
              getDownloadId(),
              getRetryingTimes(),
              getAutoRetryTimes(),
              transfer.getThrowable());
          break;
        }

        setStatus(transfer.getStatus());
        setSoFarBytes(transfer.getSoFarBytes());
        setEx(transfer.getThrowable());
        _setRetryingTimes(transfer.getRetryingTimes());

        // notify
        getDriver().notifyRetry();
        break;
      case FileDownloadStatus.error:
        if (getStatus() == FileDownloadStatus.error) {
          FileDownloadLog.w(
              this,
              "%d already err(%s) , callback by other status same transfer",
              getDownloadId(),
              getEx());
          break;
        }

        setStatus(transfer.getStatus());
        setEx(transfer.getThrowable());
        setSoFarBytes(transfer.getSoFarBytes());

        // to FileDownloadList
        FileDownloadList.getImpl().removeByError(this);

        break;
      case FileDownloadStatus.paused:
        /** Handled by {@link #pause()} */
        break;
      case FileDownloadStatus.completed:
        if (getStatus() == FileDownloadStatus.completed) {
          FileDownloadLog.w(
              this,
              "%d already completed , callback by process with same transfer",
              getDownloadId());
          break;
        }

        this.isReusedOldFile = transfer.isUseOldFile();
        setStatus(transfer.getStatus());
        // only carry total data back
        setSoFarBytes(transfer.getTotalBytes());
        setTotalBytes(transfer.getTotalBytes());

        // to FileDownloadList
        FileDownloadList.getImpl().removeByCompleted(this);

        break;
      case FileDownloadStatus.warn:
        if (getStatus() == FileDownloadStatus.warn) {
          FileDownloadLog.w(
              this, "%d already warn , callback by process with same transfer", getDownloadId());
          break;
        }

        final int count = FileDownloadList.getImpl().count(getDownloadId());
        if (count <= 1) {
          // 1. this progress kill by sys and relive,
          // for add at least one listener
          // or 2. pre downloading task has already completed/error/paused
          // request status
          final int currentStatus = _getStatusFromServer(downloadId);
          FileDownloadLog.w(
              this,
              "warn, but no listener to receive progress, " + "switch to pending %d %d",
              getDownloadId(),
              currentStatus);

          if (FileDownloadStatus.isIng(currentStatus)) {
            // ing, has callbacks
            // keep and wait callback

            setStatus(FileDownloadStatus.pending);
            getDriver().notifyPending();
            break;
          } else {
            // already over and no callback
          }
        }

        setStatus(transfer.getStatus());

        // to FileDownloadList
        FileDownloadList.getImpl().removeByWarn(this);
        break;
    }
  }