com.tdispatch.passenger.fragment.ControlCenterFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.tdispatch.passenger.fragment.ControlCenterFragment.java

Source

package com.tdispatch.passenger.fragment;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;

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

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.drawable.AnimationDrawable;
import android.location.Location;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import android.text.format.Time;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;

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.GoogleMap.OnCameraChangeListener;
import com.google.android.gms.maps.GoogleMap.OnMapClickListener;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.PolylineOptions;
import com.tdispatch.passenger.R;
import com.tdispatch.passenger.SearchActivity;
import com.tdispatch.passenger.api.ApiHelper;
import com.tdispatch.passenger.api.ApiResponse;
import com.tdispatch.passenger.common.Const;
import com.tdispatch.passenger.core.TDApplication;
import com.tdispatch.passenger.core.TDFragment;
import com.tdispatch.passenger.fragment.dialog.BookingConfirmationDialogFragment;
import com.tdispatch.passenger.fragment.dialog.BookingConfirmationDialogFragment.BookingConfirmationDialogClickListener;
import com.tdispatch.passenger.fragment.dialog.GenericDialogFragment;
import com.tdispatch.passenger.fragment.dialog.NoLocationDialogFragment;
import com.tdispatch.passenger.host.BookingListHostInterface;
import com.tdispatch.passenger.host.CommonHostInterface;
import com.tdispatch.passenger.host.SlideMenuHostInterface;
import com.tdispatch.passenger.model.AccountData;
import com.tdispatch.passenger.model.ApiSearchLocationData;
import com.tdispatch.passenger.model.BookingData;
import com.tdispatch.passenger.model.LocationData;
import com.tdispatch.passenger.model.PickupAndDropoff;
import com.webnetmobile.tools.GoogleMapRouteHelper;
import com.webnetmobile.tools.JsonTools;
import com.webnetmobile.tools.WebnetLog;
import com.webnetmobile.tools.WebnetTools;

/*
 ******************************************************************************
 *
 * Copyright (C) 2013 T Dispatch Ltd
 *
 * Licensed under the GPL License, Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.gnu.org/licenses/gpl-3.0.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************************
 *
 * @author Marcin Orlowski <marcin.orlowski@webnet.pl>
 *
 ******************************************************************************
*/
public class ControlCenterFragment extends TDFragment implements BookingConfirmationDialogClickListener {
    protected static final String PREFS_KEY_LAST_LOCATION_LAT = "prefs_last_location_lat";
    protected static final String PREFS_KEY_LAST_LOCATION_LNG = "prefs_last_location_lng";

    protected Handler mHandler = new Handler();

    protected LocationData mAddressMapPointsTo = null;

    protected LocationData mPickupAddress = null;
    protected LocationData mDropoffAddress = null;

    protected LocationManager mLocationManager = null;

    @Override
    protected int getLayoutId() {
        return R.layout.control_center_fragment;
    }

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

        mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
    }

    protected Boolean mIitialMapLocationSet = false;

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

        startCabTracking();
        startBookingTracking();

        if (mIitialMapLocationSet == false) {
            Location tmp = getMyLocation();
            LatLng loc = null;
            if (tmp != null) {
                loc = new LatLng(tmp.getLatitude(), tmp.getLongitude());
                mIitialMapLocationSet = true;
            } else {
                double defaultLat = Double
                        .valueOf(getString(R.string.caboffice_default_location_latitude).replace(",", "."));
                double defaultLng = Double
                        .valueOf(getString(R.string.caboffice_default_location_longitude).replace(",", "."));

                String latTmp = mPrefs.getString(PREFS_KEY_LAST_LOCATION_LAT, null);
                String lngTmp = mPrefs.getString(PREFS_KEY_LAST_LOCATION_LNG, null);

                double lat = (latTmp == null) ? defaultLat : Double.valueOf(latTmp);
                double lng = (lngTmp == null) ? defaultLng : Double.valueOf(lngTmp);

                loc = new LatLng(lat, lng);
            }

            moveMapToLocation(loc, true, true);
        }
    }

    @Override
    public void onPause() {
        stopBookingTracking();
        stopCabTracking();

        Location loc = getMyLocation();
        if (loc != null) {
            SharedPreferences.Editor editor = mPrefs.edit();
            editor.putString(PREFS_KEY_LAST_LOCATION_LAT, "" + loc.getLatitude());
            editor.putString(PREFS_KEY_LAST_LOCATION_LNG, "" + loc.getLongitude());
            editor.commit();
        }

        super.onPause();
    }

    protected BookingListHostInterface mBookingListHostActivity;
    protected CommonHostInterface mCommonHostActivity;
    protected SlideMenuHostInterface mSlideMenuHostInterface;

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

        mBookingListHostActivity = (BookingListHostInterface) activity;
        mSlideMenuHostInterface = (SlideMenuHostInterface) activity;
        mCommonHostActivity = (CommonHostInterface) activity;
    }

    @Override
    protected void onPostCreateView() {

        initBusyIndicators();
        showAimPoint(true);

        // try to fix another GMaps v2 related issue
        // http://code.google.com/p/gmaps-api-issues/issues/detail?id=4639
        ViewGroup mapHost = (ViewGroup) mFragmentView.findViewById(R.id.map_container);
        mapHost.requestTransparentRegion(mapHost);

        updateAddresses();
        setUIControlsVisibility(true);

        // disable debug controls
        WebnetTools.setVisibility(mFragmentView, R.id.debug_container,
                TDApplication.isDebuggable() ? View.INVISIBLE : View.INVISIBLE);

        MapFragment mapFragment = (MapFragment) mFragmentManager.findFragmentById(R.id.map_fragment);
        if (mapFragment != null) {
            CameraUpdate cameraUpdate = CameraUpdateFactory.zoomTo(15f);

            GoogleMap map = mapFragment.getMap();

            Location currentPosition = map.getMyLocation();
            if (currentPosition != null) {
                LatLng latLng = new LatLng(currentPosition.getLatitude(), currentPosition.getLongitude());
                cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 15f);
            }
            map.moveCamera(cameraUpdate);

            map.setOnCameraChangeListener(mMapCameraListener);
            map.setOnMapClickListener(mOnMapClickListener);
            map.setOnMyLocationChangeListener(mOnMyLocationChangeListener);
        } else {
            throw new IllegalStateException("Map is not ready");
        }

        WebnetTools.setVisibility(mFragmentView, R.id.price_box_container, View.INVISIBLE);

        int ids[] = { R.id.pickup_location, R.id.dropoff_location,

                R.id.button_mylocation, R.id.button_book, R.id.button_start_new_booking,

                R.id.left_menu_drag_handle, R.id.right_menu_drag_handle,

                R.id.button_set_as_pickup, R.id.button_set_as_dropoff, };
        for (int id : ids) {
            View v = mFragmentView.findViewById(id);
            if (v != null) {
                v.setOnClickListener(mOnClickListener);
            }
        }

        ids = new int[] { R.id.button_set_as_pickup, R.id.button_set_as_dropoff, R.id.button_mylocation };
        for (int id : ids) {
            View v = mFragmentView.findViewById(id);
            if (v != null) {
                v.setOnLongClickListener(mOnLongClickListener);
            }
        }

        // unveil map
        View mapCurtain = mFragmentView.findViewById(R.id.map_curtain);
        mapCurtain.startAnimation(
                AnimationUtils.loadAnimation(TDApplication.getAppContext(), R.anim.map_curtain_fade_out));
    }

    /**[ map related listeners ]**************************************************************************************/

    protected OnCameraChangeListener mMapCameraListener = new OnCameraChangeListener() {
        @Override
        public void onCameraChange(CameraPosition position) {
            mIitialMapLocationSet = true;

            showAimPoint();
            doReverseGeoCoding(position.target);
        }
    };

    protected GoogleMap.OnMapClickListener mOnMapClickListener = new OnMapClickListener() {
        @Override
        public void onMapClick(LatLng point) {
            mIitialMapLocationSet = true;
            showAimPoint(true);
        }
    };

    protected GoogleMap.OnMyLocationChangeListener mOnMyLocationChangeListener = new GoogleMap.OnMyLocationChangeListener() {
        @Override
        public void onMyLocationChange(Location location) {

            if (mIitialMapLocationSet == false) {
                LatLng loc = new LatLng(location.getLatitude(), location.getLongitude());
                moveMapToLocation(loc, false, false);
                mIitialMapLocationSet = true;
            }
        }
    };

    /**[ reverse geocoder ]*******************************************************************************************/

    protected AtomicBoolean mReverseGeoCodingRunning = new AtomicBoolean();
    protected ConcurrentLinkedQueue<LatLng> mReverseQueue = new ConcurrentLinkedQueue<LatLng>();

    protected Boolean isReverseGeoCoderRunning() {
        return mReverseGeoCodingRunning.get();
    }

    protected void doReverseGeoCoding(Location pos) {
        if (pos != null) {
            doReverseGeoCoding(new LatLng(pos.getLatitude(), pos.getLongitude()));
        }
    }

    protected void doReverseGeoCoding(LatLng pos) {
        mReverseQueue.add(pos);

        if (mReverseGeoCodingRunning.compareAndSet(false, true)) {
            mAddressMapPointsTo = null;
            WebnetTools.executeAsyncTask(new ReverseGeoAsyncTask());
        }
    }

    public class ReverseGeoAsyncTask extends AsyncTask<Void, Void, LocationData> {

        @Override
        protected void onPreExecute() {
            showBusy(BUSY_GETTING_MAP_ADDRESS);
            WebnetTools.setText(mFragmentView, R.id.debug_current_address, "ReverseGeoCoding in progress");
        }

        @Override
        protected LocationData doInBackground(Void... params) {

            LocationData result = null;

            do {
                LatLng lastLocation = null;

                while (mReverseQueue.isEmpty() == false) {
                    lastLocation = mReverseQueue.poll();
                }

                result = getReverseUsingGoogleApis(lastLocation);

            } while (mReverseQueue.isEmpty() == false);

            return result;
        }

        @Override
        protected void onPostExecute(LocationData addr) {

            setAddressMapPointsTo(addr);

            if (addr != null) {
                WebnetTools.setText(mFragmentView, R.id.debug_current_address, addr.getAddress());
            } else {
                WebnetTools.setText(mFragmentView, R.id.debug_current_address,
                        "*** Failed to get address of location ***");
            }

            mReverseGeoCodingRunning.set(false);

            hideBusy(BUSY_GETTING_MAP_ADDRESS);
        }

        protected LocationData getReverseUsingGoogleApis(LatLng loc) {

            LocationData result = null;

            String address1 = "", address2 = "", city = "", state = "", country = "", county = "", postCode = "";
            try {
                String url = "http://maps.googleapis.com/maps/api/geocode/json?latlng=" + loc.latitude + ","
                        + loc.longitude + "&sensor=true";

                HttpClient httpclient = new DefaultHttpClient();
                HttpPost httppost = new HttpPost(url);
                HttpResponse response;

                response = httpclient.execute(httppost);
                HttpEntity entity = response.getEntity();
                InputStream is = null;

                is = entity.getContent();
                BufferedReader reader = new BufferedReader(new InputStreamReader(is, "utf-8"), 8);
                StringBuilder sb = new StringBuilder();
                sb.append(reader.readLine() + "\n");
                String line = "0";
                while ((line = reader.readLine()) != null) {
                    sb.append(line + "\n");
                }
                is.close();
                reader.close();

                JSONObject jsonObject = new JSONObject(sb.toString());

                String Status = jsonObject.getString("status");
                if (Status.equalsIgnoreCase("OK")) {
                    JSONArray Results = jsonObject.getJSONArray("results");
                    JSONObject zero = Results.getJSONObject(0);
                    JSONArray addressComponents = zero.getJSONArray("address_components");

                    for (int i = 0; i < addressComponents.length(); i++) {
                        JSONObject zero2 = addressComponents.getJSONObject(i);

                        String longName = zero2.getString("long_name");
                        JSONArray typesArray = zero2.getJSONArray("types");

                        for (int typeIdx = 0; typeIdx < typesArray.length(); typeIdx++) {
                            String singleType = typesArray.getString(typeIdx);

                            if (TextUtils.isEmpty(longName) == false) {

                                if (singleType.equalsIgnoreCase("street_number")) {
                                    address1 = longName + " ";
                                } else if (singleType.equalsIgnoreCase("route")) {
                                    address1 += longName;
                                } else if (singleType.equalsIgnoreCase("sublocality")) {
                                    address2 = longName;
                                } else if (singleType.equalsIgnoreCase("locality")) {
                                    city = longName;
                                } else if (singleType.equalsIgnoreCase("postal_town")) {
                                    city = longName;
                                } else if (singleType.equalsIgnoreCase("administrative_area_level_2")) {
                                    county = longName;
                                } else if (singleType.equalsIgnoreCase("administrative_area_level_1")) {
                                    state = longName;
                                } else if (singleType.equalsIgnoreCase("country")) {
                                    country = longName;
                                } else if (singleType.equalsIgnoreCase("postal_code")) {
                                    postCode = longName;
                                }
                            }
                        }
                    }

                    ApiSearchLocationData tmp = new ApiSearchLocationData();

                    tmp.setAddress(address1);
                    tmp.setTown(city);
                    tmp.setPostCode(postCode);
                    tmp.setCountry(country);
                    tmp.setCounty(county);
                    tmp.setLocation(loc);

                    result = new LocationData(tmp);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }

            return result;
        }
    }

    /**[ busy indicators ]********************************************************************************************/

    protected static final int BUSY_GETTING_ROUTE_AND_PRICE = 1;
    protected static final int BUSY_GETTING_MAP_ADDRESS = 2;

    public void showBusy(int what) {
        doShowHideBusy(what, +1);
    }

    public void hideBusy(int what) {
        doShowHideBusy(what, -1);
    }

    protected int mBookBusyCount = 0;
    protected int mPickupDropoffBusyCount = 0;

    protected void initBusyIndicators() {
        doShowHideBusy(0, 0);
    }

    protected void doShowHideBusy(int what, int step) {

        switch (what) {
        case BUSY_GETTING_MAP_ADDRESS: {
            mPickupDropoffBusyCount += step;
        }
            break;

        case BUSY_GETTING_ROUTE_AND_PRICE: {
            mPickupDropoffBusyCount += step;
            mBookBusyCount += step;
        }
            break;
        }

        View v = mFragmentView.findViewById(R.id.busy_container);
        if (v != null) {
            AnimationDrawable bookBusyAnim = (AnimationDrawable) ((ImageView) mFragmentView.findViewById(R.id.busy))
                    .getBackground();

            if ((mBookBusyCount > 0)) {
                bookBusyAnim.start();
                v.setVisibility(View.VISIBLE);
            } else {
                v.setVisibility(View.GONE);
                bookBusyAnim.stop();
            }
        }

        v = mFragmentView.findViewById(R.id.map_aim_point_busy_container);
        if (v != null) {
            AnimationDrawable mapAimBusyAnim = (AnimationDrawable) ((ImageView) mFragmentView
                    .findViewById(R.id.map_aim_point_busy)).getBackground();
            if ((mPickupDropoffBusyCount > 0)) {
                mapAimBusyAnim.start();
                v.setVisibility(View.VISIBLE);
            } else {
                v.setVisibility(View.GONE);
                mapAimBusyAnim.stop();
            }
        }

    }

    /**[ Get directions ]*********************************************************************************************/

    protected AtomicBoolean mRouteAndFeeRunning = new AtomicBoolean();
    protected ConcurrentLinkedQueue<PickupAndDropoff> mRouteAndFeeQueue = new ConcurrentLinkedQueue<PickupAndDropoff>();

    protected List<LatLng> mRoutePointList = null;
    protected AtomicBoolean mBookingFeeCalculated = new AtomicBoolean();
    protected String mBookingFeePriceFormatted = "";
    protected String mBookingFeeDistanceFormatted = "";

    protected void getRouteAndBookingPrice(LocationData pickup, LocationData dropoff) {

        if ((pickup != null) && (dropoff != null)) {
            mRouteAndFeeQueue.add(new PickupAndDropoff(pickup, dropoff));
            if (mRouteAndFeeRunning.compareAndSet(false, true)) {
                WebnetTools.executeAsyncTask(new GetRouteAndFeeAsyncTask());
            }
        } else {
            refreshMapOverlays();
        }

        //      getRouteAndBookingPrice(
        //                        (pickup != null) ? pickup.getLatLng() : null,
        //                        (dropoff != null) ? dropoff.getLatLng() : null
        //                        );
    }

    //   protected void getRouteAndBookingPrice( LatLng pickup, LatLng dropoff ) {
    //      if( (pickup != null) && (dropoff != null) ) {
    //         mRouteAndFeeQueue.add( new PickupAndDropoff(pickup, dropoff));
    //         if( mRouteAndFeeRunning.compareAndSet(false, true) ) {
    //            WebnetTools.executeAsyncTask( new GetRouteAndFeeAsyncTask() );
    //         }
    //      } else {
    //         refreshMapOverlays();
    //      }
    //   }

    protected class GetRouteAndFeeAsyncTask extends AsyncTask<Void, Void, List<LatLng>> {

        @Override
        protected void onPreExecute() {
            showBusy(BUSY_GETTING_ROUTE_AND_PRICE);
            WebnetTools.setVisibility(mFragmentView, R.id.price_container, View.INVISIBLE);
            WebnetTools.setVisibility(mFragmentView, R.id.price_box_container, View.VISIBLE);

            // clear old route, set new markers
            mRoutePointList = null;
            refreshMapOverlays();
        }

        @Override
        protected List<LatLng> doInBackground(Void... params) {

            List<LatLng> routePointList = null;
            PickupAndDropoff lastLocation = null;

            mBookingFeeCalculated.set(false);

            ApiHelper api = ApiHelper.getInstance(TDApplication.getAppContext());

            do {
                while (mRouteAndFeeQueue.isEmpty() == false) {
                    lastLocation = mRouteAndFeeQueue.poll();
                }

                try {
                    ApiResponse feeResult = api.locationFare(lastLocation.getPickup(), lastLocation.getDropoff());
                    if (feeResult.getErrorCode() == Const.ErrorCode.OK) {

                        JSONObject feeJson = JsonTools.getJSONObject(feeResult.getJSONObject(), "fare");
                        mBookingFeePriceFormatted = JsonTools.getString(feeJson, "formatted_total_cost");

                        JSONObject distJson = JsonTools.getJSONObject(feeJson, "distance");
                        if (WebnetTools.useMetricUnits()) {
                            mBookingFeeDistanceFormatted = String.format(
                                    getString(R.string.journey_distance_metrics_fmt),
                                    JsonTools.getString(distJson, "km"));
                        } else {
                            mBookingFeeDistanceFormatted = String.format(
                                    getString(R.string.journey_distance_imperial_fmt),
                                    JsonTools.getString(distJson, "miles"));
                        }

                        mBookingFeeCalculated.set(true);
                    } else {
                        WebnetLog.e("Failed to get fare from API");
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }

            } while (mRouteAndFeeQueue.isEmpty() == false);

            if (mBookingFeeCalculated.get()) {
                GoogleMapRouteHelper gm = new GoogleMapRouteHelper(lastLocation.getPickup().getLatLng(),
                        lastLocation.getDropoff().getLatLng());
                routePointList = gm.getDirections();
            }

            return routePointList;
        }

        @Override
        protected void onPostExecute(List<LatLng> result) {

            hideBusy(BUSY_GETTING_ROUTE_AND_PRICE);
            WebnetTools.setVisibility(mFragmentView, R.id.price_container, View.VISIBLE);

            mRoutePointList = result;
            refreshMapOverlays();

            if (result == null) {
                WebnetLog.d("Failed to download directions");
            }

            mRouteAndFeeRunning.set(false);
        }
    }

    /*****************************************************************************************************************/

    protected Location getMyLocation() {

        Location result = null;

        MapFragment mapFragment = (MapFragment) mFragmentManager.findFragmentById(R.id.map_fragment);
        if (mapFragment != null) {
            GoogleMap map = mapFragment.getMap();
            if (map != null) {
                result = map.getMyLocation();
            }
        }

        return result;
    }

    protected void showCurrentLocation() {
        showCurrentLocation(false);
    }

    protected void showCurrentLocation(Boolean disableAnimation) {
        moveMapToLocation(null, false, false);
    }

    protected void moveMapToLocation(ApiSearchLocationData addr) {
        if (addr != null) {
            moveMapToLocation(new LatLng(addr.getLatitude(), addr.getLongitude()), true, false);
        }
    }

    public void moveMapToLocation(LocationData location) {
        moveMapToLocation(location, true);
    }

    public void moveMapToLocation(LocationData location, Boolean disableAnimation) {
        if (location != null) {
            moveMapToLocation(new LatLng(location.getLatitude(), location.getLongitude()), disableAnimation, false);
        }
    }

    protected void moveMapToLocation(LatLng location, Boolean disableAnimation, Boolean resetCamera) {

        MapFragment mapFragment = (MapFragment) mFragmentManager.findFragmentById(R.id.map_fragment);
        if (mapFragment != null) {
            GoogleMap map = mapFragment.getMap();
            if (map != null) {

                if (location == null) {
                    Location tmp = map.getMyLocation();
                    if (tmp != null) {
                        location = new LatLng(tmp.getLatitude(), tmp.getLongitude());
                    }
                }

                if (location == null) {
                    Location lastKnownLoc = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                    if (lastKnownLoc == null) {
                        lastKnownLoc = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                    }

                    if (lastKnownLoc != null) {
                        location = new LatLng(lastKnownLoc.getLatitude(), lastKnownLoc.getLongitude());
                    }
                }

                if (location != null) {
                    CameraUpdate cameraUpdate;
                    if (resetCamera) {
                        CameraPosition cameraPosition = new CameraPosition.Builder().target(location).zoom(15f)
                                .bearing(0f).tilt(0).build();
                        cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition);
                    } else {
                        cameraUpdate = CameraUpdateFactory.newLatLng(location);
                    }

                    if (disableAnimation) {
                        map.moveCamera(cameraUpdate);
                    } else {
                        map.animateCamera(cameraUpdate);
                    }
                } else {
                    NoLocationDialogFragment frag = NoLocationDialogFragment.newInstance(
                            GenericDialogFragment.DIALOG_TYPE_ERROR,
                            getString(R.string.unable_to_get_current_location_body),
                            getString(R.string.unable_to_get_current_location_button_show_settings));
                    frag.setTargetFragment(mMe, 0);
                    frag.show(((FragmentActivity) mParentActivity).getSupportFragmentManager(), "nolocationdialog");
                }
            }
        }
    }

    /*****************************************************************************************************************/

    protected View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {

            Boolean result = false;

            switch (v.getId()) {

            case R.id.button_mylocation: {
                moveMapToLocation(null, false, true);
            }
                break;

            case R.id.button_set_as_pickup: {
                if (getPickupAddress() != null) {
                    setPickupAddress(null);
                    updateAddresses();
                }

                result = true;
            }
                break;

            case R.id.button_set_as_dropoff: {
                if (getDropoffAddress() != null) {
                    setDropoffAddress(null);
                    updateAddresses();
                }

                result = true;
            }
                break;
            }

            return result;
        }
    };

    protected View.OnClickListener mOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            int id = v.getId();

            switch (id) {

            case R.id.button_set_as_pickup: {
                LocationData tmp = getAddressMapPointsTo();
                if (tmp != null) {
                    hideAimPoint();
                    setPickupAddress(tmp);
                    updateAddresses();
                } else {
                    showDialog(GenericDialogFragment.DIALOG_TYPE_ERROR, R.string.dialog_error_title,
                            R.string.map_aim_location_unknown_body);
                    //                  TDApplication.playSound(Const.Sound.BUZZ);
                }
            }
                break;

            case R.id.button_set_as_dropoff: {
                LocationData tmp = getAddressMapPointsTo();
                if (tmp != null) {
                    hideAimPoint();
                    setDropoffAddress(tmp);
                    updateAddresses();
                } else {
                    showDialog(GenericDialogFragment.DIALOG_TYPE_ERROR, R.string.dialog_error_title,
                            R.string.map_aim_location_unknown_body);
                    //                  TDApplication.playSound(Const.Sound.BUZZ);
                }
            }
                break;

            case R.id.left_menu_drag_handle: {
                mSlideMenuHostInterface.showLeftMenu();
            }
                break;

            case R.id.right_menu_drag_handle: {
                mSlideMenuHostInterface.showRightMenu();
            }
                break;

            case R.id.button_mylocation: {
                showCurrentLocation(false);
            }
                break;

            case R.id.button_book: {
                Boolean proceed = false;
                Integer errorMsgId = null;

                if (mContext.getResources().getBoolean(R.bool.caboffice_settings_dropoff_location_is_mandatory)) {
                    if ((getPickupAddress() != null) && (getDropoffAddress() != null)) {
                        proceed = true;
                    } else {
                        errorMsgId = R.string.new_booking_both_locations_required_to_place_booking;
                    }
                } else {
                    if (getPickupAddress() != null) {
                        proceed = true;
                    } else {
                        errorMsgId = R.string.new_booking_no_pickup_location_body;
                    }
                }

                if (proceed) {
                    BookingConfirmationDialogFragment frag = BookingConfirmationDialogFragment
                            .newInstance(getPickupAddress(), getDropoffAddress());
                    frag.setTargetFragment(ControlCenterFragment.this, 0);
                    frag.show(((FragmentActivity) mParentActivity).getSupportFragmentManager(),
                            "newbookingconfirmation");
                } else {
                    showDialog(GenericDialogFragment.DIALOG_TYPE_ERROR, R.string.dialog_error_title, errorMsgId);
                }
            }
                break;

            case R.id.button_start_new_booking: {

                if (getAddressMapPointsTo() != null) {
                    setPickupAddress(getAddressMapPointsTo());
                    updateAddresses();
                }

                setUIControlsVisibility(true);
            }
                break;

            case R.id.pickup_location: {
                doAddressSearch(SearchActivity.TYPE_PICKUP, getPickupAddress());
            }
                break;
            case R.id.dropoff_location: {
                doAddressSearch(SearchActivity.TYPE_DROPOFF, getDropoffAddress());
            }

            }
        }
    };

    /**[ BookingConfirmationDialogClickListener ]**********************************************************************/

    @Override
    public void bookingConfirmed(LocationData pickup, LocationData dropoff, Long pickupMillis) {

        int maxDaysAhead = getResources().getInteger(R.integer.caboffice_settings_new_bookings_max_days_ahead);

        Boolean result = false;
        Boolean pickupMillisInvalid = false;
        String pickupMillisBodyId = "";

        if (pickupMillis != null) {
            Long diff = (pickupMillis - System.currentTimeMillis());

            if (diff > 0) {

                if (diff > (WebnetTools.MILLIS_PER_MINUTE * 5)) {
                    if (diff < (WebnetTools.MILLIS_PER_DAY * maxDaysAhead)) {
                        //    keep it
                    } else {
                        pickupMillisBodyId = getString(R.string.new_booking_pickup_date_too_ahead_body_fmt,
                                maxDaysAhead);
                        pickupMillisInvalid = true;
                    }
                } else {
                    pickupMillis = null;
                }

            } else {
                pickupMillisBodyId = getString(R.string.new_booking_pickup_date_already_passed);
                pickupMillisInvalid = true;
            }

        }

        if (pickupMillisInvalid == false) {
            if (mPickupAddress != null) {
                mCommonHostActivity.lockUI();

                // prepare booking
                try {
                    AccountData user = TDApplication.getSessionManager().getAccountData();

                    JSONObject json = new JSONObject();

                    JSONObject passenger = new JSONObject();
                    passenger.put("name", user.getFullName());
                    passenger.put("phone", (user.getPhone() != null) ? user.getPhone() : "");
                    passenger.put("email", (user.getEmail() != null) ? user.getEmail() : "");
                    json.put("passenger", passenger);

                    // pickup location
                    json.put("pickup_location", pickup.toJSON());

                    if (pickupMillis != null) {
                        Time t = new Time();
                        t.set(pickupMillis);

                        String timeStr = t.format3339(false).replace(".000+", "+"); // FIXME API BUG
                        json.put("pickup_time", timeStr);
                    }

                    // dropoff
                    if (mDropoffAddress != null) {
                        json.put("dropoff_location", dropoff.toJSON());
                    }

                    json.put("passengers", 1);
                    json.put("status", "incoming");

                    WebnetTools.executeAsyncTask(new NewBookingAsyncTask(), json);

                    result = true;

                } catch (Exception e) {
                    e.printStackTrace();
                }

            } else {
                showDialog(GenericDialogFragment.DIALOG_TYPE_ERROR, R.string.dialog_error_title,
                        R.string.new_booking_no_pickup_location_body);
            }

        } else {
            showDialog(GenericDialogFragment.DIALOG_TYPE_ERROR, getString(R.string.dialog_error_title),
                    pickupMillisBodyId);
        }

        if (result == false) {
            mCommonHostActivity.unlockUI();
        }

    }

    protected class NewBookingAsyncTask extends AsyncTask<JSONObject, Void, ApiResponse> {

        @Override
        protected void onPreExecute() {
            showBusy(BUSY_GETTING_ROUTE_AND_PRICE);
        }

        @Override
        protected ApiResponse doInBackground(JSONObject... params) {
            JSONObject newBooking = params[0];

            ApiResponse response = new ApiResponse();

            ApiHelper api = ApiHelper.getInstance(TDApplication.getAppContext());
            try {
                response = api.bookingsNewBooking(newBooking);

            } catch (Exception e) {
                e.printStackTrace();
            }

            return response;
        }

        @Override
        protected void onPostExecute(ApiResponse result) {

            if (result.getErrorCode() == Const.ErrorCode.OK) {

                WebnetLog.e("OK OK. Booked: " + result.getJSONObject());

                BookingData placedBooking = new BookingData(
                        JsonTools.getJSONObject(result.getJSONObject(), "booking"));

                // update booking list
                mBookingListHostActivity.addBooking(placedBooking);

                // place booking
                String msg = String.format(getString(R.string.new_booking_body_fmt),
                        placedBooking.getPickupLocation().getAddress());
                showDialog(GenericDialogFragment.DIALOG_TYPE_OK, getString(R.string.new_booking_title), msg);

                // reset UI (addresses)
                mRoutePointList = null;

                setPickupAddress(null);
                setDropoffAddress(null);

                updateAddresses();
                setUIControlsVisibility(false);

                refreshMapOverlays();
            } else {
                showDialog(GenericDialogFragment.DIALOG_TYPE_ERROR, getString(R.string.dialog_error_title),
                        String.format(getString(R.string.new_booking_failed_body_fmt), result.getErrorMessage()));
            }

            hideBusy(BUSY_GETTING_ROUTE_AND_PRICE);
            mCommonHostActivity.unlockUI();
        }
    }

    /*****************************************************************************************************************/

    protected Boolean mAimPointVisible = false;

    protected void hideAimPoint() {
        if (mAimPointVisible) {
            mAimPointVisible = false;

            View v = mFragmentView.findViewById(R.id.map_aim_point_container);
            v.clearAnimation();
            v.startAnimation(AnimationUtils.loadAnimation(mContext, R.anim.fade_out));

            WebnetTools.setVisibility(mFragmentView, R.id.map_aim_point_minimal_container, View.VISIBLE);

            int[] ids = { R.id.button_set_as_pickup, R.id.button_set_as_dropoff };
            for (int id : ids) {
                v = mFragmentView.findViewById(id);
                v.setClickable(false);
                v.setLongClickable(false);
            }
        }
    }

    protected void showAimPoint() {
        if (isUIControlsVisibile()) {
            showAimPoint(false);
        }
    }

    protected void showAimPoint(Boolean animate) {

        if (mAimPointVisible == false) {
            mAimPointVisible = true;

            View v = mFragmentView.findViewById(R.id.map_aim_point_container);
            v.clearAnimation();

            v.startAnimation(
                    AnimationUtils.loadAnimation(mContext, (animate) ? R.anim.fade_in : R.anim.fade_in_instant));

            WebnetTools.setVisibility(mFragmentView, R.id.map_aim_point_minimal_container, View.INVISIBLE);

            int[] ids = { R.id.button_set_as_pickup, R.id.button_set_as_dropoff };
            for (int id : ids) {
                v = mFragmentView.findViewById(id);
                v.setClickable(true);
                v.setLongClickable(true);
            }
        }
    }

    /*****************************************************************************************************************/

    protected void setAddressMapPointsTo(LocationData addr) {
        mAddressMapPointsTo = addr;
    }

    protected LocationData getAddressMapPointsTo() {
        return mAddressMapPointsTo;
    }

    public void setPickupAddress(LocationData addr) {
        if (addr != null) {
            mIitialMapLocationSet = true;
        }
        mPickupAddress = addr;
    }

    public LocationData getPickupAddress() {
        return mPickupAddress;
    }

    public void setDropoffAddress(LocationData addr) {
        if (addr != null) {
            mIitialMapLocationSet = true;
        }
        mDropoffAddress = addr;
    }

    public LocationData getDropoffAddress() {
        return mDropoffAddress;
    }

    public void updateAddresses() {

        LocationData pickup = getPickupAddress();
        LocationData dropoff = getDropoffAddress();

        if (pickup != null) {
            WebnetTools.setText(mFragmentView, R.id.pickup_location, pickup.getAddress());
        } else {
            WebnetTools.setText(mFragmentView, R.id.pickup_location, R.string.pickup_line_default);
        }

        if (dropoff != null) {
            WebnetTools.setText(mFragmentView, R.id.dropoff_location, dropoff.getAddress());
        } else {

            int labelId = R.string.dropoff_line_default;
            if (mContext.getResources().getBoolean(R.bool.caboffice_settings_use_alternative_dropoff_label)) {
                labelId = R.string.dropoff_line_alternative;
            }

            WebnetTools.setText(mFragmentView, R.id.dropoff_location, labelId);
        }

        // calc route if we can
        getRouteAndBookingPrice(pickup, dropoff);

        if ((pickup != null) || (dropoff != null)) {
            if (isUIControlsVisibile() == false) {
                setUIControlsVisibility(true);
            }
        }
    }

    /**[ booking tracking ]*********************************************************************************/

    protected HashMap<String, LatLng> mTrackableBookings = new HashMap<String, LatLng>();

    protected AtomicBoolean mBookingTrackingEnabled = new AtomicBoolean();

    protected void startBookingTracking() {

        if (mContext.getResources().getBoolean(R.bool.caboffice_settings_track_bookings)) {
            if (mBookingTrackingEnabled.compareAndSet(false, true)) {
                mHandler.post(mUpdateBookingTrackingRunnable);
            }
        }
    }

    protected void stopBookingTracking() {
        mHandler.removeCallbacks(mUpdateBookingTrackingRunnable);
        mBookingTrackingEnabled.compareAndSet(true, false);
    }

    protected Runnable mUpdateBookingTrackingRunnable = new Runnable() {
        @Override
        public void run() {
            if (mBookingTrackingEnabled.get()) {
                updateBookingTracking();

                mHandler.postDelayed(this, WebnetTools.MILLIS_PER_WEEK * 15);
            } else {
                WebnetLog.d("Booking tracking disabled");
            }
        }
    };

    protected void updateBookingTracking() {
        if (mTrackableBookings.size() > 0) {
            WebnetTools.executeAsyncTask(new UpdateBookingTrackingAsyncTask(mTrackableBookings));
        }
    }

    protected class UpdateBookingTrackingAsyncTask extends AsyncTask<Void, Void, ApiResponse> {

        protected HashMap<String, LatLng> mBookingsToTrack = null;
        protected HashMap<String, LatLng> mTrackedBookings = null;

        public UpdateBookingTrackingAsyncTask(HashMap<String, LatLng> bookingsToTrack) {
            mBookingsToTrack = bookingsToTrack;
        }

        @Override
        protected ApiResponse doInBackground(Void... params) {

            mTrackedBookings = new HashMap<String, LatLng>();

            ApiResponse response = new ApiResponse();

            try {
                ApiHelper api = ApiHelper.getInstance(TDApplication.getAppContext());

                Iterator<String> iter = (Iterator<String>) mBookingsToTrack.keySet();
                while (iter.hasNext()) {
                    String bookingPk = iter.next();

                    ApiResponse r = api.bookingsTrackBooking(bookingPk);
                    if (r.getErrorCode() == Const.ErrorCode.OK) {

                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }

            return response;
        }

    }

    /**[ nearby taxis ]*************************************************************************************/

    protected AtomicBoolean mCabTrackingEnabled = new AtomicBoolean();

    protected void startCabTracking() {

        if (mContext.getResources().getBoolean(R.bool.caboffice_settings_track_nearby_cabs)) {
            if (mCabTrackingEnabled.compareAndSet(false, true)) {
                mHandler.post(mUpdateNearbyCabsRunnable);
            }
        }
    }

    protected void stopCabTracking() {
        mHandler.removeCallbacks(mUpdateNearbyCabsRunnable);
        mCabTrackingEnabled.compareAndSet(true, false);
    }

    protected ArrayList<LatLng> mNearbyTaxis = null;

    protected Runnable mUpdateNearbyCabsRunnable = new Runnable() {
        @Override
        public void run() {

            if (mCabTrackingEnabled.get()) {
                updateNarbyCabs();

                mHandler.postDelayed(this, WebnetTools.MILLIS_PER_SECOND * 30);
            } else {
                WebnetLog.d("Cab Update disabled");
            }
        }
    };

    protected void updateNarbyCabs() {
        Location pos = getMyLocation();
        if (pos != null) {
            UpdateNearbyCabsAsyncTask task = new UpdateNearbyCabsAsyncTask(pos);
            WebnetTools.executeAsyncTask(task);
        }
    }

    protected class UpdateNearbyCabsAsyncTask extends AsyncTask<Void, Void, ApiResponse> {

        protected ArrayList<LatLng> mTaxis = null;
        protected LatLng mPos;

        public UpdateNearbyCabsAsyncTask(Location position) {
            mPos = new LatLng(position.getLatitude(), position.getLongitude());
        }

        public UpdateNearbyCabsAsyncTask(LatLng position) {
            mPos = position;
        }

        @Override
        protected ApiResponse doInBackground(Void... params) {

            ApiResponse response = new ApiResponse();

            try {
                ApiHelper api = ApiHelper.getInstance(TDApplication.getAppContext());
                response = api.getNearbyDrivers(mPos);

                if (response.getErrorCode() == Const.ErrorCode.OK) {

                    mTaxis = new ArrayList<LatLng>();

                    JSONArray tmp = response.getJSONObject().getJSONArray("drivers");

                    for (int i = 0; i < tmp.length(); i++) {
                        JSONObject item = (JSONObject) tmp.get(i);
                        mTaxis.add(new LatLng(item.getDouble("lat"), item.getDouble("lng")));
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
                response.setErrorCode(Const.ErrorCode.EXCEPTION_ERROR);
                response.setException(e);
            }

            return response;
        }

        @Override
        protected void onPostExecute(ApiResponse response) {
            if (response.getErrorCode() == Const.ErrorCode.OK) {
                mNearbyTaxis = mTaxis;
                refreshMapOverlays();
            }
        }
    }

    /**[ Map overlays ]*************************************************************************************/

    protected void refreshMapOverlays() {

        MapFragment mapFragment = (MapFragment) mFragmentManager.findFragmentById(R.id.map_fragment);
        if (mapFragment != null) {
            GoogleMap map = mapFragment.getMap();
            if (map != null) {
                map.clear();

                // nearby taxis
                if (mNearbyTaxis != null) {
                    for (int i = 0; i < mNearbyTaxis.size(); i++) {
                        map.addMarker(new MarkerOptions().position(mNearbyTaxis.get(i))
                                .icon(BitmapDescriptorFactory.fromResource(R.drawable.map_marker_nearby_cab)));
                    }
                }

                // pickup-dropoff route
                if ((getPickupAddress() != null) && (getDropoffAddress() != null) && (mRoutePointList != null)
                        && (mRoutePointList.size() >= 2)) {
                    LatLng cabPickupLocation = mRoutePointList.get(0);
                    LatLng cabDropoffLocation = mRoutePointList.get(mRoutePointList.size() - 1);

                    MarkerOptions mPickup = new MarkerOptions().position(cabPickupLocation).anchor(0.5f, 0.5f)
                            .icon(BitmapDescriptorFactory.fromResource(R.drawable.map_marker_cab_pickup));
                    map.addMarker(mPickup);

                    MarkerOptions mDestination = new MarkerOptions().position(cabDropoffLocation).anchor(0.5f, 0.5f)
                            .icon(BitmapDescriptorFactory.fromResource(R.drawable.map_marker_cab_dropoff));
                    map.addMarker(mDestination);

                    PolylineOptions rectLine = new PolylineOptions().width(5)
                            .color(getResources().getColor(R.color.map_route_fg));
                    for (int i = 0; i < mRoutePointList.size(); i++) {
                        rectLine.add(mRoutePointList.get(i));
                    }
                    map.addPolyline(rectLine);

                    createDashedLine(map, getPickupAddress().getLatLng(), mRoutePointList.get(0),
                            getResources().getColor(R.color.pickup_location));
                    createDashedLine(map, getDropoffAddress().getLatLng(),
                            mRoutePointList.get(mRoutePointList.size() - 1),
                            getResources().getColor(R.color.dropoff_location));
                }

                if (mPickupAddress != null) {
                    MarkerOptions mPickup = new MarkerOptions().position(mPickupAddress.getLatLng())
                            .icon(BitmapDescriptorFactory.fromResource(R.drawable.map_marker_pickup_big));
                    map.addMarker(mPickup);
                }

                if (mDropoffAddress != null) {
                    MarkerOptions mDestination = new MarkerOptions().position(mDropoffAddress.getLatLng())
                            .icon(BitmapDescriptorFactory.fromResource(R.drawable.map_marker_dropoff));
                    map.addMarker(mDestination);
                }

                // booking fee
                if ((mPickupAddress == null) || (mDropoffAddress == null)) {
                    WebnetTools.setVisibility(mFragmentView, R.id.price_box_container, View.INVISIBLE);
                } else {
                    if (mBookingFeeCalculated.get() == true) {
                        WebnetTools.setText(mFragmentView, R.id.price, mBookingFeePriceFormatted);
                        WebnetTools.setText(mFragmentView, R.id.distance, mBookingFeeDistanceFormatted);
                        WebnetTools.setVisibility(mFragmentView, R.id.price_box_container, View.VISIBLE);
                    } else {
                        WebnetTools.setVisibility(mFragmentView, R.id.price_box_container, View.INVISIBLE);
                    }
                }
            }
        }
    }

    public void createDashedLine(GoogleMap map, LatLng begin, LatLng end, int color) {
        double diffLat = (end.latitude - begin.latitude);
        double diffLng = (end.longitude - begin.longitude);

        double zoom = (map.getCameraPosition().zoom) * 2;

        double divLat = diffLat / zoom;
        double divLng = diffLng / zoom;

        LatLng tmpLat = begin;

        for (int i = 0; i < zoom; i++) {
            LatLng loopLatLng = tmpLat;

            if (i == (zoom - 1)) {
                loopLatLng = end;
            } else {
                if (i > 0) {
                    loopLatLng = new LatLng(tmpLat.latitude + (divLat * 0.25f),
                            tmpLat.longitude + (divLng * 0.25f));
                }
            }

            map.addPolyline(new PolylineOptions().add(loopLatLng)
                    .add(new LatLng(tmpLat.latitude + divLat, tmpLat.longitude + divLng)).color(color).width(5f));

            tmpLat = new LatLng(tmpLat.latitude + divLat, tmpLat.longitude + divLng);
        }
    }

    /*******************************************/

    protected Boolean mUIControlsVisibile = false;

    protected void setUIControlsVisibility(Boolean visible) {

        mUIControlsVisibile = visible;

        if (visible) {
            disableBookingControls(false);
        } else {
            disableBookingControls(true);
        }
    }

    protected Boolean isUIControlsVisibile() {
        return mUIControlsVisibile;
    }

    protected void disableBookingControls(Boolean disabled) {

        WebnetTools.setVisibility(mFragmentView, R.id.booking_addresses_container,
                (disabled) ? View.INVISIBLE : View.VISIBLE);
        WebnetTools.setVisibility(mFragmentView, R.id.bottom_container, (disabled) ? View.INVISIBLE : View.VISIBLE);

        WebnetTools.setVisibility(mFragmentView, R.id.map_aim_point_container,
                (disabled) ? View.INVISIBLE : View.VISIBLE);

        WebnetTools.setVisibility(mFragmentView, R.id.bottom_start_new_booking_container,
                (disabled) ? View.VISIBLE : View.INVISIBLE);

        if (disabled) {
            WebnetTools.setVisibility(mFragmentView, R.id.price_box_container, View.INVISIBLE);
            hideAimPoint();
        } else {
            showAimPoint(true);
        }
    }

    /**[ address search wrapper ]***************************/

    protected void doAddressSearch(int type, LocationData address) {
        Intent intent = new Intent();
        intent.putExtra(Const.Bundle.TYPE, type);
        intent.putExtra(Const.Bundle.LOCATION, address);
        intent.putExtra(Const.Bundle.REQUEST_CODE, Const.RequestCode.ADDRESS_SEARCH);
        intent.setComponent(new ComponentName(mContext.getPackageName(), SearchActivity.class.getName()));
        startActivityForResult(intent, Const.RequestCode.ADDRESS_SEARCH);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {

        switch (requestCode) {

        case Const.RequestCode.ADDRESS_SEARCH: {
            if (resultCode == Activity.RESULT_OK) {

                int type = intent.getExtras().getInt(Const.Bundle.TYPE);
                LocationData location = intent.getExtras().getParcelable(Const.Bundle.LOCATION);

                switch (type) {
                case SearchActivity.TYPE_PICKUP:
                    setPickupAddress(location);
                    break;
                case SearchActivity.TYPE_DROPOFF:
                    setDropoffAddress(location);
                    break;
                }

                updateAddresses();
                moveMapToLocation(location);
            }
        }
            break;

        default: {
            super.onActivityResult(requestCode, resultCode, intent);
        }
            break;
        }
    }

} // end of class