package jp.sourceforge.nicoro;

import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;

import java.lang.ref.WeakReference;

public class NicoroApplication extends Application {
    private static final String KEY_UNCAUGHT_EXCEPTION = "pref_key_uncaught_exception";
    
	private ThumbnailCacher mThumbnailCacher;
	private ThumbInfoCacher mThumbInfoCacher;

	@Override
	public void onCreate() {
		super.onCreate();
		
		UncaughtExceptionHandlerWrapper handler =
		    new UncaughtExceptionHandlerWrapper(getApplicationContext());
	    handler.setDefaultHandler();
	    
//        // メモリ予約
//        Runtime runtime = Runtime.getRuntime();
//        long reserveSize = runtime.maxMemory() / 2
//            - (runtime.totalMemory() - runtime.freeMemory());
//        if (reserveSize > 0) {
//            byte[] temp = new byte[(int) reserveSize];
//            temp = null;
//            runtime.gc();
//        }
	}
	
	@Override
	public void onLowMemory() {
		super.onLowMemory();
		if (mThumbnailCacher != null) {
			mThumbnailCacher.onLowMemory();
		}
		if (mThumbInfoCacher != null) {
			mThumbInfoCacher.onLowMemory();
		}
	}
	
	public static NicoroApplication getInstance(Activity activity) {
	    return (NicoroApplication) activity.getApplication();
	}
	
	public ThumbnailCacher getThumbnailCacher() {
		if (mThumbnailCacher == null) {
			mThumbnailCacher = new ThumbnailCacher();
			mThumbnailCacher.start();
		}
		return mThumbnailCacher;
	}
	
	public ThumbInfoCacher getThumbInfoCacher() {
		if (mThumbInfoCacher == null) {
			mThumbInfoCacher = new ThumbInfoCacher();
			mThumbInfoCacher.start();
		}
		return mThumbInfoCacher;
	}
	
	public String processLastUncaughtException() {
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
        String lastUncaught = sp.getString(KEY_UNCAUGHT_EXCEPTION, null);
        if (lastUncaught != null) {
            sp.edit().remove(KEY_UNCAUGHT_EXCEPTION).commit();
        }
        return lastUncaught;
	}
	
	private static class UncaughtExceptionHandlerWrapper
	implements Thread.UncaughtExceptionHandler {
	    private WeakReference<Context> mRefContext;
	    private Thread.UncaughtExceptionHandler mDefaultHandler;
	    
	    UncaughtExceptionHandlerWrapper(Context context) {
	        mRefContext = new WeakReference<Context>(context);
	        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
	        assert !(mDefaultHandler instanceof UncaughtExceptionHandlerWrapper);
	    }
	    
	    void setDefaultHandler() {
	        Thread.setDefaultUncaughtExceptionHandler(this);
	    }
	    
        @Override
        public void uncaughtException(Thread thread, Throwable ex) {
            Context context = mRefContext.get();
            if (context != null) {
                StringBuilder builder = new StringBuilder();
                builder.append(ex.toString()).append("\n\n");
                StackTraceElement[] traces = ex.getStackTrace();
                assert traces != null;
                assert traces.length > 0;
                builder.append(traces[0].toString());
                if (!traces[0].getClassName().startsWith("jp.sourceforge.nicoro")) {
                    for (int i = 1; i < traces.length; ++i) {
                        if (traces[i].getClassName().startsWith("jp.sourceforge.nicoro")) {
                            builder.append("\n...\n").append(traces[i].toString());
                            break;
                        }
                    }
                }
                
                SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
                sp.edit().putString(KEY_UNCAUGHT_EXCEPTION, builder.toString())
                    .commit();
            }
            mDefaultHandler.uncaughtException(thread, ex);
        }
	}
}
