package com.aptoide.amethyst.downloadmanager;
import android.os.StatFs;
import android.util.Log;
import com.aptoide.amethyst.downloadmanager.exception.IPBlackListedException;
import java.io.BufferedInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import com.aptoide.amethyst.downloadmanager.exception.CompletedDownloadException;
import com.aptoide.amethyst.downloadmanager.exception.ContentTypeNotApkException;
import com.aptoide.amethyst.downloadmanager.exception.DownloadNotFoundException;
import com.aptoide.amethyst.downloadmanager.exception.Md5FailedException;
import com.aptoide.amethyst.downloadmanager.model.DownloadFile;
import com.aptoide.amethyst.downloadmanager.model.DownloadModel;
import com.aptoide.amethyst.downloadmanager.state.ActiveState;
import com.aptoide.amethyst.downloadmanager.state.ErrorState;
/**
* Created with IntelliJ IDEA.
* User: rmateus
* Date: 02-07-2013
* Time: 15:22
* To change this template use File | Settings | File Templates.
*/
public class DownloadThread implements Runnable, Serializable {
DownloadConnection mConnection = null;
DownloadFile mDownloadFile = null;
transient RandomAccessFile file = null;
private long mFullSize;
private long mProgress;
private DownloadModel download;
private long fileSize;
private long mDownloadedSize = 0;
private long mRemainingSize;
private DownloadInfoRunnable parent;
public DownloadThread(DownloadModel download, DownloadInfoRunnable parent) throws IOException {
this.download = download;
this.parent = parent;
this.mConnection = download.createConnection();
this.mProgress = DownloadFile.getFileLength(download.getDestination());
this.mFullSize = download.getSize();
this.mRemainingSize = mFullSize;
}
public long getmDownloadedSize() {
return mDownloadedSize;
}
public long getmProgress() {
return mProgress > 0 ? mProgress : 0;
}
public long getmFullSize() {
return mFullSize;
}
public long getmRemainingSize() {
return mRemainingSize;
}
@Override
public void run() {
try {
if (!(parent.getStatusState() instanceof ActiveState)) {
return;
}
mDownloadFile = download.createFile();
file = mDownloadFile.getmFile();
this.mConnection = download.createConnection();
mConnection.setPaidApp(parent.isPaid());
this.mDownloadedSize = 0;
fileSize = DownloadFile.getFileLength(download.getDestination());
mDownloadFile.setDownloadedSize(file, fileSize);
this.mRemainingSize = mFullSize - fileSize;
download();
} catch (DownloadNotFoundException exception) {
exception.printStackTrace();
parent.changeStatusState(new ErrorState(parent, EnumDownloadFailReason.NOT_FOUND));
} catch (FileNotFoundException exception) {
exception.printStackTrace();
parent.changeStatusState(new ErrorState(parent, EnumDownloadFailReason.SD_ERROR));
} catch (ContentTypeNotApkException e) {
parent.changeStatusState(new ErrorState(parent, EnumDownloadFailReason.PAIDAPP_NOTFOUND));
} catch (IPBlackListedException e) {
if (mConnection != null) {
mConnection.close();
}
try {
mConnection = download.createFallbackConnection();
download();
} catch (DownloadNotFoundException exception) {
exception.printStackTrace();
parent.changeStatusState(new ErrorState(parent, EnumDownloadFailReason.NOT_FOUND));
} catch (FileNotFoundException exception) {
exception.printStackTrace();
parent.changeStatusState(new ErrorState(parent, EnumDownloadFailReason.SD_ERROR));
} catch (ContentTypeNotApkException e1) {
parent.changeStatusState(new ErrorState(parent, EnumDownloadFailReason.PAIDAPP_NOTFOUND));
} catch (IPBlackListedException e1) {
try {
InetAddress.getByName(mConnection.getURL().getHost());
} catch (UnknownHostException e2) {
e2.printStackTrace();
}
parent.changeStatusState(new ErrorState(parent, EnumDownloadFailReason.IP_BLACKLISTED));
} catch (Md5FailedException e1) {
e1.printStackTrace();
mDownloadFile.delete();
parent.changeStatusState(new ErrorState(parent, EnumDownloadFailReason.MD5_CHECK_FAILED));
} catch (UnknownHostException e1) {
e1.printStackTrace();
parent.changeStatusState(new ErrorState(parent, EnumDownloadFailReason.CONNECTION_ERROR));
} catch (CompletedDownloadException e1) {
mFullSize = mProgress = fileSize;
mRemainingSize = 0;
e1.printStackTrace();
} catch (Exception e1) {
e1.printStackTrace();
parent.changeStatusState(new ErrorState(parent, EnumDownloadFailReason.CONNECTION_ERROR));
}
} catch (Md5FailedException e) {
e.printStackTrace();
mDownloadFile.delete();
parent.changeStatusState(new ErrorState(parent, EnumDownloadFailReason.MD5_CHECK_FAILED));
} catch (UnknownHostException e) {
e.printStackTrace();
parent.changeStatusState(new ErrorState(parent, EnumDownloadFailReason.CONNECTION_ERROR));
} catch (IOException e) {
e.printStackTrace();
parent.changeStatusState(new ErrorState(parent, EnumDownloadFailReason.CONNECTION_ERROR));
} catch (CompletedDownloadException e) {
mFullSize = mProgress = fileSize;
mRemainingSize = 0;
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
parent.changeStatusState(new ErrorState(parent, EnumDownloadFailReason.CONNECTION_ERROR));
}
if (mDownloadFile != null && file != null) {
mDownloadFile.close(file);
}
if (mConnection != null) {
mConnection.close();
}
}
/**
* Actual method that performs the download.
*
* @throws IOException
* @throws CompletedDownloadException
* @throws DownloadNotFoundException
* @throws IPBlackListedException
* @throws ContentTypeNotApkException
* @throws Md5FailedException
*/
private void download() throws IOException, CompletedDownloadException, DownloadNotFoundException, IPBlackListedException, ContentTypeNotApkException, Md5FailedException {
mConnection.connect(fileSize, parent.isUpdate());
Log.d("DownloadManager", "Starting Download " + (parent.getStatusState() instanceof ActiveState) + " " + this.mDownloadedSize + fileSize + " " + this.mRemainingSize);
byte[] bytes = new byte[1024];
int bytesRead;
BufferedInputStream mStream = mConnection.getStream();
if (parent.getStatusState() instanceof ActiveState) {
StatFs stat = new StatFs(download.getDestination());
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
long avail = (blockSize * availableBlocks);
if (mRemainingSize > avail) {
parent.changeStatusState(new ErrorState(parent, EnumDownloadFailReason.NO_FREE_SPACE));
}
}
while ((bytesRead = mStream.read(bytes)) != -1 && parent.getStatusState() instanceof ActiveState) {
file.write(bytes, 0, bytesRead);
this.mDownloadedSize += bytesRead;
this.mProgress += bytesRead;
}
if (parent.getStatusState() instanceof ActiveState) {
mDownloadFile.checkMd5();
mDownloadFile.rename();
}
}
}