package jp.sourceforge.nicoro;

import static jp.sourceforge.nicoro.Log.LOG_TAG;

import java.io.IOException;
import java.lang.ref.SoftReference;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;

import android.graphics.Bitmap;
import android.os.Message;

public class ThumbnailCacher extends LooperThread {
	private static final int MSG_ID_LOAD_THUMBNAIL = 0;

	private static class Params {
		public String url;
		public CallbackMessage<Bitmap, Void> callbackMessage;

		public Params(String u, CallbackMessage<Bitmap, Void> cm) {
			url = u;
			callbackMessage = cm;
		}
	}

	private ConcurrentHashMap<String, SoftReference<Bitmap>> mThumbnailCache =
		new ConcurrentHashMap<String, SoftReference<Bitmap>>();
	private volatile HttpUriRequest mCurrentHttpRequest;
	private DefaultHttpClient mHttpClient;

	public ThumbnailCacher() {
		super("ThumbnailCacher");
	}

	@Override
	public boolean handleMessage(Message msg) {
		switch (msg.what) {
		case MSG_ID_LOAD_THUMBNAIL:
			Params params = (Params) msg.obj;
			// ダウンロード前にもう一度確認（別のリクエストでダウンロード済みかもしれないので）
			Bitmap bitmap = getThumbnail(params.url);
			DefaultHttpClient httpClient;
			try {
				if (bitmap == null) {
					HttpGet httpRequest = new HttpGet(params.url);
					mCurrentHttpRequest = httpRequest;
					if (mHttpClient == null) {
						httpClient = Util.createHttpClient(15 * 1000, 30 * 1000);
						mHttpClient = httpClient;
					} else {
					    httpClient = mHttpClient;
					}
					bitmap = Util.loadBitmap(httpClient, httpRequest);
					mCurrentHttpRequest = null;
					if (bitmap != null) {
						mThumbnailCache.put(params.url, new SoftReference<Bitmap>(bitmap));
					}
				}

				if (bitmap != null) {
				    params.callbackMessage.sendMessageSuccess(bitmap);
				}
			} catch (ClientProtocolException e) {
				Log.e(LOG_TAG, e.toString(), e);
				// 再ダウンロード
				mCurrentHttpRequest = null;
                httpClient = mHttpClient;
				if (httpClient != null) {
				    httpClient.getConnectionManager().shutdown();
				    mHttpClient = null;
				}
				getHandler().obtainMessage(MSG_ID_LOAD_THUMBNAIL, params).sendToTarget();
			} catch (IOException e) {
				Log.e(LOG_TAG, e.toString(), e);
				// 再ダウンロード
				mCurrentHttpRequest = null;
                httpClient = mHttpClient;
                if (httpClient != null) {
                    httpClient.getConnectionManager().shutdown();
                    mHttpClient = null;
                }
				getHandler().obtainMessage(MSG_ID_LOAD_THUMBNAIL, params).sendToTarget();
			} catch (IllegalStateException e) {
	            // HttpClientを強制シャットダウンしたときに飛んでくる可能性
                Log.e(LOG_TAG, e.toString(), e);
                mCurrentHttpRequest = null;
                httpClient = mHttpClient;
                if (httpClient != null) {
                    httpClient.getConnectionManager().shutdown();
                    mHttpClient = null;
                }
			}
			break;
		default:
			assert false : msg.what;
			break;
		}
		return true;
	}

	@Override
	public boolean quit() {
		boolean ret = super.quit();
		Util.abortHttpUriRequest(mCurrentHttpRequest);
		DefaultHttpClient httpClient = mHttpClient;
		if (httpClient != null) {
            mHttpClient = null;
		    httpClient.getConnectionManager().shutdown();
		}
		return ret;
	}

	public void onLowMemory() {
	    for (Iterator<String> it = mThumbnailCache.keySet().iterator(); it.hasNext(); ) {
	        String key = it.next();
            SoftReference<Bitmap> ref = mThumbnailCache.get(key);
            Bitmap bitmap = (ref == null ? null : ref.get());
            if (bitmap == null) {
                it.remove();
            }
	    }
	}

	public Bitmap getThumbnail(String url) {
		SoftReference<Bitmap> ref = mThumbnailCache.get(url);
		if (ref != null) {
			return ref.get();
		}
		return null;
	}

	public void loadThumbnail(String url,
	        CallbackMessage<Bitmap, Void> callback) {
		Params params = new Params(url, callback);
		getHandler().obtainMessage(MSG_ID_LOAD_THUMBNAIL, params).sendToTarget();
	}
}
