package org.keyscience.BackgroundTask;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.os.AsyncTask;
import android.support.v4.content.LocalBroadcastManager;

import com.google.android.gms.location.Geofence;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.keyscience.R;
import org.keyscience.SingletonPattern.SingletonEcoQuests;
import org.keyscience.SingletonPattern.User;
import org.keyscience.app.Constants;
import org.keyscience.models.EcoQuestModel;
import org.keyscience.network.DatabaseConnection;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Set;

public class EcoQuestJSONLoaderTask extends AsyncTask<String, Integer, Boolean> {

    private WeakReference<GoogleMap> googleMapWeakReference;
    private WeakReference<ArrayList<Geofence>> geoFenceListWeakReference;
    private WeakReference<Context> contextWeakReference;

    public EcoQuestJSONLoaderTask(GoogleMap googleMapWeakReference, ArrayList<Geofence> geoFenceListWeakReference, Context context) {
        this.googleMapWeakReference = new WeakReference<>(googleMapWeakReference);
        this.geoFenceListWeakReference = new WeakReference<>(geoFenceListWeakReference);
        this.contextWeakReference = new WeakReference<>(context);
    }


    @Override
    protected Boolean doInBackground(String... urls) {
        // build singleton HasMap of EcoQuest
        SingletonEcoQuests singletonEcoQuests = SingletonEcoQuests.getInstance();

        if (singletonEcoQuests.size() == 0) {
            //call JSON update on server side
            DatabaseConnection.callPhpPage(urls[0]);
            JSONArray jArray = null;
            try {
                jArray = new JSONArray(DatabaseConnection.getJSON(urls[1]));
            } catch (JSONException e) {
                e.printStackTrace();
                // failed to retrieve JSON for EcoQuests
                return false;
            }

            for (int i = 0; i < jArray.length(); i++) {

                JSONObject json_data = null;
                EcoQuestModel ecoQuestModel = null;
                try {
                    json_data = jArray.getJSONObject(i);

                    ecoQuestModel = new EcoQuestModel(json_data.getInt("ID"), json_data.getInt("Points"),
                            json_data.getString("Name"), json_data.getString("Clue"),
                            json_data.getDouble("Latitude"), json_data.getDouble("Longitude"),
                            json_data.getInt("Max radius (m)"), json_data.getInt("Min Radius (m)"), json_data.getString("General Location Note"),
                            json_data.getString("EducationTitle"), json_data.getString("EducationDescription"),
                            json_data.getString("EducationLearnMore"), json_data.getString("EducationImageURL"));

                    singletonEcoQuests.put(ecoQuestModel.getId(), ecoQuestModel);

                } catch (JSONException e) {
                    e.printStackTrace();
                    e.printStackTrace();
                    // failed to read JSON for EcoQuest Object
                    return false;
                }
            }
            return true;
        }
        return true;
    }

    @Override
    protected void onPostExecute(Boolean success) {
        super.onPostExecute(success);

        if (success) {
            GoogleMap googleMap = googleMapWeakReference.get();
            ArrayList<Geofence> geofenceList = geoFenceListWeakReference.get();
            geofenceList.clear();
            SingletonEcoQuests singletonEcoQuests = SingletonEcoQuests.getInstance();

            //geohunt_ring is an empty bitmap used to make the marker invisible, yet clickable
            BitmapDrawable bitmap = (BitmapDrawable) contextWeakReference.get().getResources().getDrawable(R.drawable.geohunt_ring);
            Bitmap b = bitmap.getBitmap();
            Bitmap event_icon = Bitmap.createScaledBitmap(b, 125, 125, false);

            Set<Integer> keySet = singletonEcoQuests.getHashMap().keySet();


            for (Integer key : keySet) {
                EcoQuestModel ecoQuestModel = singletonEcoQuests.getHashMap().get(key);

                LatLng latLng = new LatLng(ecoQuestModel.getLat(), ecoQuestModel.getLng());

                googleMap.addMarker(new MarkerOptions().position(latLng)
                        .title(ecoQuestModel.getName())
                        .snippet(ecoQuestModel.getClue())
                        .icon(BitmapDescriptorFactory.fromBitmap(event_icon)));


                // this circle represents the area of the geofence using the outer radius
                //Draw circle with different colors for completed quests
                if (User.getInstance().contains(ecoQuestModel.getId())) {
                    googleMap.addCircle(new CircleOptions()
                            .center(latLng)
                            .radius(ecoQuestModel.getMaxRadius())
                            .strokeColor(Color.argb(100, 100, 255, 255))
                            .fillColor(Color.argb(100, 150, 150, 150)));
                } else {
                    googleMap.addCircle(new CircleOptions()
                            .center(latLng)
                            .radius(ecoQuestModel.getMaxRadius())
                            .strokeColor(Color.argb(100, 255, 0, 0))
                            .fillColor(Color.argb(100, 150, 150, 150)));
                }

                // geofence is setup with the Min radius to force user to get closer to the actual coordinates
                geofenceList.add(new Geofence.Builder()
                        // Set the request ID of the geofence. This is a string to identify this
                        // geofence.
                        .setRequestId("" + ecoQuestModel.getId())
                        .setCircularRegion(
                                latLng.latitude,
                                latLng.longitude,
                                ((float) ecoQuestModel.getMinRadius())
                        )
                        .setExpirationDuration(Geofence.NEVER_EXPIRE)
                        .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_DWELL | Geofence.GEOFENCE_TRANSITION_ENTER)
                        .setLoiteringDelay(3000)//send alert if the user stays inside the geofence during this period of time
                        .build());
            }

            // notify that geofences are ready to be watched
            Intent intent = new Intent();
            intent.setAction(Constants.GEOFENCE_ACTION);
            LocalBroadcastManager.getInstance(contextWeakReference.get()).sendBroadcast(intent);
        }
    }
}

