package com.jasonette.seed.Component;

import android.content.Context;
import android.graphics.Point;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;

import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMapOptions;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.MapsInitializer;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.jasonette.seed.Core.JasonViewActivity;
import com.jasonette.seed.Helper.JasonHelper;

import org.json.JSONArray;
import org.json.JSONObject;


public class JasonMapComponent {
    static int EQUATOR_LENGTH = 40075004;

    public static View build(View view, final JSONObject component, final JSONObject parent, final Context context) {
        if(view == null){
            try {
                MapsInitializer.initialize(context);
                GoogleMapOptions options = new GoogleMapOptions();

                LatLng latlng = new LatLng(0, 0);
                if(component.has("region")) {
                    latlng = getCoordinates(component.getJSONObject("region"));
                }
                options.camera(new CameraPosition(latlng, 16, 0, 0));
                JSONObject style = component.getJSONObject("style");
                if (style.has("type")) {
                    switch ((String) style.get("type")) {
                        case "satellite":
                            options.mapType(GoogleMap.MAP_TYPE_SATELLITE);
                            break;
                        case "hybrid":
                            options.mapType(GoogleMap.MAP_TYPE_HYBRID);
                            break;
                        case "terrain":
                            options.mapType(GoogleMap.MAP_TYPE_TERRAIN);
                            break;
                        default:
                            options.mapType(GoogleMap.MAP_TYPE_NORMAL);
                    }
                } else {
                    options.mapType(GoogleMap.MAP_TYPE_NORMAL);
                }
                MapView mapview = new MapView(context, options);
                mapview.onCreate(null); // Trigger onCreate
                ((JasonViewActivity)context).addListViewOnItemTouchListener(touchListener);
                // Add pins when the map is ready
                mapview.getMapAsync(new MapReadyHandler(component, mapview, context));
                return mapview;
            } catch (Exception err) {
                Log.d("Error", err.toString());
            }
        } else {
            try {
                JasonComponent.build(view, component, parent, context);

                JasonHelper.style(component, context);

                JasonComponent.addListener(view, context);
                view.requestLayout();

                ((MapView)view).onResume(); // Trigger onResume
                return view;
            } catch (Exception err){
                Log.d("Error", err.toString());
            }
        }
        return new View(context);
    }

    private static LatLng getCoordinates(JSONObject position) {
        // Calculate latitude and longitude
        double latitude = 0.0;
        double longitude = 0.0;
        try {
            String[] r = position.getString("coord").split(",");
            if (r.length == 2) {
                latitude = Double.parseDouble(r[0]);
                longitude = Double.parseDouble(r[1]);
            }
        } catch (Exception err) {
            Log.d("Error", err.toString());
        }
        return new LatLng(latitude, longitude);
    }

    static class MapReadyHandler implements OnMapReadyCallback {
        private JSONObject component;
        private MapView view;
        private Context context;

        MapReadyHandler(JSONObject component, MapView view, Context context) {
            this.component = component;
            this.view = view;
            this.context = context;
        }

        private double getZoomForMetersWide(final double meters, final double width, final double lat) {
            // Converts metes wide to a zoom level for a google map, got this nice formula from
            // http://stackoverflow.com/a/21034310/1034194
            final double latAdjust = Math.cos(Math.PI * lat / 180.0);

            final double arg = EQUATOR_LENGTH * width * latAdjust / (meters * 256.0);

            return Math.log(arg) / Math.log(2.0);
        }

        @Override
        public void onMapReady(GoogleMap map) {
            try {
                // Add pins to the map
                if (component.has("pins")) {
                    JSONArray pins = component.getJSONArray("pins");
                    for (int i = 0; i < pins.length(); i++) {
                        JSONObject pin = pins.getJSONObject(i);
                        MarkerOptions options = new MarkerOptions();
                        options.position(getCoordinates(pin));
                        if (pin.has("title")) {
                            options.title(pin.getString("title"));
                        }
                        if (pin.has("description")) {
                            options.snippet(pin.getString("description"));
                        }
                        Marker marker = map.addMarker(options);
                        if (pin.has("style")) {
                            JSONObject style = pin.getJSONObject("style");
                            if (style.has("selected") && style.getBoolean("selected")) {
                                marker.showInfoWindow();
                            }
                        }
                    }
                }

                // Move the camera to the zoom level that shows at least the desired region
                if(component.has("region")) {
                    JSONObject region = component.getJSONObject("region");
                    if(region.has("width") && region.has("height")) {
                        double width = region.getDouble("width");
                        double height = region.getDouble("height");
                        JasonViewActivity activity = ((JasonViewActivity) context);
                        DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
                        double viewWidth = view.getLayoutParams().width / metrics.density;
                        double viewHeight = view.getLayoutParams().height / metrics.density;
                        double meters = width;
                        if(height > width && viewHeight > viewWidth) {
                            // Widen the zoom in order to see the requested height
                            meters = height;
                        }
                        double lat = map.getCameraPosition().target.latitude;
                        float zoom = (float)getZoomForMetersWide(meters, viewWidth, lat);
                        map.moveCamera(CameraUpdateFactory.zoomTo(zoom));
                    }
                }
            } catch (Exception err) {
                Log.d("Error", err.toString());
            }
        }
    }

    // Intercept touch events on the RecyclerView to make sure they don't interfere with map moves
    static RecyclerView.SimpleOnItemTouchListener touchListener = new RecyclerView.SimpleOnItemTouchListener() {
        // Intercept touch events on the recycler view, and if they are over a mapview, make sure
        // to let the mapview handle them
        @Override
        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
            LinearLayout layout = (LinearLayout)rv.findChildViewUnder(e.getX(),e.getY());
            if(layout != null) {
                for(int i=0; i<layout.getChildCount(); i++) {
                    View child= layout.getChildAt(i);
                    // Weed out non-map views ASAP
                    if (child.getClass().equals(MapView.class)) {
                        int left = layout.getLeft() + child.getLeft();
                        int right = layout.getLeft() + child.getRight();
                        int top = layout.getTop() + child.getTop();
                        int bottom = layout.getTop() + child.getBottom();
                        if(e.getX() > left && e.getX() < right && e.getY() > top && e.getY() < bottom) {
                            switch (e.getActionMasked()) {
                                // Pressed on map: stop listview from scrolling
                                case MotionEvent.ACTION_DOWN:
                                    rv.requestDisallowInterceptTouchEvent(true);
                                    break;

                                // Released on map or cancelled: listview can be normal again
                                case MotionEvent.ACTION_UP:
                                case MotionEvent.ACTION_CANCEL:
                                    rv.requestDisallowInterceptTouchEvent(false);
                                    break;
                            }
                        }
                    }
                }
            }
            return false;
        }
    };
}
@@ -68,39 +68,8 @@
 xt;%0A
-import android.graphics.Point;%0A
 impo
@@ -272,57 +272,8 @@
 t;%0A%0A
-import com.google.android.gms.maps.CameraUpdate;%0A
 impo

remove unused imports