package cn.net.caoyao.cpzshandset.service.http;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.http.HttpResponse;
import org.apache.http.conn.ConnectTimeoutException;

import android.os.Message;
import android.util.Log;

public class FileHttpResponseHandler extends AsyncHttpResponseHandler {
	public final static int TIME_OUT = 30000;
	private final static int BUFFER_SIZE = 1024 * 8;

	private static final String TAG = "FileHttpResponseHandler";
	private static final String TEMP_SUFFIX = ".download";
	private File file;
	private File tempFile;
	private File baseDirFile;
	private RandomAccessFile outputStream;
	private long downloadSize;
	private long previousFileSize;
	private long totalSize;
	private long networkSpeed;
	private long previousTime;
	private long totalTime;
	private boolean interrupt = false;
	private boolean timerInterrupt = false;
	private String url;
	private Timer timer = new Timer();
	private static final int TIMERSLEEPTIME = 100;

	public FileHttpResponseHandler(String url, String rootFile, String fileName) {

		super();
		this.url = url;
		this.baseDirFile = new File(rootFile);
		this.file = new File(rootFile, fileName);
		this.tempFile = new File(rootFile, fileName + TEMP_SUFFIX);
		init();
	}

	public FileHttpResponseHandler(String rootFile, String fileName) {
		super();
		this.baseDirFile = new File(rootFile);
		this.file = new File(rootFile, fileName);
		this.tempFile = new File(rootFile, fileName + TEMP_SUFFIX);
		init();
	}

	public FileHttpResponseHandler(String filePath) {
		super();
		this.file = new File(filePath);
		this.baseDirFile = new File(this.file.getParent());
		this.tempFile = new File(filePath + TEMP_SUFFIX);
		init();
	}

	private void init() {
		// TODO Auto-generated method stub
		if (!this.baseDirFile.exists()) {
			this.baseDirFile.mkdirs();
		}
	}

	private void startTimer() {
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				while (!timerInterrupt) {
					sendProgressMessage(totalSize, getDownloadSize(),
							networkSpeed);
					try {
						Thread.sleep(TIMERSLEEPTIME);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}

			}
		}, 0, 1000);
	}

	private void stopTimer() {
		timerInterrupt = true;
	}

	public File getFile() {
		return file;
	}

	public String getUrl() {
		return url;
	}

	private class ProgressReportingRandomAccessFile extends RandomAccessFile {
		private int progress = 0;

		public ProgressReportingRandomAccessFile(File file, String mode)
				throws FileNotFoundException {
			super(file, mode);
		}

		@Override
		public void write(byte[] buffer, int offset, int count)
				throws IOException {

			super.write(buffer, offset, count);
			progress += count;
			totalTime = System.currentTimeMillis() - previousTime;
			downloadSize = progress + previousFileSize;
			if (totalTime > 0) {
				networkSpeed = (long) ((progress / totalTime) / 1.024);
			}

		}
	}

	public boolean isInterrupt() {

		return interrupt;
	}

	public void setInterrupt(boolean interrupt) {
		this.interrupt = interrupt;
	}

	public long getDownloadSize() {

		return downloadSize;
	}

	public long getTotalSize() {

		return totalSize;
	}
	
	public void setTotalSize(long size) {

		totalSize=size;
	}

	public double getDownloadSpeed() {

		return this.networkSpeed;
	}

	public void setPreviousFileSize(long previousFileSize) {
		this.previousFileSize = previousFileSize;
	}

	public long getTotalTime() {

		return this.totalTime;
	}

	public void onSuccess(byte[] binaryData) {
		onSuccess(new String(binaryData));
	}

	public void onSuccess(int statusCode, byte[] binaryData) {
		onSuccess(binaryData);
	}

	public void onFailure(Throwable error, byte[] binaryData) {
		onFailure(error);
	}

	protected void sendSuccessMessage(int statusCode, byte[] responseBody) {
		sendMessage(obtainMessage(SUCCESS_MESSAGE, new Object[] { statusCode,
				responseBody }));
	}

	@Override
	protected void sendFailureMessage(Throwable e, byte[] responseBody) {
		sendMessage(obtainMessage(FAILURE_MESSAGE, new Object[] { e,
				responseBody }));
	}

	protected void sendProgressMessage(long totalSize, long currentSize,
			long speed) {
		sendMessage(obtainMessage(PROGRESS_MESSAGE, new Object[] { totalSize,
				currentSize, speed }));
	}

	protected void handleSuccessMessage(int statusCode, byte[] responseBody) {
		onSuccess(statusCode, responseBody);
	}

	protected void handleFailureMessage(Throwable e, byte[] responseBody) {
		onFailure(e, responseBody);
	}

	@Override
	protected void handleMessage(Message msg) {
		Object[] response;
		switch (msg.what) {
		case SUCCESS_MESSAGE:
			response = (Object[]) msg.obj;
			handleSuccessMessage(((Integer) response[0]).intValue(),
					(byte[]) response[1]);
			break;
		default:
			super.handleMessage(msg);
			break;
		}
	}

	@Override
	protected void sendResponseMessage(HttpResponse response) {

		Throwable error = null;
		byte[] responseBody = null;
		long result = -1;
		int statusCode = 0;
		// previousTime = System.currentTimeMillis();
		try {
			statusCode = response.getStatusLine().getStatusCode();
			long contentLenght = response.getEntity().getContentLength();
			// -1的解决方式ContentLength 在手机访问的时候出现了问题，返回为-1
			if (contentLenght == -1) {
				contentLenght = response.getEntity().getContent().available();
			}
			totalSize = contentLenght + previousFileSize;

			Log.v(TAG, "totalSize: " + totalSize);

			if (file.exists() && totalSize == file.length()) {
				Log.v(TAG, "Output file already exists. Skipping download.");
				//throw new FileAlreadyExistException("Output file already exists. Skipping download.");
				sendSuccessMessage(statusCode, "Output file already exists. Skipping download.".getBytes());
				return;
			} else if (tempFile.exists()) {
				// response.addHeader("Range", "bytes=" + tempFile.length()
				// +
				// "-");
				Log.v(TAG, "yahooo: " + response.getEntity().getContentLength());
				previousFileSize = tempFile.length();

				Log.v(TAG, "File is not complete, download now.");
				Log.v(TAG, "File length:" + tempFile.length() + " totalSize:"
						+ totalSize);

			}
			outputStream = new ProgressReportingRandomAccessFile(tempFile, "rw");
			InputStream input = response.getEntity().getContent();
			startTimer();
			int bytesCopied = copy(input, outputStream);
			if ((previousFileSize + bytesCopied) != totalSize
					&& totalSize != -1 && !interrupt) {
				throw new IOException("Download incomplete: " + bytesCopied+ " != " + totalSize);
			}
			Log.v(TAG, "Download completed successfully.");
			result = bytesCopied;
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			sendFailureMessage(e, responseBody);
			error = e;
		}/* catch (FileAlreadyExistException e) {
			// TODO Auto-generated catch block
			// sendSuccessMessage(statusCode, e.getMessage().getBytes());
			error = e;
		}*/ catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			error = e;
			// sendFailureMessage(e, responseBody);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			// sendFailureMessage(e, responseBody);
			error = e;
		}
		// 停止打印
		stopTimer();
		// 保证timer被关闭
		try {
			Thread.sleep(TIMERSLEEPTIME);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if (result == -1 || interrupt || error != null) {
			if (error != null) {
				Log.v(TAG, "Download failed." + error.getMessage());
				/*if (error instanceof FileAlreadyExistException) {
					sendSuccessMessage(statusCode, "下载成功！".getBytes());

				} else {
					sendFailureMessage(error, responseBody);
				}*/
				sendFailureMessage(error, responseBody);
			}
			return;
		}
		tempFile.renameTo(file);
		sendSuccessMessage(statusCode, "下载成功！".getBytes());
	}

	public int copy(InputStream input, RandomAccessFile out) throws IOException {

		if (input == null || out == null) {
			return -1;
		}

		byte[] buffer = new byte[BUFFER_SIZE];

		BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE);
		Log.v(TAG, "length" + out.length());
		int count = 0, n = 0;
		long errorBlockTimePreviousTime = -1, expireTime = 0;
		try {
			out.seek(out.length());
			previousTime = System.currentTimeMillis();
			while (!interrupt) {
				n = in.read(buffer, 0, BUFFER_SIZE);
				if (n == -1) {
					break;
				}
				out.write(buffer, 0, n);
				count += n;
				if (networkSpeed == 0) {
					if (errorBlockTimePreviousTime > 0) {
						expireTime = System.currentTimeMillis()
								- errorBlockTimePreviousTime;
						if (expireTime > TIME_OUT) {
							throw new ConnectTimeoutException("connection time out.");
						}
					} else {
						errorBlockTimePreviousTime = System.currentTimeMillis();
					}
				} else {
					expireTime = 0;
					errorBlockTimePreviousTime = -1;
				}
			}
		} finally {

			try {
				out.close();
				// 无法关闭 inputstram
				// input.close();
				// in.close();
			} catch (IOException e) {
				// TODO: handle exception
			}
		}
		return count;

	}

	public File getTempFile() {
		// TODO Auto-generated method stub
		return tempFile;
	}

}