package com.example.techtest;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import javax.net.ssl.SSLPeerUnverifiedException;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONObject;

import android.app.Activity;
import android.app.Fragment;
import android.app.ListFragment;
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.example.techtest.model.CompressVenue;
import com.example.techtest.model.Venue;
import com.google.gson.Gson;

/**
 * A list fragment representing a list of Places. This fragment also supports
 * tablet devices by allowing list items to be given an 'activated' state upon
 * selection. This helps indicate which item is currently being viewed in a
 * {@link PlaceDetailFragment}.
 * <p>
 * Activities containing this fragment MUST implement the {@link Callbacks}
 * interface.
 */
public class PlaceListFragment extends Fragment {

	View rootView;
	ListView lvSearchResults;

	ArrayList <CompressVenue> results;

	Location locAct;
	LocationListener locationListener;

	String TAG = "com.example.techtest.PlaceListFragment";
	/**
	 * The serialization (saved instance state) Bundle key representing the
	 * activated item position. Only used on tablets.
	 */
	private static final String STATE_ACTIVATED_POSITION = "activated_position";

	/**
	 * The fragment's current callback object, which is notified of list item
	 * clicks.
	 */
	private Callbacks mCallbacks = sDummyCallbacks;

	/**
	 * The current activated item position. Only used on tablets.
	 */
	private int mActivatedPosition = ListView.INVALID_POSITION;

	/**
	 * A callback interface that all activities containing this fragment must
	 * implement. This mechanism allows activities to be notified of item
	 * selections.
	 */
	public interface Callbacks {
		/**
		 * Callback for when an item has been selected.
		 */
		public void onItemSelected(double lat, double lng);
	}

	/**
	 * A dummy implementation of the {@link Callbacks} interface that does
	 * nothing. Used only when this fragment is not attached to an activity.
	 */
	private static Callbacks sDummyCallbacks = new Callbacks() {
		public void onItemSelected(double lat, double lng) {
		}
	};

	/**
	 * Mandatory empty constructor for the fragment manager to instantiate the
	 * fragment (e.g. upon screen orientation changes).
	 */
	public PlaceListFragment() {
	}

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

	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		rootView = inflater.inflate(R.layout.fragment_search_layout,
				container, false);

		lvSearchResults = (ListView) rootView.findViewById(R.id.listViewSearchResults);
		final ImageButton searchButton = (ImageButton)rootView.findViewById(R.id.imageButtonSearch);
		final EditText searchText = (EditText)rootView.findViewById(R.id.editTextSearch);

		results = new ArrayList<CompressVenue> ();
		locAct = new Location("");		
		lvSearchResults.setAdapter(new PlacesAdapter());

		searchButton.setOnClickListener(new OnClickListener() {

			public void onClick(View v) { 
				new FourSquareResults().execute(searchText.getText().toString());
			}
		});


		//lvSearchResults.setAdapter();


		return rootView;
	}
	
	@Override
	public void onResume() {
		// Acquire a reference to the system Location Manager
		LocationManager locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);

		// Define a listener that responds to location updates
		locationListener = new LocationListener() {
			public void onLocationChanged(Location location) {
				// Called when a new location is found by the network location provider.
				locAct = location;
			}

			public void onStatusChanged(String provider, int status, Bundle extras) {}

			public void onProviderEnabled(String provider) {}

			public void onProviderDisabled(String provider) {}
		};

		// Register the listener with the Location Manager to receive location updates
		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
		super.onResume();
	}
	
	@Override
	public void onPause() {
		LocationManager locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE); 
		locationManager.removeUpdates(locationListener);
		super.onPause();
	}

	@Override
	public void onViewCreated(View view, Bundle savedInstanceState) {
		super.onViewCreated(view, savedInstanceState);

		// Restore the previously serialized activated item position.
		if (savedInstanceState != null
				&& savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
			setActivatedPosition(savedInstanceState
					.getInt(STATE_ACTIVATED_POSITION));
		}
	}

	@Override
	public void onAttach(Activity activity) {
		super.onAttach(activity);

		// Activities containing this fragment must implement its callbacks.
		if (!(activity instanceof Callbacks)) {
			throw new IllegalStateException(
					"Activity must implement fragment's callbacks.");
		}

		mCallbacks = (Callbacks) activity;
	}

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

		// Reset the active callbacks interface to the dummy implementation.
		mCallbacks = sDummyCallbacks;
	}

	@Override
	public void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		if (mActivatedPosition != ListView.INVALID_POSITION) {
			// Serialize and persist the activated item position.
			outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
		}
	}

	/**
	 * Turns on activate-on-click mode. When this mode is on, list items will be
	 * given the 'activated' state when touched.
	 */
	public void setActivateOnItemClick(boolean activateOnItemClick) {
		// When setting CHOICE_MODE_SINGLE, ListView will automatically
		// give items the 'activated' state when touched.
		lvSearchResults.setChoiceMode(
				activateOnItemClick ? ListView.CHOICE_MODE_SINGLE
						: ListView.CHOICE_MODE_NONE);
	}

	private void setActivatedPosition(int position) {
		if (position == ListView.INVALID_POSITION) {
			lvSearchResults.setItemChecked(mActivatedPosition, false);
		} else {
			lvSearchResults.setItemChecked(position, true);
		}

		mActivatedPosition = position;
	}


	public class FourSquareResults extends AsyncTask<String, Integer, ArrayList<CompressVenue>> {
		private ProgressDialog mProgress;

		@Override
		protected void onPreExecute() {
			mProgress = new ProgressDialog(PlaceListFragment.this.getActivity());
			mProgress.setCancelable(false);
			mProgress.setMessage("Getting venues nearby ...");
			mProgress.show();
			super.onPreExecute();
		}

		@Override
		protected ArrayList<CompressVenue> doInBackground(String... params) {

			String near;
			ArrayList<CompressVenue> venues = new ArrayList<CompressVenue>();
			try {
				near = java.net.URLEncoder.encode(params[0], "UTF-8").replace("+", "%20");

				//date required
				String apiDateVersion = FoursquareConstants.API_DATE_VERSION;
				// Call Foursquare to get the Venues around
				String uri = "https://api.foursquare.com/v2/venues/search"
						+ "?v="
						+ apiDateVersion
						+ "&client_id=" 
						+ FoursquareConstants.CLIENT_ID 
						+ "&client_secret="
						+ FoursquareConstants.CLIENT_SECRET
						+ "&near="
						+ near
						;

				JSONObject venuesJson = executeHttpGet(uri);

				// Get return code
				int returnCode = Integer.parseInt(venuesJson.getJSONObject("meta")
						.getString("code"));
				// 200 = OK
				if (returnCode == 200) {
					Gson gson = new Gson();
					JSONArray json = venuesJson.getJSONObject("response")
							.getJSONArray("venues");
					for (int i = 0; i < json.length(); i++) {
						Venue venue = gson.fromJson(json.getJSONObject(i)
								.toString(), Venue.class);
						CompressVenue cv = new CompressVenue();
						cv.setName(venue.getName());
						if (venue.getCategories()!= null && venue.getCategories().size() >0) {
							cv.setDesc(venue.getCategories().get(0).getName());
							if (venue.getCategories().get(0).getIcon()!=null) {
								cv.setIcon(venue.getCategories().get(0).getIcon().getPrefix() + 100 + venue.getCategories().get(0).getIcon().getSuffix());
							}
						}

						cv.setLat(venue.getLocation().getLat());
						cv.setLng(venue.getLocation().getLng());
						venues.add(cv);
						Log.d(TAG, "->" + gson.toJson(venue));
					}
				} else {
					venuesJson.getJSONObject("meta")
					.getString("errorDetail");
				}

			} catch (SSLPeerUnverifiedException sslExp) {
				sslExp.printStackTrace();
			} catch (Exception exp) {
				exp.printStackTrace();
			}


			return venues;
		}

		@Override
		protected void onPostExecute(ArrayList<CompressVenue> venues) {

			mProgress.dismiss();

			results = venues;
			((PlacesAdapter)lvSearchResults.getAdapter()).notifyDataSetChanged();
			lvSearchResults.invalidate();

			super.onPostExecute(venues);
		}

		// Calls a URI and returns the answer as a JSON object
		private JSONObject executeHttpGet(String uri) throws Exception {
			HttpGet req = new HttpGet(uri);

			HttpClient client = new DefaultHttpClient();
			HttpResponse resLogin = client.execute(req);
			BufferedReader r = new BufferedReader(new InputStreamReader(resLogin
					.getEntity().getContent()));
			StringBuilder sb = new StringBuilder();
			String s = null;
			while ((s = r.readLine()) != null) {
				sb.append(s);
			}

			return new JSONObject(sb.toString());
		}
	}


	/*
	 * This Adapter refreshes the list with the different places 
	 */
	class PlacesAdapter extends BaseAdapter {

		public int getCount() {
			Log.d(TAG, "COUNT:  " + results.size());
			return results.size();
		}

		public Object getItem(int position) {
			return null;
		}

		public long getItemId(int position) {
			return 0;
		}

		public View getView(int position, View convertView, ViewGroup parent) {

			Log.d(TAG, "POSITION: " + position);

			if (convertView == null) {
				convertView = getActivity().getLayoutInflater().inflate(R.layout.place_row, null);
			}

			final CompressVenue ven = results.get(position);

			// Get the location to know the distance
			Location loc = new Location ("");
			loc.setLatitude(ven.getLat());
			loc.setLongitude(ven.getLng());

			// Filling the information
			((TextView)convertView.findViewById(R.id.textViewPlaceName)).setText(ven.getName());
			((TextView)convertView.findViewById(R.id.textViewPlaceDistance)).setText(String.format("%.1f", (loc.distanceTo(locAct)/1000)) + "km");
			((TextView)convertView.findViewById(R.id.textViewDescription)).setText(ven.getDesc());

			((ImageView)convertView.findViewById(R.id.imageViewIconPlace)).setImageResource(R.drawable.ic_action_refresh);
			// Using the image
			try {
				new DownloadImageTask ((ImageView)convertView.findViewById(R.id.imageViewIconPlace)).execute(ven.getIcon());
			} catch (Exception ex) {

			}

			convertView.setOnClickListener(new OnClickListener() {

				public void onClick(View v) {
					mCallbacks.onItemSelected(ven.getLat (), ven.getLng ());
				}
			});
			return convertView;
		}
	}


	private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
		ImageView bmImage;

		public DownloadImageTask(ImageView bmImage) {
			this.bmImage = bmImage;
		}

		protected Bitmap doInBackground(String... urls) {

			String urldisplay = urls[0];
			Bitmap mIcon11 = null;
			if (urldisplay !=null && !"".equals(urldisplay)) {

				try {
					InputStream in = new java.net.URL(urldisplay).openStream();
					mIcon11 = BitmapFactory.decodeStream(in);
				} catch (Exception e) {
					Log.e("Error", e.getMessage());
					e.printStackTrace();
				}
			}
			return mIcon11;
		}

		protected void onPostExecute(Bitmap result) {
			if (result != null)
				bmImage.setImageBitmap(result);
		}
	}
}
