package org.witness.informacam.app.screens;

import info.guardianproject.iocipher.File;
import info.guardianproject.iocipher.camera.StorageManager;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

import org.witness.informacam.InformaCam;
import org.witness.informacam.app.R;
import org.witness.informacam.app.RemoteShareActivity;
import org.witness.informacam.app.screens.popups.SharePopup;
import org.witness.informacam.app.utils.Constants.App.Home;
import org.witness.informacam.app.utils.Constants.HomeActivityListener;
import org.witness.informacam.app.utils.Constants.Preferences;
import org.witness.informacam.app.utils.adapters.GalleryFilterAdapter;
import org.witness.informacam.app.utils.adapters.GalleryGridAdapter;
import org.witness.informacam.json.JSONException;
import org.witness.informacam.models.media.IMedia;
import org.witness.informacam.models.notifications.INotification;
import org.witness.informacam.share.DropboxSyncManager;
import org.witness.informacam.utils.Constants.App.Storage;
import org.witness.informacam.utils.Constants.ListAdapterListener;
import org.witness.informacam.utils.Constants.Models;

import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.CheckBox;
import android.widget.GridView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.Toast;

public class GalleryFragment extends Fragment implements
		OnItemClickListener, OnItemLongClickListener, ListAdapterListener,
		OnItemSelectedListener {
	View rootView;
	GridView mediaDisplayGrid;
	GalleryGridAdapter galleryGridAdapter;

	RelativeLayout noMedia;

	Activity a = null;

	boolean isInMultiSelectMode;
	ArrayList<IMedia> batch = null;
	List<IMedia> listMedia = null;

	private static final String LOG = Home.LOG;
	private final InformaCam informaCam = InformaCam.getInstance();
	private ActionMode mActionMode;
	private static int mCurrentFiltering;
	private MenuItem mMenuItemBatchOperations;
	private View mEncodingMedia;

	private MenuItem miDropbox;
	
	@SuppressWarnings("unused")
	private boolean isDataInitialized;
	
	private ProgressBar progressWait;
	private int mNumLoading;
	
	private int mLastProgress = -1;
	
	private Handler h = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			Bundle b = msg.getData();
			/*
			if(b.containsKey(Models.IMedia.VERSION)) {

				if (b.getString(Models.IMedia.VERSION) != null) {

					mediaExportUris.add(Uri
							.fromFile(new java.io.File(b
									.getString(Models.IMedia.VERSION))));
					
					h.post(new Runnable ()
					{
							public void run ()
							{
								barProgressDialog.incrementProgressBy(1);

								if (barProgressDialog.getProgress() == barProgressDialog.getMax())
								{
									barProgressDialog.dismiss();
									showShareDialog();
								}
								
							}
					});
					
				}
			} else if(b.containsKey(Codes.Keys.UI.PROGRESS)) {
				
			}
			else
			*/
			if (msg.what == -1)
			{				
				String errMsg = b.getString("msg");
				Toast.makeText(a,errMsg, Toast.LENGTH_LONG).show();
			}
		
		}
	};
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setHasOptionsMenu(true);
	}

	@Override
	public View onCreateView(LayoutInflater li, ViewGroup container,
			Bundle savedInstanceState) {
		super.onCreateView(li, container, savedInstanceState);

		rootView = li.inflate(R.layout.fragment_gallery, null);
		mediaDisplayGrid = (GridView) rootView
				.findViewById(R.id.media_display_grid);
		noMedia = (RelativeLayout) rootView
				.findViewById(R.id.media_display_no_media);
		noMedia.setVisibility(View.GONE);
		
		progressWait = (ProgressBar) rootView.findViewById(R.id.progressWait);
		progressWait.setVisibility(View.GONE);
		
		mEncodingMedia = rootView.findViewById(R.id.media_encoding);
		mEncodingMedia.setVisibility(View.GONE);
		mEncodingMedia.findViewById(R.id.ivClose).setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				mEncodingMedia.setVisibility(View.GONE);
			}
		});
		return rootView;
	}

	@Override
	public void onAttach(Activity a) {
		super.onAttach(a);
		this.a = a;
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		initLayout(savedInstanceState);	
	}

	@Override
	public void onResume()
	{
		super.onResume();
		updateAdapters();
		
		DropboxSyncManager.getInstance(a).finishAuthentication();
		
	}

	public void initData() {
		mCurrentFiltering = 0; //All items
		updateData();
	}
	
	public static List<IMedia> getMediaList()
	{

		int sorting = Models.IMediaManifest.Sort.DATE_DESC;
		if (mCurrentFiltering == 1) // Photos
			sorting = Models.IMediaManifest.Sort.TYPE_PHOTO;
		else if (mCurrentFiltering == 2)
			sorting = Models.IMediaManifest.Sort.TYPE_VIDEO;

		List<IMedia> listSource = InformaCam.getInstance().mediaManifest.sortBy(sorting);
		List<IMedia> listMedia = null;

		if (listSource != null) {

			listMedia = new ArrayList<IMedia>(listSource);

			if (mCurrentFiltering == 3) // Tagged items
			{
				for (int i = listMedia.size() - 1; i >= 0; i--) {
					IMedia m = listMedia.get(i);
					boolean hasTags = (m.getInnerLevelRegions().size() > 0);
					if (!hasTags)
						listMedia.remove(i);
				}
			} else if (mCurrentFiltering == 4) // Shared items
			{
				List<INotification> listNotifications = InformaCam.getInstance().notificationsManifest.sortBy(Models.INotificationManifest.Sort.DATE_DESC);

				for (int i = listMedia.size() - 1; i >= 0; i--) {
					boolean hasBeenShared = false;

					IMedia m = listMedia.get(i);
					for (INotification n : listNotifications) {
						if (m._id.equals(n.mediaId)) {
							if (n.type == Models.INotification.Type.SHARED_MEDIA &&
									n.taskComplete) {
								hasBeenShared = true;
								break;
							}
						}
					}
					if (!hasBeenShared)
						listMedia.remove(i);
				}
			} else if (mCurrentFiltering == 5) // encrypted items
			{

				for (int i = listMedia.size() - 1; i >= 0; i--) {

					IMedia m = listMedia.get(i);
					if (m.dcimEntry.fileAsset.source != Storage.Type.IOCIPHER)
						listMedia.remove(i);
				}
			} else if (mCurrentFiltering == 6) // unencrypted items
			{
				if (listMedia != null) {
					for (int i = listMedia.size() - 1; i >= 0; i--) {

						IMedia m = listMedia.get(i);
						if (m.dcimEntry.fileAsset.source != Storage.Type.FILE_SYSTEM)
							listMedia.remove(i);
					}
				}
			}
		}
		
		return listMedia;
	}
	
	private void onMediaListAvailable()
	{
		//progressWait.setVisibility(View.GONE);
		galleryGridAdapter = new GalleryGridAdapter(a, listMedia);
		galleryGridAdapter.setNumLoading(mNumLoading);
		galleryGridAdapter.setInSelectionMode(isInMultiSelectMode);
		if (mediaDisplayGrid != null) {
			mediaDisplayGrid.setAdapter(galleryGridAdapter);
			mediaDisplayGrid.setOnItemLongClickListener(this);
			mediaDisplayGrid.setOnItemClickListener(this);
		}

		updateAdapters();

		if((listMedia != null && listMedia.size() > 0) || this.mNumLoading > 0) {
			if (noMedia != null)
				noMedia.setVisibility(View.GONE);
		} else {

			if (noMedia != null)
				noMedia.setVisibility(View.VISIBLE);
		}
	}
	
	private void updateData()
	{
		Thread getMediaListThread = new Thread(new Runnable()
		{
			@Override
			public void run() {
				listMedia = getMediaList();
				
				if (a != null)
					a.runOnUiThread(new Runnable()
					{
						@Override
						public void run() {
							onMediaListAvailable();
						}
					});
			}
		});
		getMediaListThread.start();
	}

	public void toggleMultiSelectMode(boolean mode) {
		isInMultiSelectMode = mode;
		if (galleryGridAdapter != null)
			galleryGridAdapter.setInSelectionMode(isInMultiSelectMode);
		toggleMultiSelectMode();
	}

	public void toggleMultiSelectMode() {
		// multiSelect.setImageDrawable(a.getResources().getDrawable(isInMultiSelectMode
		// ? R.drawable.ic_action_selected : R.drawable.ic_action_select));
		if (isInMultiSelectMode) {
			batch = new ArrayList<IMedia>();
			// batchEditHolder.setVisibility(View.VISIBLE);
		} else {
			batch = null;
			// batchEditHolder.setVisibility(View.GONE);

		}
		
		if (galleryGridAdapter != null)
			galleryGridAdapter.update(listMedia);
		// galleryListAdapter.update(listMedia);

	}

	private void initLayout(Bundle savedInstanceState) {
		mediaDisplayGrid.removeAllViewsInLayout();
		toggleMultiSelectMode(false);
	}

	@Override
	public boolean onItemLongClick(final AdapterView<?> adapterView, final View view,
			final int position, final long id) {
		
		if (position < mNumLoading)
			return false; // Ignore clicks on incomplete items
		 
		 mActionMode = getActivity().startActionMode(
					mActionModeSelect);


		 h.postDelayed(new Runnable ()
		 {
			 public void run ()
			 {
				int actualPosition = position - mNumLoading;
					
				 onItemClick(adapterView, view, actualPosition, id);
			 }
		 }
		 , 100);
		 
		
		return true;
	}

	@Override
	public void onItemClick(AdapterView<?> adapterView, View view, int position,
			long id) {
		
		if (position < mNumLoading)
			return; // Ignore clicks on incomplete items
		position -= mNumLoading;
		
		if (!isInMultiSelectMode) {
			((HomeActivityListener) a).launchEditor(listMedia.get(position));
		} else {
			try {
				IMedia m = listMedia.get(position);

				if (!m.has(Models.IMedia.TempKeys.IS_SELECTED)) {
					m.put(Models.IMedia.TempKeys.IS_SELECTED, false);
				}

				if (m.getBoolean(Models.IMedia.TempKeys.IS_SELECTED)) {
					m.put(Models.IMedia.TempKeys.IS_SELECTED, false);
					batch.remove(m);
				} else {
					m.put(Models.IMedia.TempKeys.IS_SELECTED, true);
					batch.add(m);
				}

				CheckBox chkSelected = (CheckBox) view
						.findViewById(R.id.chkSelect);
				chkSelected.setChecked(m
						.getBoolean(Models.IMedia.TempKeys.IS_SELECTED));

				if (mActionMode != null)
					mActionMode.invalidate();
				// LinearLayout ll = (LinearLayout)
				// view.findViewById(R.id.gallery_thumb_holder);
				// ll.setBackgroundDrawable(getResources().getDrawable(selectedColor));
			} catch (JSONException e) {
				Log.e(LOG, e.toString());
				e.printStackTrace();
			}
		}

	}
	
	private boolean mIsSelectAll = false;
	
	private void selectAll (boolean select)
	{
		mIsSelectAll = select;
		
		for (IMedia m : listMedia)
		{
			m.put(Models.IMedia.TempKeys.IS_SELECTED, select);
			
			if (select)
				batch.add(m);
			else
				batch.remove(m);

			mediaDisplayGrid.invalidate();
			mActionMode.invalidate();
			updateAdapters();
		}
	}

	private void updateAdapters() {

		if (listMedia != null && galleryGridAdapter != null)
			this.galleryGridAdapter.update(listMedia);

		if ((listMedia != null && listMedia.size() > 0) || this.mNumLoading > 0)
		{
			if (noMedia != null)
				noMedia.setVisibility(View.GONE);
			if (mMenuItemBatchOperations != null)
				mMenuItemBatchOperations.setVisible(true);
		}
		else
		{
			if (noMedia != null)
				noMedia.setVisibility(View.VISIBLE);
			if (mMenuItemBatchOperations != null)
				mMenuItemBatchOperations.setVisible(false);
		}
	}

	@Override
	public void updateAdapter(int which) {
		Log.d(LOG, "UPDATING OUR ADAPTERS");
		if (a != null) {
			updateData();
		}
	}

	
	@Override
	public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
		super.onCreateOptionsMenu(menu, inflater);
		inflater.inflate(R.menu.activity_home_gallery, menu);

		MenuItem menuFilter = menu.findItem(R.id.menu_filter);
		Spinner spinner = (Spinner) menuFilter.getActionView();
		GalleryFilterAdapter spinnerAdapter = new GalleryFilterAdapter(spinner.getContext(), this.getResources().getTextArray(R.array.filter_options));
		spinner.setAdapter(spinnerAdapter);
		spinner.setOnItemSelectedListener(this);
		
		mMenuItemBatchOperations = menu.findItem(R.id.menu_select);
		
		miDropbox = menu.findItem(R.id.menu_remote_access_dropbox);
		DropboxSyncManager dsm = DropboxSyncManager.getInstance(a);
		if (dsm != null && dsm.isSyncing())
			miDropbox.setChecked(true);
		
		ActionBar actionBar = getActivity().getActionBar();
		actionBar.setDisplayShowTitleEnabled(true);
		actionBar.setTitle(R.string.home_gallery_title);
		actionBar.setDisplayShowHomeEnabled(true);
		actionBar.setDisplayHomeAsUpEnabled(false);
		actionBar.setHomeButtonEnabled(true);
		actionBar.setLogo(this.getResources().getDrawable(
				R.drawable.ic_action_up));
		actionBar.setDisplayUseLogoEnabled(true);
		actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case android.R.id.home:
			((HomeActivityListener) a).launchMain();
			return true;
		case R.id.menu_select:
			mActionMode = getActivity().startActionMode(
					mActionModeSelect);
			return true;
		case R.id.menu_remote_access_tor:
			enableOnionShare();
			return true;
		case R.id.menu_remote_access_dropbox:
			manageDropboxSync(!item.isChecked());
			return true;
			
		}
		return super.onOptionsItemSelected(item);
	}

	private final ActionMode.Callback mActionModeSelect = new ActionMode.Callback() {

		// Called when the action mode is created; startActionMode() was called
		@Override
		public boolean onCreateActionMode(ActionMode mode, Menu menu) {
			// Inflate a menu resource providing context menu items
			 MenuInflater inflater = mode.getMenuInflater();
			 inflater.inflate(R.menu.activity_home_gallery_action_mode, menu);
			
			
		//	menu.add(Menu.NONE, R.string.menu_share, 0, R.string.menu_share)
		//		.setIcon(R.drawable.ic_gallery_share);
		//	menu.add(Menu.NONE, R.string.home_gallery_delete, 0,
			//		R.string.home_gallery_delete).setIcon(
				//	R.drawable.ic_gallery_trash);

			toggleMultiSelectMode(true);
			return true;
		}

		// Called each time the action mode is shown. Always called after
		// onCreateActionMode, but
		// may be called multiple times if the mode is invalidated.
		@Override
		public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
			int nSelected = (batch == null) ? 0 : batch.size();
			mode.setTitle(GalleryFragment.this.getString(
					R.string.home_gallery_selected, nSelected));
			
			 
			 MenuItem miDropbox2 = menu.findItem(R.id.menu_remote_access_dropbox);
				DropboxSyncManager dsm = DropboxSyncManager.getInstance(a);
				if (dsm != null && dsm.isSyncing())
					miDropbox2.setChecked(true);
				
			return false; // Return false if nothing is done
		}

		// Called when the user selects a contextual menu item
		@Override
		public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
			
			int shareType = SharePopup.SHARE_TYPE_MEDIA;
			boolean isLocalShare = PreferenceManager.getDefaultSharedPreferences(a).getBoolean("prefExportLocal", false);
			
			switch (item.getItemId()) {
			case R.string.menu_done:
				mode.finish(); // Action picked, so close the CAB
				return true;
			case R.id.menu_home_gallery_select_all:
				selectAll(!mIsSelectAll);
				return true;
			case R.id.menu_share_hash:
				shareHashes();
				return true;
			case R.id.menu_remote_access_tor:
				enableOnionShare();
				return true;
			case R.id.menu_remote_access_dropbox:
				manageDropboxSync(!item.isChecked());
				return true;
			case R.id.menu_share_meta_j3m:
				shareType = SharePopup.SHARE_TYPE_J3M;
			case R.id.menu_share_meta_csv:
				shareType = SharePopup.SHARE_TYPE_CSV;
			case R.id.menu_share:
				
					if (batch.size() > 0)
					{
						new SharePopup(a,batch,false,shareType,isLocalShare);
								
					}
					else
					{

								batch.clear();
								mode.finish();
						
					}						

				return true;
			case R.id.menu_home_gallery_delete:
				((HomeActivityListener) a).waiter(true);
				new Thread(new Runnable() {
					private ActionMode mMode;

					@Override
					public void run() {
						for (IMedia m : batch) {
							m.delete();
						}
						h.post(new Runnable() {
							private ActionMode mMode;

							@Override
							public void run() {
								mMode.finish();
								((HomeActivityListener) a).waiter(false);
								updateData();
							}

							public Runnable init(ActionMode mode) {
								mMode = mode;
								return this;
							}
						}.init(mMode));
					}

					public Runnable init(ActionMode mode) {
						mMode = mode;
						return this;
					}
				}.init(mode)).start();
				return true;
			default:
				return false;
			}
		}

		// Called when the user exits the action mode
		@Override
		public void onDestroyActionMode(ActionMode mode) {
			mActionMode = null;
			toggleMultiSelectMode(false);
			
			DropboxSyncManager dsm = DropboxSyncManager.getInstance(a);
			if (dsm != null && dsm.isSyncing())
				miDropbox.setChecked(true);
			else
				miDropbox.setChecked(false);
		}
	};
	
	private void shareHashes ()
	{
		try
		{
			StringBuffer hexStrings = new StringBuffer();
			
			for (IMedia media : batch)
			{
				String mediaId = ((IMedia) media)._id;
				boolean hasBeenShared = false;
				
				List<INotification> listNotifs = InformaCam.getInstance().notificationsManifest.sortBy(Models.INotificationManifest.Sort.DATE_DESC);
				for (INotification n :listNotifs)
				{
					
					if (mediaId.equals(n.mediaId))
					{
						//this means we sent to an organization, likely the testbed
						if ((n.type == Models.INotification.Type.EXPORTED_MEDIA) &&
							n.taskComplete)
						{
							hasBeenShared = true;
						}
					}
				}
				
				@SuppressWarnings("unused")
				String j3m = ((IMedia) media).buildJ3M(a, false, null);
				
				//generate public hash id from values
				String creatorHash = media.genealogy.createdOnDevice;
				StringBuffer mediaHash = new StringBuffer();
				for(String mHash : media.genealogy.hashes) {
					mediaHash.append(mHash);
				}
				
				MessageDigest md;
				try {
					md = MessageDigest.getInstance("SHA-1");
					md.update((creatorHash+mediaHash.toString()).getBytes());
					
					byte[] byteData = md.digest();
					
					   StringBuffer hexString = new StringBuffer();
				    	for (int i=0;i<byteData.length;i++) {
				    		String hex=Integer.toHexString(0xff & byteData[i]);
				   	     	if(hex.length()==1) hexString.append('0');
				   	     	hexString.append(hex);
				    	}
				    	
				    	hexStrings.append(getString(R.string._id_)).append(hexString).append(' ');
					
				} catch (NoSuchAlgorithmException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
			Intent sendIntent = new Intent();
	    	sendIntent.setAction(Intent.ACTION_SEND);
	    	
	    	//if (!hasBeenShared) //if it hasn't been shared, then just show the hashes
	    	sendIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string._camerav_notarization_id_) + ' ' + hexStrings.toString().trim());
	    	//else //if it has, then show a URL
	    		//sendIntent.putExtra(Intent.EXTRA_TEXT, "#" + getString(R.string.app_name) + " https://j3m.info/submissions/?hashes=" + hexString + " (media:" + mediaHash + ")");
	    	
	    	sendIntent.setType("text/plain");
	    	startActivity(sendIntent);
		}
		catch (Exception e)
		{
			
		}
		
	}

	@Override
	public void setPending(final int numPending, final int numCompleted) {		
		
		if(a == null) {
			return; 
		}
		
		mNumLoading = numPending - numCompleted;
		
		a.runOnUiThread(new Runnable() {
			@Override
			public void run() {
				
				if (galleryGridAdapter != null)
				{
					galleryGridAdapter.setNumLoading(numPending - numCompleted);
				}	
				
				if (numPending > 0 && numCompleted == 0)
				{
					SharedPreferences sp = a.getSharedPreferences(a.getResources().getString(R.string.app_name), Context.MODE_PRIVATE);
					int nTimesShown = sp.getInt(Preferences.Keys.HINT_PROCESSING_IMAGES_SHOWN, 0);
					if (nTimesShown < 3)
					{
						nTimesShown++;
						sp.edit().putInt(Preferences.Keys.HINT_PROCESSING_IMAGES_SHOWN, nTimesShown).commit();
						mEncodingMedia.setVisibility(View.VISIBLE);
					}
				}
				else if (mNumLoading == 0)
				{
					mEncodingMedia.setVisibility(View.GONE);
				}
				
			}
		});
	}

	@Override
	public void onItemSelected(AdapterView<?> adapterView, View view, int itemPosition,
			long itemId) {
		mCurrentFiltering = itemPosition;
		updateAdapter(0);
	}

	@Override
	public void onNothingSelected(AdapterView<?> arg0) {
	}
	
	private void enableOnionShare ()
	{
		Intent intent = new Intent(a, RemoteShareActivity.class);
		
		if (batch != null && batch.size() > 0)
		{
			ArrayList<String> mediaIds = new ArrayList<String>();
			
			for (IMedia media : batch)
				mediaIds.add(media._id);
			
			intent.putExtra("medialist", mediaIds.toArray(new String[mediaIds.size()]));
			
		}
		
		
		startActivity(intent);

	}

	private void manageDropboxSync (boolean enable)
	{
		miDropbox.setChecked(enable);
		
		DropboxSyncManager dsm = DropboxSyncManager.getInstance(a);
		
		if (enable)
		{
			if (!dsm.isSyncing())
			{
				//do web oauth (doesn't require local app)
				boolean isInit = dsm.start(a);
				
				if (isInit) //if init'd, then backup all existing files that aren't already backed up!
				{
					
					if (batch != null)			
						for (IMedia media : batch)
						{				
							dsm.uploadMediaAsync(media);
						}
				}
			}
			
		}
		else
		{
			dsm.stop();
		}
		
		
	}
	
	
}