package de.tudarmstadt.informatik.hostage.ui2.activity;

import android.app.ActionBar;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;

import de.tudarmstadt.informatik.hostage.HoneyHandler;
import de.tudarmstadt.informatik.hostage.HoneyService;
import de.tudarmstadt.informatik.hostage.R;
import de.tudarmstadt.informatik.hostage.ui.LogFilter;
import de.tudarmstadt.informatik.hostage.ui2.adapter.DrawerListAdapter;
import de.tudarmstadt.informatik.hostage.ui2.fragment.AboutFragment;
import de.tudarmstadt.informatik.hostage.ui2.fragment.HomeFragment;
import de.tudarmstadt.informatik.hostage.ui2.fragment.ProfileManagerFragment;
import de.tudarmstadt.informatik.hostage.ui2.fragment.RecordOverviewFragment;
import de.tudarmstadt.informatik.hostage.ui2.fragment.ServicesFragment;
import de.tudarmstadt.informatik.hostage.ui2.fragment.SettingsFragment;
import de.tudarmstadt.informatik.hostage.ui2.fragment.StatisticsFragment;
import de.tudarmstadt.informatik.hostage.ui2.fragment.ThreatMapFragment;
import de.tudarmstadt.informatik.hostage.ui2.fragment.opengl.ThreatIndicatorGLRenderer;
import de.tudarmstadt.informatik.hostage.ui2.model.DrawerListItem;

/**
 * @author Alexander Brakowski
 * @created 12.01.14 23:24
 */
public class MainActivity extends Activity {
	public static volatile Context context;

	public static boolean isRooted = false;

	public static boolean porthackInstalled = false;

	/** singleton instance of the MainActivity **/
	private static MainActivity sInstance = null;

	public Fragment mDisplayedFragment;

	public HoneyService mHoneyService;

	private DrawerLayout mDrawerLayout;

	private ListView mDrawerList;

	private ActionBarDrawerToggle mDrawerToggle;

	private CharSequence mDrawerTitle;

	private CharSequence mTitle;

    private MainMenuItem mSelectedMenuItem = null;

	private ArrayList<DrawerListItem> mDrawerItems;

	private boolean mServiceBound = false;

	/**
	 * Connection to bind the background service
	 *
	 * @see HoneyService
	 */
	private ServiceConnection mConnection = new ServiceConnection() {
		/**
		 * After the service is bound, check which has been clicked and start
		 * it.
		 *
		 * @see android.content.ServiceConnection#onServiceConnected(android.content.ComponentName, android.os.IBinder)
		 */
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			mHoneyService = ((HoneyService.LocalBinder) service).getService();
			mServiceBound = true;
		}

		/**
		 * After the service is unbound, delete reference.
		 *
		 * @see android.content.ServiceConnection#onServiceDisconnected(android.content.ComponentName)
		 */
		@Override
		public void onServiceDisconnected(ComponentName name) {
			mHoneyService = null;
			mServiceBound = false;
		}

	};

	private boolean mInvalidMenuItem = false;

	private HashMap<String, Boolean> mAttacksOnProtocol = new HashMap<String, Boolean>();

	/**
	 * Retrieve the singleton latest instance of the activity
	 * @return MainActivity - the singleton instance
	 */
	public static MainActivity getInstance(){
		assert(sInstance != null);
		return sInstance;
	}

	public static Context getContext(){
		return MainActivity.context;
	}

	@Override
	public void onStart(){
		super.onStart();

		registerReceiver();

		if(isServiceRunning()){
			this.bindService();
		}
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		sInstance = this;

		MainActivity.context = getApplicationContext();

		setContentView(R.layout.activity_drawer_main);

		ThreatIndicatorGLRenderer.assets = getAssets();
		ThreatIndicatorGLRenderer.setThreatLevel(ThreatIndicatorGLRenderer.ThreatLevel.NOT_MONITORING);
		// set background color
		TypedArray arr = getTheme().obtainStyledAttributes(
				new int[] { android.R.color.background_light });
		ThreatIndicatorGLRenderer.setBackgroundColor(arr.getColor(0, 0xFFFFFF));
		arr.recycle();

		ActionBar actionBar = getActionBar();
		actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE
				| ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_HOME_AS_UP);

		mTitle = mDrawerTitle = getTitle();
		mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
		mDrawerList = (ListView) findViewById(R.id.left_drawer);

		mDrawerItems = new ArrayList<DrawerListItem>();
		mDrawerItems.add(new DrawerListItem(R.string.drawer_overview, R.drawable.ic_menu_home));
		mDrawerItems.add(new DrawerListItem(R.string.drawer_threat_map, R.drawable.ic_menu_mapmode));
		mDrawerItems.add(new DrawerListItem(R.string.drawer_records, R.drawable.ic_menu_records));
		mDrawerItems.add(new DrawerListItem(R.string.drawer_statistics, R.drawable.ic_menu_stats));
		mDrawerItems.add(new DrawerListItem(R.string.drawer_services, R.drawable.ic_menu_set_as));
		mDrawerItems.add(
				new DrawerListItem(R.string.drawer_profile_manager, R.drawable.ic_menu_allfriends));
		mDrawerItems.add(
				new DrawerListItem(R.string.drawer_settings, R.drawable.ic_menu_preferences));
		mDrawerItems.add(
				new DrawerListItem(R.string.drawer_app_info, R.drawable.ic_menu_info_details));


		DrawerListAdapter listAdapter = new DrawerListAdapter(this, mDrawerItems);

		mDrawerList.setAdapter(listAdapter);
		mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

		getActionBar().setDisplayHomeAsUpEnabled(true);
		getActionBar().setHomeButtonEnabled(true);
		getActionBar().setDisplayShowHomeEnabled(true);

		mDrawerToggle = new ActionBarDrawerToggle(
				this,                  /* host Activity */
				mDrawerLayout,         /* DrawerLayout object */
				R.drawable.ic_navigation_drawer,  /* nav drawer image to replace 'Up' caret */
				R.string.drawer_open,  /* "open drawer" description for accessibility */
				R.string.drawer_close  /* "close drawer" description for accessibility */
		) {
			public void onDrawerClosed(View view) {
				getActionBar().setTitle(mTitle);
				invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
			}

			public void onDrawerOpened(View drawerView) {
				getActionBar().setTitle(mDrawerTitle);
				invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
			}
		};
		mDrawerLayout.setDrawerListener(mDrawerToggle);

		checkRootAndPorthack();
		startAndBind();

		if (savedInstanceState == null) {
			// on first time display view for first nav item
			displayView(0);
		}
	}

	private void registerReceiver() {
		LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver,
				new IntentFilter(getString(R.string.broadcast)));
	}

	private void unregisterReceiver() {
		LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
	}

	private BroadcastReceiver mReceiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context context, Intent intent) {
			Bundle extras = intent.getExtras();

			String sender = extras.getString("SENDER");
			String[] values = extras.getStringArray("VALUES");

			if(sender.equals(HoneyHandler.class.getName()) && values[0].equals(getString(R.string.broadcast_started))) {
				mAttacksOnProtocol.put(values[1], true);
			}
		}
	};

	public boolean hasProtocolAttacks(String protocol){
		if(!mAttacksOnProtocol.containsKey(protocol)) return false;

		return mAttacksOnProtocol.get(protocol);
	}

	public void startAndBind() {
		if(!isServiceRunning()){
			startService(getServiceIntent());
		}

		bindService();
	}

	public void stopAndUnbind() {
		if(mServiceBound){
			unbindService();
		}

		stopService(getServiceIntent());
	}

	public void unbindService() {
		try {
			unbindService(mConnection);
		} catch(IllegalArgumentException ex){
			// somehow already unbound.
		}
	}

	public void bindService() {
		mAttacksOnProtocol.clear();
		bindService(getServiceIntent(), mConnection, BIND_AUTO_CREATE);
		//mServiceBound = true;
	}

	@Override
	protected void onDestroy() {
		// Unregister Broadcast Receiver
		unregisterReceiver();

		// Unbind running service
		if(!mHoneyService.hasRunningListeners()){
			stopAndUnbind();
		}
		super.onDestroy();
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// toggle nav drawer on selecting action bar app icon/title
		if (mDrawerToggle.onOptionsItemSelected(item)) {
			return true;
		}

		if(item.getItemId() == android.R.id.home){
			if(!mDrawerToggle.isDrawerIndicatorEnabled()){
				if(getFragmentManager().getBackStackEntryCount() > 0) {
					getFragmentManager().popBackStackImmediate();
					this.mDisplayedFragment = getFragmentManager().findFragmentById(R.id.content_frame);
					this.mInvalidMenuItem = true;
				}

				if(getCurrentFragment().getTag() != null) mDrawerToggle.setDrawerIndicatorEnabled(true);
				return true;
			}
		}

		return super.onOptionsItemSelected(item);
	}

	@Override
	public void setTitle(CharSequence title) {
		mTitle = title;
		getActionBar().setTitle(mTitle);
	}

	/**
	 * When using the ActionBarDrawerToggle, you must call it during
	 * onPostCreate() and onConfigurationChanged()...
	 */

	@Override
	protected void onPostCreate(Bundle savedInstanceState) {
		super.onPostCreate(savedInstanceState);
		// Sync the toggle state after onRestoreInstanceState has occurred.
		mDrawerToggle.syncState();
	}

	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
		// Pass any configuration change to the drawer toggls
		mDrawerToggle.onConfigurationChanged(newConfig);
	}

	public Fragment getCurrentFragment() {
		return this.mDisplayedFragment;
	}

	public void displayView(int position) {
		if(mSelectedMenuItem != null && position == mSelectedMenuItem.value && !mInvalidMenuItem) {
			mDrawerLayout.closeDrawer(mDrawerList);
			return;
		}

        // DONT OPEN SAME VIEW AGAIN
		mInvalidMenuItem = false;
		MainMenuItem menuItemPosition = mSelectedMenuItem = MainMenuItem.create(position);

        Fragment fragment = null;

		// set orientation fixed to portrait in home fragment
		if(menuItemPosition == MainMenuItem.HOME){
			setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT | ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
		} else {
			setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
		}

        // update the main content by replacing fragments
		switch (menuItemPosition) {
			case HOME:
				fragment = new HomeFragment();
				break;
			case THREAT_MAP:
				fragment = new ThreatMapFragment();
				break;
			case RECORDS:{
				Intent intent = this.getIntent();
				intent.removeExtra(LogFilter.LOG_FILTER_INTENT_KEY);
				fragment = new RecordOverviewFragment();
				break;
            }
            case STATISTICS: {
                Intent intent = this.getIntent();
                intent.removeExtra(LogFilter.LOG_FILTER_INTENT_KEY);
                fragment = new StatisticsFragment();
                break;
            }
			case SERVICES:
				fragment = new ServicesFragment();
				break;
			case PROFILE_MANAGER:
				fragment = new ProfileManagerFragment();
				break;
			case SETTINGS:
				fragment = new SettingsFragment();
				break;
			case APPLICATION_INFO:
				fragment = new AboutFragment();
				break;
			default:
				break;
		}

		if (fragment != null) {
			// update selected item and title, then close the drawer if needed
            injectFragment(fragment, false, menuItemPosition);

		    mDrawerList.setItemChecked(position, true);
		    mDrawerList.setSelection(position);
		    setTitle(mDrawerItems.get(position).text);
        }

		mDrawerLayout.closeDrawer(mDrawerList);
	}

	public void injectFragment(Fragment fragment, boolean enableBack){
		injectFragment(fragment, enableBack, null);
	}

	public void injectFragment(Fragment fragment, boolean enableBack, Object tagObj){
		if(enableBack){
			mDrawerToggle.setDrawerIndicatorEnabled(false);
		}

		String tag = (tagObj == null ? null : tagObj.toString());

		FragmentManager fragmentManager = getFragmentManager();
		FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
		fragmentTransaction.replace(R.id.content_frame, fragment, tag);

		fragmentTransaction.addToBackStack(tag);

		fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
		fragmentTransaction.commit();

		this.mDisplayedFragment = fragment;
		
		if(tagObj == null){
			this.mInvalidMenuItem = true;
		}
	}

	@Override
	public void onBackPressed() {
		if(getFragmentManager().getBackStackEntryCount() == 1) {
			finish();
		} else {
			super.onBackPressed();
			this.mDisplayedFragment = getFragmentManager().findFragmentById(R.id.content_frame);
			this.mInvalidMenuItem = true;
			if(getCurrentFragment().getTag() != null) mDrawerToggle.setDrawerIndicatorEnabled(true);
		}
	}

	public static void displayBackStack(FragmentManager fm) {
		int count = fm.getBackStackEntryCount();
		Log.d("Backstack log", "There are " + count + " entries");
		for(int i = 0; i<count; i++) {
			// Display Backstack-entry data like
			String name = fm.getBackStackEntryAt(i).getName();
			Log.d("Backstack log", "entry " + i + ": " + name);
		}
	}

	public Intent getServiceIntent() {
		return new Intent(this, HoneyService.class);
	}

	public Fragment getDisplayedFragment() {
		return this.mDisplayedFragment;
	}

	/**
	 * Checks if the phone ist rooted and if porthack is installed. Sets flags
	 * {@link this.isRooted} and {@link this.porthackInstalled}
	 */
	private void checkRootAndPorthack() {
		isRooted = false;
		porthackInstalled = false;
		Process p;
		try {
			String found = "Found";
			String notFound = "Not found";
			String command = "[ -f /data/local/p ] && echo " + found
					+ " || echo " + notFound;
			p = Runtime.getRuntime().exec(new String[] { "su", "-c", command });
			BufferedReader in = new BufferedReader(new InputStreamReader(
					p.getInputStream()));
			/*
			 * int av = byte[] b = new byte[av]; if (av != 0) { in.read(b); }
			 */
			String echoResponse = in.readLine();
			Log.i("MainAc", echoResponse);
			if (echoResponse.equals(found)) {
				isRooted = true;
				porthackInstalled = true;
			} else if (echoResponse.equals(notFound)) {
				isRooted = true;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		Log.i("MainAc", "Rooted: " + isRooted + " Porthack: "
				+ porthackInstalled);
	}

	public HoneyService getHoneyService(){
		return this.mHoneyService;
	}

	public boolean isServiceBound(){
		return this.mServiceBound;
	}

	public boolean isServiceRunning() {
		ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
		for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(
				Integer.MAX_VALUE)) {
			if (service.service.getClassName().equals(
					HoneyService.class.getName())) {
				return true;
			}
		}
		return false;
	}

	public enum MainMenuItem {
        HOME(0),
        THREAT_MAP(1),
        RECORDS(2),
		STATISTICS(3),
        SERVICES(4),
        PROFILE_MANAGER(5),
        SETTINGS(6),
        APPLICATION_INFO(7);

        private int value;

        private MainMenuItem(int value) {
            this.value = value;
        }
        static public MainMenuItem create(int value){
            if (value < 0 || value  >= MainMenuItem.values().length) return MainMenuItem.HOME;
            return  MainMenuItem.values()[value];
        }
		public int getValue() {
			return value;
		}
    }

	private class DrawerItemClickListener implements ListView.OnItemClickListener {
		public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
			displayView(position);
		}
	}
}
