package com.retroarch.browser;

import java.io.*;

import com.retroarch.R;
import com.retroarch.browser.preferences.util.UserPreferences;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager.NameNotFoundException;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceActivity;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;

/**
 * {@link PreferenceActivity} subclass that provides all of the
 * functionality of the main menu screen.
 */
public final class MainMenuActivity extends PreferenceActivity {
	private static MainMenuActivity instance = null;
	private static final int ACTIVITY_LOAD_ROM = 0;
	private static final int ACTIVITY_RETROARCH = 1;
	private static final String TAG = "MainMenu";
	private static String libretro_path;
	private static String libretro_name;
	
	private void showGPLWaiver() {
		AlertDialog.Builder alert = new AlertDialog.Builder(this)
				.setTitle(R.string.gpl_waiver)
				.setMessage(R.string.gpl_waiver_desc)
				.setPositiveButton("Keep", null)
				.setNegativeButton("Remove non-GPL cores",
						new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog, int which) {
								final File[] libs = new File(getApplicationInfo().dataDir, "/cores").listFiles();
								for (final File lib : libs) {
									ModuleWrapper module = new ModuleWrapper(getApplicationContext(), lib);
									
									boolean gplv3 = module.getCoreLicense().equals("GPLv3");
									boolean gplv2 = module.getCoreLicense().equals("GPLv2");
									
									if (!gplv3 && !gplv2) {
										String libName = lib.getName();
										Log.i("GPL WAIVER", "Deleting non-GPL core" + libName + "...");
										lib.delete();
									}
								}
							}
						});
		alert.show();
	}

	@Override
	@SuppressWarnings("deprecation")
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		// Load the main menu XML.
		addPreferencesFromResource(R.xml.main_menu);

		// Cache an instance of this class (TODO: Bad practice, kill this somehow).
		instance = this;

		// Get libretro path and name.
		SharedPreferences prefs = UserPreferences.getPreferences(this);
		libretro_path = prefs.getString("libretro_path", getApplicationInfo().dataDir + "/cores");
		libretro_name = prefs.getString("libretro_name", getString(R.string.no_core));

		// Bind audio stream to hardware controls.
		setVolumeControlStream(AudioManager.STREAM_MUSIC);

		// Extract assets. 
		extractAssets();

		if (!prefs.getBoolean("first_time_refreshrate_calculate", false)) {
			prefs.edit().putBoolean("first_time_refreshrate_calculate", true).commit();

			if (!detectDevice(false)) {
				AlertDialog.Builder alert = new AlertDialog.Builder(this)
						.setTitle(R.string.welcome_to_retroarch)
						.setMessage(R.string.welcome_to_retroarch_desc)
						.setPositiveButton("OK", null);
				alert.show();
			}
			
			showGPLWaiver();
		}

		Intent startedByIntent = getIntent();
		if (startedByIntent.getStringExtra("ROM") != null && startedByIntent.getStringExtra("LIBRETRO") != null) {
			if (savedInstanceState == null || !savedInstanceState.getBoolean("romexec"))
				loadRomExternal(startedByIntent.getStringExtra("ROM"),
						startedByIntent.getStringExtra("LIBRETRO"));
			else
				finish();
		}
	}

	public static MainMenuActivity getInstance() {
		return instance;
	}

	private int getVersionCode() {
		int version = 0;
		try {
			version = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
		} catch (NameNotFoundException e) {
		}

		return version;
	}

	private boolean areAssetsExtracted() {
		int version = getVersionCode();

		try {
			String dataDir = getApplicationInfo().dataDir;
			File cacheVersion = new File(dataDir, ".cacheversion");
			if (cacheVersion.isFile() && cacheVersion.canRead() && cacheVersion.canWrite()) {
				DataInputStream cacheStream = new DataInputStream(
						new FileInputStream(cacheVersion));

				int currentCacheVersion = 0;
				try {
					currentCacheVersion = cacheStream.readInt();
				} catch (IOException e) {
				}
				cacheStream.close();

				if (currentCacheVersion == version) {
					Log.i("ASSETS", "Assets already extracted, skipping...");
					return true;
				}
			}
		} catch (IOException e) {
			Log.e(TAG, "Failed to extract assets to cache.");
			return false;
		}

		return false;
	}

	// Extract assets from native code. Doing it from Java side is apparently unbearably slow ...
	private void extractAssetsThread() {
		try {
			String dataDir = getApplicationInfo().dataDir;

			String apk = getApplicationInfo().sourceDir;
			Log.i(TAG, "Extracting RetroArch assets from: " + apk + " ...");
			boolean success = NativeInterface.extractArchiveTo(apk, "assets", dataDir);
			if (!success) {
				throw new IOException("Failed to extract assets ...");
			}
			Log.i(TAG, "Extracted assets ...");

			File cacheVersion = new File(dataDir, ".cacheversion");
			DataOutputStream outputCacheVersion = new DataOutputStream(
					new FileOutputStream(cacheVersion, false));
			outputCacheVersion.writeInt(getVersionCode());
			outputCacheVersion.close();
		} catch (IOException e) {
			Log.e(TAG, "Failed to extract assets to cache.");
		}
	}

	private void extractAssets() {
		if (areAssetsExtracted())
			return;

		final Dialog dialog = new Dialog(this);
		final Handler handler = new Handler();
		dialog.setContentView(R.layout.assets);
		dialog.setCancelable(false);
		dialog.setTitle("Asset extraction");

		// Java is fun :)
		Thread assetsThread = new Thread(new Runnable() {
			public void run() {
				extractAssetsThread();
				handler.post(new Runnable() {
					public void run() {
						dialog.dismiss();
					}
				});
			}
		});
		assetsThread.start();

		dialog.show();
	}

	public void setModule(String core_path, String core_name) {
		UserPreferences.updateConfigFile(this);
		
		libretro_path = core_path;
		libretro_name = core_name;

		SharedPreferences prefs = UserPreferences.getPreferences(this);
		SharedPreferences.Editor edit = prefs.edit();
		edit.putString("libretro_path", libretro_path);
		edit.putString("libretro_name", libretro_name);
		edit.commit();

		// Set the title section to contain the name of the selected core.
		setCoreTitle(libretro_name);
		
	}

	public void setCoreTitle(String core_name) {
		setTitle("RetroArch : " + core_name);
	}

	private boolean detectDevice(boolean show_dialog) {
		boolean retval = false;

		final Context ctx = this;
		final boolean mentionPlayStore = !Build.MODEL.equals("OUYA Console");
		final String message = (mentionPlayStore ? getString(R.string.detect_device_msg_general) : getString(R.string.detect_device_msg_ouya));

		Log.i("Device MODEL", Build.MODEL);
		if (Build.MODEL.equals("SHIELD")) {
			AlertDialog.Builder alert = new AlertDialog.Builder(this)
					.setTitle(R.string.nvidia_shield_detected)
					.setMessage(message)
					.setPositiveButton(R.string.ok,
							new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									SharedPreferences prefs = UserPreferences.getPreferences(MainMenuActivity.this);
									SharedPreferences.Editor edit = prefs.edit();
									edit.putString("video_refresh_rate", Double.toString(60.00d));
									edit.putBoolean("input_overlay_enable", false);
									edit.putBoolean("input_autodetect_enable", true);
									edit.putString("audio_latency", "64");
									edit.putBoolean("audio_latency_auto", true);
									edit.commit();
									UserPreferences.updateConfigFile(ctx);
								}
							});
			alert.show();
			retval = true;
		} else if (Build.MODEL.equals("GAMEMID_BT")) {
			AlertDialog.Builder alert = new AlertDialog.Builder(this)
					.setTitle(R.string.game_mid_detected)
					.setMessage(message)
					.setPositiveButton(R.string.ok,
							new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									SharedPreferences prefs = UserPreferences.getPreferences(MainMenuActivity.this);
									SharedPreferences.Editor edit = prefs.edit();
									edit.putBoolean("input_overlay_enable", false);
									edit.putBoolean("input_autodetect_enable", true);
									edit.putString("audio_latency", "160");
									edit.putBoolean("audio_latency_auto", false);
									edit.commit();
									UserPreferences.updateConfigFile(ctx);
								}
							});
			alert.show();
			retval = true;
		} else if (Build.MODEL.equals("OUYA Console")) {
			AlertDialog.Builder alert = new AlertDialog.Builder(this)
					.setTitle(R.string.ouya_detected)
					.setMessage(message)
					.setPositiveButton(R.string.ok,
							new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									SharedPreferences prefs = UserPreferences.getPreferences(MainMenuActivity.this);
									SharedPreferences.Editor edit = prefs.edit();
									edit.putBoolean("input_overlay_enable", false);
									edit.putBoolean("input_autodetect_enable", true);
									edit.putString("audio_latency", "64");
									edit.putBoolean("audio_latency_auto", true);
									edit.commit();
									UserPreferences.updateConfigFile(ctx);
								}
							});
			alert.show();
			retval = true;
		} else if (Build.MODEL.equals("R800x")) {
					AlertDialog.Builder alert = new AlertDialog.Builder(this)
							.setTitle(R.string.xperia_play_detected)
							.setMessage(message)
							.setPositiveButton(R.string.ok,
									new DialogInterface.OnClickListener() {
										@Override
										public void onClick(DialogInterface dialog, int which) {
											SharedPreferences prefs = UserPreferences.getPreferences(MainMenuActivity.this);
											SharedPreferences.Editor edit = prefs.edit();
											edit.putBoolean("video_threaded", false);
											edit.putBoolean("input_overlay_enable", false);
											edit.putBoolean("input_autodetect_enable", true);
											edit.putString("video_refresh_rate", Double.toString(59.19132938771038));
											edit.putString("audio_latency", "128");
											edit.putBoolean("audio_latency_auto", false);
											edit.commit();
											UserPreferences.updateConfigFile(ctx);
										}
									});
					alert.show();
					retval = true;
		} else if (Build.ID.equals("JSS15J")) {
			AlertDialog.Builder alert = new AlertDialog.Builder(this)
					.setTitle(R.string.nexus_7_2013_detected)
					.setMessage(message)
					.setPositiveButton(R.string.ok,
							new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									SharedPreferences prefs = UserPreferences.getPreferences(MainMenuActivity.this);
									SharedPreferences.Editor edit = prefs.edit();
									edit.putString("video_refresh_rate", Double.toString(59.65));
									edit.putString("audio_latency", "64");
									edit.putBoolean("audio_latency_auto", false);
									edit.commit();
									UserPreferences.updateConfigFile(ctx);
								}
							});
			alert.show();
			retval = true;
		}

		if (show_dialog) {
			Toast.makeText(this, R.string.no_optimal_settings, Toast.LENGTH_SHORT).show();
		}

		return retval;
	}

	@Override
	public void startActivity(Intent intent) {
		if (intent.getComponent().getClassName()
				.equals("com.retroarch.browser.diractivities.ROMActivity")) {
			if (!new File(libretro_path).isDirectory()) {
				super.startActivityForResult(intent, ACTIVITY_LOAD_ROM);
			} else {
				Toast.makeText(this, R.string.load_a_core_first, Toast.LENGTH_SHORT).show();
			}
		} else {
			super.startActivity(intent);
		}
	}

	@Override
	protected void onActivityResult(int reqCode, int resCode, Intent data) {
		switch (reqCode) {
			case ACTIVITY_LOAD_ROM: {
				if (data.getStringExtra("PATH") != null) {
					UserPreferences.updateConfigFile(this);
					String current_ime = Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
					Toast.makeText(this,String.format(getString(R.string.loading_data), data.getStringExtra("PATH")), Toast.LENGTH_SHORT).show();
					Intent myIntent = new Intent(this, RetroActivity.class);
					myIntent.putExtra("ROM", data.getStringExtra("PATH"));
					myIntent.putExtra("LIBRETRO", libretro_path);
					myIntent.putExtra("CONFIGFILE", UserPreferences.getDefaultConfigPath(this));
					myIntent.putExtra("IME", current_ime);
					startActivityForResult(myIntent, ACTIVITY_RETROARCH);
				}
				break;
			}
		
			case ACTIVITY_RETROARCH: {
				Log.i(TAG, "RetroArch finished running.");
				UserPreferences.readbackConfigFile(this);
				break;
			}
		}
	}

	@Override
	protected void onSaveInstanceState(Bundle data) {
		super.onSaveInstanceState(data);
		data.putCharSequence("title", getTitle());
		data.putBoolean("romexec", true);
	}

	@Override
	protected void onRestoreInstanceState(Bundle state) {
		super.onRestoreInstanceState(state);

		if (state != null) {
			setTitle(state.getCharSequence("title"));
		}
	}

	private void loadRomExternal(String rom, String core) {
		UserPreferences.updateConfigFile(this);
		String current_ime = Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
		Toast.makeText(this, String.format(getString(R.string.loading_data), rom), Toast.LENGTH_SHORT).show();
		Intent myIntent = new Intent(this, RetroActivity.class);
		myIntent.putExtra("ROM", rom);
		myIntent.putExtra("LIBRETRO", core);
		myIntent.putExtra("CONFIGFILE", UserPreferences.getDefaultConfigPath(this));
		myIntent.putExtra("IME", current_ime);
		startActivity(myIntent);
	}
}