public class Maps implements OnMapReadyCallback {

    private double currentLatitude;
    private double currentLongitude;
    private float defaultZoom;
    private IMapDataReceiver receiver;
    private IMessageProvider messageProvider;
    GoogleMap map;

    public Maps(CityPickerActivity activity, IMapDataReceiver receiver, IMessageProvider messageProvider) {
        map = null;
        this.receiver = receiver;
        this.messageProvider = messageProvider;
        Coordinate coordinate = PositionManager.getInstance().getCurrentLocationCoordinates();
        try {
            currentLatitude = coordinate.getLatitude();
            currentLongitude = coordinate.getLongitude();
            defaultZoom = 8;
        } catch (NullPointerException e) {
            currentLongitude = 37.59;
            currentLatitude = 55.74;
            defaultZoom = 3;
        }
        ((SupportMapFragment) activity.getSupportFragmentManager().findFragmentById(R.id.map)).getMapAsync(this);
    }

    public void closeDataReceiver() {
        receiver = null;
        messageProvider = null;
    }

    public void setMapSettings(GoogleMap map) {
        map.getUiSettings().setCompassEnabled(true);
        map.getUiSettings().setMyLocationButtonEnabled(true);
        map.getUiSettings().setZoomControlsEnabled(true);
        map.getUiSettings().setAllGesturesEnabled(true);
        if (ActivityCompat.checkSelfPermission(MyApplication.getAppContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            try {
                messageProvider.showToast(R.string.error_gps_permission);
            } catch (NullPointerException e) {
                e.printStackTrace();
            }
            return;
        }
        map.setMyLocationEnabled(true);
    }

    public void setCameraPosition(Coordinate coordinate, float zoom, float bearing, float tilt) {
        setCameraPosition(coordinate.getLatitude(), coordinate.getLongitude(), zoom, bearing, tilt);
    }

    public void setCameraPosition(double latitude, double longitude, float zoom, float bearing, float tilt) {
        CameraPosition cameraPosition = new CameraPosition.Builder()
                .target(new LatLng(latitude, longitude))
                .zoom(zoom)
                .bearing(bearing)
                .tilt(tilt)
                .build();
        CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition);
        map.animateCamera(cameraUpdate);
    }

    public void setNewLatLng(double latitude, double longitude) {
        CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLng(new LatLng(latitude, longitude));
        map.animateCamera(cameraUpdate);
    }

    public double getCurrentLatitude() {
        return map.getCameraPosition().target.latitude;
    }

    public double getCurrentLongitude() {
        return map.getCameraPosition().target.longitude;
    }

    public float getCurrentZoom() {
        return map.getCameraPosition().zoom;
    }

    public float getDefaultZoom() {
        return defaultZoom;
    }

    public void setNewLatLngZoom(double latitude, double longitude, float zoom) {
        CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(latitude, longitude), zoom);
        map.animateCamera(cameraUpdate);
    }

    public void setNewZoom(float zoom) {
        CameraUpdate cameraUpdate = CameraUpdateFactory.zoomTo(zoom);
        map.animateCamera(cameraUpdate);
    }

    public void deleteAllMarkers() {
        map.clear();
    }

    public void setNewMarker(Coordinate coordinate, String text) {
        setNewMarker(coordinate.getLatitude(), coordinate.getLongitude(), text);
    }

    public void setNewMarker(double latitude, double longitude) {
        map.addMarker(new MarkerOptions().position(new LatLng(latitude, longitude)).draggable(false));
    }

    public void setNewMarker(double latitude, double longitude, String text) {
        map.addMarker(new MarkerOptions().position(new LatLng(latitude, longitude)).title(text).draggable(false));
    }

    public void setNewMarker (String city) {
        if (!AppUtils.isNetworkAvailable(MyApplication.getAppContext())) {
            return;
        }
        CoordinateGetter coordinatedGetter = new CoordinateGetter();
        coordinatedGetter.execute(city);
    }

    private void setMapClickListeners(final GoogleMap map) {
        // Клик на маркер
        map.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
            @Override
            public boolean onMarkerClick(Marker marker) {
                try {
                    setCameraPosition(marker.getPosition().latitude, marker.getPosition().longitude, getCurrentZoom(), 0, 0);
                    marker.showInfoWindow();
                    try {
                        receiver.setLocationNameFromMap(marker.getTitle());
                    } catch (NullPointerException e) {
                        e.printStackTrace();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return true;
            }
        });

        // Клик по карте
        map.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
            @Override
            public void onMapClick(LatLng latLng) {
                try {
                    currentLatitude = latLng.latitude;
                    currentLongitude = latLng.longitude;
                    String location = receiver.setLocationCoordinatesFromMap(currentLatitude, currentLongitude);
                    deleteAllMarkers();
                    setNewMarker(currentLatitude, currentLongitude, location);
                } catch (EmptyCurrentAddressException | NullPointerException e) {
                    e.printStackTrace();
                    if (AppUtils.isNetworkAvailable(MyApplication.getAppContext())) {
                        LocationNameGetter locationNameGetter = new LocationNameGetter();
                        locationNameGetter.execute(latLng);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        map = googleMap;
        setMapSettings(googleMap);
        setMapClickListeners(googleMap);
        setCameraPosition(currentLatitude, currentLongitude, defaultZoom, 0, 0);
    }

    class CoordinateGetter extends AsyncTask<String, Void, Position> {


        @Override
        protected Position doInBackground(String... params) {
            GoogleMapsGeocoding googleMapsGeocoding = new GoogleMapsGeocoding();
            Coordinate coordinate = googleMapsGeocoding.requestCoordinatesSynch(params[0]);
            Position position = new Position();
            position.setLocationName(params[0]);
            position.setCoordinate(coordinate);
            return position;
        }

        @Override
        protected void onPostExecute(Position position) {
            super.onPostExecute(position);
            if (position.getCoordinate() != null) {
                deleteAllMarkers();
                setNewMarker(position.getCoordinate().getLatitude(), position.getCoordinate().getLongitude(),position.getLocationName());
                setCameraPosition(position.getCoordinate(),getDefaultZoom(),0,0);
            } else {
                messageProvider.showToast(R.string.invalid_lang_long_used);
            }
        }
    }

    class LocationNameGetter extends AsyncTask<LatLng, Void, Position> {


        @Override
        protected Position doInBackground(LatLng... params) {
            GoogleMapsGeocoding googleMapsGeocoding = new GoogleMapsGeocoding();
            String city = googleMapsGeocoding.requestLocationNameSynch(params[0]);
            Position position = new Position();
            position.setLocationName(city);
            Coordinate coordinate = new Coordinate(params[0].latitude, params[0].longitude);
            position.setCoordinate(coordinate);
            return position;
        }

        @Override
        protected void onPostExecute(Position position) {
            super.onPostExecute(position);
            receiver.setLocation(position.getLocationName());
            deleteAllMarkers();
            setNewMarker(position.getCoordinate().getLatitude(), position.getCoordinate().getLongitude());
            setCameraPosition(position.getCoordinate(),getDefaultZoom(),0,0);
        }
    }
} public class CityPickerAdapter extends HeaderFooterAdapter<String> {

    private List<String> newCities;
    private View.OnClickListener onClickListener;

    public CityPickerAdapter(List<String> itemList, View.OnClickListener onClickListener) {
        super(itemList);
        this.onClickListener = onClickListener;
        this.newCities = new ArrayList<>();
    }

    public void addCityToNewLocationsList(String city) {
        newCities.add(city);
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        RecyclerView.ViewHolder parentHolder = super.onCreateViewHolder(parent, viewType);
        if (parentHolder != null) {
            return parentHolder;
        } else {
            Context context = parent.getContext();
            View view = LayoutInflater.from(context).inflate(R.layout.recycler_item, parent, false);
            return new ViewHolder(view, onClickListener);
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
        if (!(isHeaderPosition(position) || isFooterPosition(position))) {
            ViewHolder holder = (ViewHolder) viewHolder;

            // Единицу отнимаем изза Footer элемента в родителе
            String itemText = itemList.get(position - 1);

            if (newCities.contains(itemText)) {
                holder.markCityAsNew(true);
            } else {
                holder.markCityAsNew(false);
            }
            holder.setItemFavoriteState(PositionManager.getInstance().isFavouriteCity(itemText));
            holder.setItemText(itemText);
        }
    }

    private class ViewHolder extends RecyclerView.ViewHolder {

        private TextView itemTextView;
        private ImageButton itemImageButton;
        private CardView cardView;

        public ViewHolder(View itemView, View.OnClickListener listener) {
            super(itemView);
            cardView = (CardView) itemView;
            itemTextView = (TextView) cardView.findViewById(R.id.cityTW);
            itemImageButton = ((ImageButton) cardView.findViewById(R.id.starBtn));
            itemImageButton.setOnClickListener(listener);
            cardView.setOnClickListener(listener);
        }

        public void setItemText(CharSequence text) {
            itemTextView.setText(text);
        }

        public void setItemFavoriteState(boolean isFavorite) {
            int starImageRes = android.R.drawable.btn_star_big_off;
            if (isFavorite) {
                starImageRes = android.R.drawable.btn_star_big_on;
            }
            itemImageButton.setImageResource(starImageRes);
        }

        public void markCityAsNew(boolean mark) {
            if (mark) {
                cardView.setCardBackgroundColor(ContextCompat.getColor(MyApplication.getAppContext(), R.color.new_city_card));
            } else {
                cardView.setCardBackgroundColor(ContextCompat.getColor(MyApplication.getAppContext(), R.color.city_card_background));
            }
        }
    }
} public abstract class HidingScrollListener extends RecyclerView.OnScrollListener {
    private static final int HIDE_THRESHOLD = 20;
    private int scrolledDistance = 0;
    private boolean controlsVisible = true;

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);

        int firstVisibleItem = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
        //show views if first item is first visible position and views are hidden
        if (firstVisibleItem == 0) {
            if (!controlsVisible) {
                onShow();
                controlsVisible = true;
            }
        } else {
            if (scrolledDistance > HIDE_THRESHOLD && controlsVisible) {
                onHide();
                controlsVisible = false;
                scrolledDistance = 0;
            } else if (scrolledDistance < -HIDE_THRESHOLD && !controlsVisible) {
                onShow();
                controlsVisible = true;
                scrolledDistance = 0;
            }
        }

        if ((controlsVisible && dy > 0) || (!controlsVisible && dy < 0)) {
            scrolledDistance += dy;
        }
    }

    public abstract void onHide();

    public abstract void onShow();

} public class GoogleMapsGeocoding {
    private final static String TAG = GoogleMapsGeocoding.class.getSimpleName();
    private final static String PLACE_API_BASE_URL = "https://maps.googleapis.com/maps/api/geocode/json";
    private final static String API_KEY = MyApplication.getAppContext().getString(R.string.google_maps_geocoding);
    private final static String API = "Google Maps Geocoding API";

    public void requestCoordinates(final String input, final ICoordinateReceiver receiver, final boolean updateTimezone) {
        if (!AppUtils.isNetworkAvailable(MyApplication.getAppContext())) {
            return;
        }
        try {
            final String URL = PLACE_API_BASE_URL + "?key="
                    + API_KEY + "&address="
                    + URLEncoder.encode(input, "utf8");
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    .url(URL)
                    .build();
            Call call = client.newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Request request, IOException e) {
//                    AppUtils.showInfoMessage(MyApplication.getAppContext().getString(R.string.invalid_lang_long_used)).show();
                }

                @Override
                public void onResponse(Response response) throws IOException {
                    String jsonData = response.body().string();
                    String status = "";
                    try {
                        JSONObject jsonObject = new JSONObject(jsonData);
                        JSONArray jsonArray = jsonObject.getJSONArray("results");
                        status = jsonObject.getString("status");
                        if (!status.equals("OK")) {
                            String log = "GoogleMapsGeocoding Async: url <" + URL + ">; response status: <" + status + ">";
                            throw new JSONException(log);
                        }
                        JSONObject jsonGeometry = new JSONObject(jsonArray.getJSONObject(0).getString("geometry"));
                        JSONObject jsonLocation = new JSONObject(jsonGeometry.getString("location"));
                        Coordinate coordinate = new Coordinate();
                        coordinate.setLatitude(Double.parseDouble(jsonLocation.getString("lat")));
                        coordinate.setLongitude(Double.parseDouble(jsonLocation.getString("lng")));
                        receiver.updatePositionCoordinate(input, coordinate);
                        if (updateTimezone) {
                            GoogleMapsTimezone googleMapsTimezone = new GoogleMapsTimezone();
                            googleMapsTimezone.requestCoordinates(input);
                        }
                    } catch (JSONException e) {
//                        AppUtils.showInfoMessage(MyApplication.getAppContext().getString(R.string.invalid_lang_long_used)).show();
                        if (Fabric.isInitialized()) {
                            Crashlytics.logException(e);
                            Answers.getInstance().logCustom(new CustomEvent(AppUtils.ApiCustomEvent)
                                    .putCustomAttribute(API, status));
                        }
                    }
                }
            });
        } catch (UnsupportedEncodingException e) {
//            AppUtils.showInfoMessage(MyApplication.getAppContext().getString(R.string.invalid_lang_long_used)).show();
        }
    }

    public void requestLocationName(final double latitude, final double longitude, final ILocationNameReceiver receiver) {
        if (!AppUtils.isNetworkAvailable(MyApplication.getAppContext())) {
            return;
        }
        try {
            final String systemLanguage = Locale.getDefault().getLanguage();
            final String locationCoordinate = String.valueOf(latitude) + "," + String.valueOf(longitude);
            final String resultType = URLEncoder.encode("administrative_area_level_2|administrative_area_level_1|country", "utf8");
            final String URL = PLACE_API_BASE_URL
                    + "?key=" + API_KEY
                    + "&language=" + systemLanguage
                    + "&result_type=" + resultType
                    + "&latlng=" + URLEncoder.encode(locationCoordinate, "utf8");
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    .url(URL)
                    .build();
            Call call = client.newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Request request, IOException e) {
//                    AppUtils.showInfoMessage(MyApplication.getAppContext().getString(R.string.no_address_found)).show();
                }

                @Override
                public void onResponse(Response response) throws IOException {
                    String jsonData = response.body().string();
                    String status = "";
                    try {
                        JSONObject jsonObject = new JSONObject(jsonData);
                        JSONArray jsonArray = jsonObject.getJSONArray("results");
                        status = jsonObject.getString("status");
                        if (!status.equals("OK")) {
                            String log = "GoogleMapsReverseGeocoding Async: url <" + URL + ">; response status: <" + status + ">";
                            throw new JSONException(log);
                        }
                        receiver.updateLocation(jsonArray.getJSONObject(0).getString("formatted_address"), new Coordinate(latitude, longitude));
                    } catch (JSONException e) {
//                        AppUtils.showInfoMessage(MyApplication.getAppContext().getString(R.string.no_address_found)).show();
                        if (Fabric.isInitialized()) {
                            Crashlytics.logException(e);
                            Answers.getInstance().logCustom(new CustomEvent(AppUtils.ApiCustomEvent)
                                    .putCustomAttribute(API, status));
                        }
                    }
                }
            });
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    public Coordinate requestCoordinatesSynch(final String input) {
        Coordinate coordinate = null;
        String status = "";
        try {
            final String URL = PLACE_API_BASE_URL + "?key="
                    + API_KEY + "&address="
                    + URLEncoder.encode(input, "utf8");
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    .url(URL)
                    .build();
            Response response = client.newCall(request).execute();
            String jsonData = response.body().string();
            JSONObject jsonObject = new JSONObject(jsonData);
            JSONArray jsonArray = jsonObject.getJSONArray("results");
            status = jsonObject.getString("status");
            if (!status.equals("OK")) {
                String log = "GoogleMapsGeocoding: url <" + URL + ">; response status <" + status + ">";
                throw new JSONException(log);
            }
            JSONObject jsonGeometry = new JSONObject(jsonArray.getJSONObject(0).getString("geometry"));
            JSONObject jsonLocation = new JSONObject(jsonGeometry.getString("location"));
            coordinate = new Coordinate();
            coordinate.setLatitude(Double.parseDouble(jsonLocation.getString("lat")));
            coordinate.setLongitude(Double.parseDouble(jsonLocation.getString("lng")));
        } catch (JSONException e) {
            if (Fabric.isInitialized()) {
                Crashlytics.logException(e);
                Answers.getInstance().logCustom(new CustomEvent(AppUtils.ApiCustomEvent)
                        .putCustomAttribute(API, status));
            }
            return null;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        return coordinate;
    }

    public String requestLocationNameSynch(final LatLng coordinates) {
        String status = "";
        try {
            final String systemLanguage = Locale.getDefault().getLanguage();
            final String locationCoordinate = String.valueOf(coordinates.latitude) + "," + String.valueOf(coordinates.longitude);
            final String resultType = URLEncoder.encode("administrative_area_level_2|administrative_area_level_1|country", "utf8");
            final String URL = PLACE_API_BASE_URL
                    + "?key=" + API_KEY
                    + "&language=" + systemLanguage
                    + "&result_type=" + resultType
                    + "&latlng=" + URLEncoder.encode(locationCoordinate, "utf8");
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    .url(URL)
                    .build();
            Response response = client.newCall(request).execute();
            String jsonData = response.body().string();

            JSONObject jsonObject = new JSONObject(jsonData);
            JSONArray jsonArray = jsonObject.getJSONArray("results");
            status = jsonObject.getString("status");
            if (!status.equals("OK")) {
                String log = "GoogleMapsReverseGeocoding: url <" + URL + ">; response status <" + status + ">";
                throw new JSONException(log);
            }
            return jsonArray.getJSONObject(0).getString("formatted_address");
        } catch (JSONException e) {
            if (Fabric.isInitialized()) {
                Crashlytics.logException(e);
                Answers.getInstance().logCustom(new CustomEvent(AppUtils.ApiCustomEvent)
                        .putCustomAttribute(API, status));
            }
            return null;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
} public class GoogleMapsTimezone {
    private final static String TAG = GoogleMapsTimezone.class.getSimpleName();
    private final static String PLACE_API_BASE_URL = "https://maps.googleapis.com/maps/api/timezone/json";
    private final static String API_KEY = MyApplication.getAppContext().getString(R.string.google_maps_timezone);
    private final static String API = "Google Maps Timezone API";

    public void requestCoordinates(final String cityName) {
        final Position position = PositionManager.getInstance().getPosition(cityName);
        if ((position == null) || (position.getCoordinate() == null) || (position.getCoordinate().getLatitude() == 0 && position.getCoordinate().getLongitude() == 0)) {
            return;
        }
        requestCoordinates(position);
    }

    public void requestCoordinates(final Position position) {
        if (!AppUtils.isNetworkAvailable(MyApplication.getAppContext())) {
            return;
        }
        try {
            final String URL = PLACE_API_BASE_URL
                    + "?key=" + API_KEY
                    + "&timestamp=0&location="
                    + URLEncoder.encode(position.getCoordinate().convertToTimezoneUrlParameterString(), "utf8");
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    .url(URL)
                    .build();
            Call call = client.newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Request request, IOException e) {
                    e.printStackTrace();
                }

                @Override
                public void onResponse(Response response) throws IOException {
                    String jsonData = response.body().string();
                    String status = "";
                    try {
                        JSONObject jsonObject = new JSONObject(jsonData);
                        status = jsonObject.getString("status");
                        if (!status.equals("OK")) {
                            String log = "GoogleMapsTimezone: url <" + URL + ">; response status <" + status + ">";
                            throw new JSONException(log);
                        }
                        int timeZoneId = jsonObject.getInt("rawOffset");
                        PositionManager.getInstance().updatePositionTimeZone(position, timeZoneId);
                    } catch (JSONException e) {
                        e.printStackTrace();
                        if (Fabric.isInitialized()) {
                            Crashlytics.logException(e);
                            Answers.getInstance().logCustom(new CustomEvent(AppUtils.ApiCustomEvent)
                                    .putCustomAttribute(API, status));
                        }
                    }
                }
            });
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
} public class EmptyCurrentAddressException extends Exception {
} public class NoAvailableAddressesException extends Exception {
} public interface IMapDataReceiver {
    void setLocationNameFromMap(String name);

    String setLocationCoordinatesFromMap(double latitude, double longitude) throws EmptyCurrentAddressException;

    void setLocation(String city);
} public interface IMessageProvider {

    void showSnackbar(@StringRes int stringId, int length);

    void showSnackbar(CharSequence string, int length);

    void showToast (@StringRes int stringId);

    void showToast (CharSequence string);
} public class LocationParser { // кидать ошибку если нехватает элементов
    List<Address> list;
    String country;
    String region;
    String subRegion;
    String city;

    public LocationParser() {
        this(null);
    }

    public LocationParser(List<Address> list) {
        this.list = list;
        country = null;
        region = null;
        subRegion = null;
        city = null;
    }

    public LocationParser setAddressesList(List<Address> list) {
        this.list = list;
        return this;
    }

    public LocationParser parseList() throws NoAvailableAddressesException {
        if (list == null || list.size() == 0) {
            throw new NoAvailableAddressesException();
        } else {
            for (Address address : list) {
                if (country == null) {
                    country = address.getCountryName();
                }
                if (region == null) {
                    region = address.getAdminArea();
                }
                if (subRegion == null) {
                    subRegion = address.getSubAdminArea();
                }
                if (city == null) {
                    city = address.getLocality();
                }
            }
        }
        return this;
    }

    public String getAddressLine() throws EmptyCurrentAddressException {
        StringBuilder sb = new StringBuilder(20);
        if (city == null) {
            city = "";
        }
        if (subRegion == null) {
            subRegion = "";
        }
        if (region == null) {
            region = "";
        }
        if (country == null) {
            country = "";
        }

        if (city.length() > 0) {
            sb.append(city);
        } else {
            sb.append(subRegion);
        }
        if (sb.length() > 0) {
            sb.append(", ");
        }
        sb.append(region);
        if (sb.length() > 0) {
            sb.append(", ");
        }
        sb.append(country);
        if (sb.length() == 0) {
            throw new EmptyCurrentAddressException();
        }
        return sb.toString();
    }
} public class Coordinate implements Comparable<Coordinate> {
    private double latitude;
    private double longitude;

    public Coordinate(double latitude, double longitude) {
        this.latitude = latitude;
        this.longitude = longitude;
    }

    public Coordinate() {

    }

    public double getLatitude() {
        return latitude;
    }

    public void setLatitude(double latitude) {
        this.latitude = latitude;
    }

    public double getLongitude() {
        return longitude;
    }

    public void setLongitude(double longitude) {
        this.longitude = longitude;
    }

    @Override
    public int compareTo(Coordinate another) {
        if (another == null) {
            return 1;
        }
        if (latitude == another.getLatitude() && longitude == another.getLongitude()) {
            return 0;
        }
        return 1;
    }

    @Override
    public String toString() {
        return "Coordinate{latitude=" + latitude + ", longitude=" + longitude + "}";
    }

    public String convertToTimezoneUrlParameterString() {
        return String.valueOf(latitude) + "," + String.valueOf(longitude);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Coordinate that = (Coordinate) o;

        if (Double.compare(that.latitude, latitude) != 0) return false;
        return Double.compare(that.longitude, longitude) == 0;

    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        temp = Double.doubleToLongBits(latitude);
        result = (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(longitude);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }
} public class PositionManager implements ICoordinateReceiver, ILocationNameReceiver {

    AppUtils.TemperatureMetrics temperatureMetric;
    AppUtils.SpeedMetrics speedMetric;
    AppUtils.PressureMetrics pressureMetric;
    private WeatherStation currStation;
    private volatile Position activePosition;            // Здесь лежит "активная" позиция (которая на данный момент активна на экране)
    private HashMap<WeatherStationFactory.ServiceType, WeatherStation> stations;
    private volatile Position currentPosition; // Здесь лежит текущая по местоположению локация (там где находится пользователь)
    private volatile HashMap<String, Position> positions;
    List<String> favouritesPositions;
    private volatile IWeatherReceiver receiver;
    private volatile IMessageProvider messageProvider;
    private SQLiteProcessData dbManager;
    private boolean lastResponseIsFailure;
    private CurrentLocationManager locationManager;

    private Drawable[] iconsSet;
    IconicsDrawable iconNa = null;
    private boolean isSvgIconsUsed = false;
    private int currentWeatherIconColor;
    private int forecastWeatherIconColor;

    public synchronized void setReceiver(IWeatherReceiver receiver) {
        this.receiver = receiver;
    }

    public synchronized void setMessageProvider(IMessageProvider provider) {
        this.messageProvider = provider;
    }

    private static volatile PositionManager instance;

    private PositionManager() {
        lastResponseIsFailure = false;
        iconNa = new IconicsDrawable(MyApplication.getAppContext())
                .icon(WeatherIcons.Icon.wic_na)
                .sizeDp(80)
                .paddingDp(4);
    }

    public static PositionManager getInstance() {
        if (instance == null) {
            synchronized (PositionManager.class) {
                if (instance == null) {
                    instance = new PositionManager();
                    instance.setReceiver(null);
                    instance.initManager();
                }
            }
        }
        return instance;
    }

    public static PositionManager getInstance(IMessageProvider provider, IWeatherReceiver receiver) {
        if (instance == null) {
            synchronized (PositionManager.class) {
                if (instance == null) {
                    instance = new PositionManager();
                    instance.setMessageProvider(provider);
                    instance.setReceiver(receiver);
                    instance.initManager();
                }
            }
        }
        return instance;
    }

    public synchronized void removeInstance() {
        instance = null;
    }

    public void initManager() {
        dbManager = new SQLiteProcessData();
        temperatureMetric = dbManager.loadTemperatureMetrics();
        speedMetric = dbManager.loadSpeedMetrics();
        pressureMetric = dbManager.loadPressureMetrics();
        initCurrentLocation();
        initPositions();
        initLocationManager();
        initStations();
        updateFavoritesList();
    }

    public void updateFavoritesList() {
        favouritesPositions = dbManager.loadFavoriteTownList();
        Collections.sort(favouritesPositions);
    }

    public List<String> getFavouritesList() {
        return favouritesPositions;
    }

    public boolean flipFavCity(String cityName) {
        boolean state;
        if (isFavouriteCity(cityName)) {
            state = false;
            favouritesPositions.remove(cityName);
        } else {
            state = true;
            favouritesPositions.add(cityName);
            Collections.sort(favouritesPositions);
        }
        dbManager.saveTownFavourite(state, cityName);
        return state;
    }

    public void removeFavoriteCity(String city) {
        if (favouritesPositions != null) {
            favouritesPositions.remove(city);
        }
    }

    public boolean isFavouriteCity(String cityName) {
        try {
            return favouritesPositions.contains(cityName);
        } catch (NullPointerException | ClassCastException e) {
            e.printStackTrace();
            return false;
        }
    }

    public void clearFavorites() {
        if (favouritesPositions != null) {
            favouritesPositions.clear();
        }
    }

    // Пока заглушка, потом настрки сохранять при их смене в настройках
    public void saveSettings() {
        saveCurrStation();
        saveMetrics();
        saveCurrPosition();
    }

    public void saveMetrics() {
        dbManager.saveSettings(temperatureMetric, speedMetric, pressureMetric);
    }

    public void saveCurrPosition() {
        try {
            dbManager.saveLastCurrentLocationName(currentPosition.getLocationName());
            dbManager.saveLastPositionCoordinates(currentPosition.getCoordinate());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void saveCurrStation() {
        dbManager.saveSettings(currStation);
    }

    /**
     * Метод инициализации списка сервисов для получения информации о погодных условиях.
     */
    private void initStations() {
        WeatherStationFactory wsf = new WeatherStationFactory();
        stations = wsf
                .addOpenWeatherMap()
                .create();
        currStation = stations.get(dbManager.loadStation());
    }

    private void initCurrentLocation() {
        currentPosition = new Position();
        currentPosition.setLocationName("Smart Forecast");
        currentPosition.setCityID(0);
        currentPosition.setCoordinate(null);
    }

    /**
     * Метод инициализации списка местоположений, вызывается из активити
     */
    private void initPositions() {
        ArrayList<Position> pos = dbManager.loadTownListFull();
        initPositions(pos);
    }

    /**
     * Метод инициализации списка местоположений, которые добавлены в список городов
     */
    private void initPositions(ArrayList<Position> pos) {
        PositionFactory positionFactory = new PositionFactory();

        if (pos.size() != 0) {
            for (Position entry : pos) {
                positionFactory.addFavouritePosition(entry);
            }
        }
        positions = positionFactory.getPositions();
        for (Position p : positions.values()) {
            if ((p.getCoordinate() == null) || (p.getCoordinate().getLatitude() == 0 && p.getCoordinate().getLongitude() == 0)) {
                GoogleMapsGeocoding googleMapsGeocoding = new GoogleMapsGeocoding();
                googleMapsGeocoding.requestCoordinates(p.getLocationName(), this, false);
            }
            if (!p.timeZoneIsDefined()) {
                GoogleMapsTimezone googleMapsTimezone = new GoogleMapsTimezone();
                googleMapsTimezone.requestCoordinates(p);
            }
        }
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(MyApplication.getAppContext());
        boolean saveCurrentLocation = sp.getString(MyApplication.getAppContext().getString(R.string.pref_location_key), MyApplication.getAppContext().getString(R.string.pref_location_current)).equals(MyApplication.getAppContext().getString(R.string.pref_location_current));
        String lastActivePositionName = sp.getString(MyApplication.getAppContext().getString(R.string.last_active_position_name), "");
        currentPosition.setLocationName(dbManager.loadСurrentTown());
        currentPosition.setCoordinate(dbManager.loadLastPositionCoordinates());
        if (saveCurrentLocation) {
            activePosition = currentPosition;
            boolean isLocationPermissionGranted = Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
                    ContextCompat.checkSelfPermission(MyApplication.getAppContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
            if (!isLocationPermissionGranted) {
                if (!lastActivePositionName.isEmpty() && positionInListPresent(lastActivePositionName)) {
                    activePosition = getPosition(lastActivePositionName);
                }
            }
        } else {
            if (!lastActivePositionName.isEmpty() && positionInListPresent(lastActivePositionName)) {
                activePosition = getPosition(lastActivePositionName);
            } else {
                activePosition = currentPosition;
            }
        }
    }

    /**
     * Метод, с помощью которого добавляем новую локацию в список "Избранных"
     * Вызывается когда пользователь добавляет новый город в список.
     *
     * @param name        объект типа {@link String}, содержащий название города
     * @param coordinates геграфические координаты местоположения
     */
    public void addPosition(String name, Coordinate coordinates) {
        if (positionInListPresent(name)) {
            sendMessage(R.string.city_exist, Snackbar.LENGTH_LONG);
            return;
        }
        PositionFactory positionFactory = new PositionFactory(positions);
        positionFactory.addFavouritePosition(name, coordinates, dbManager);
        positions = positionFactory.getPositions();
    }

    /**
     * Метод, с помощью которого получаем список местоположений
     * Вызывается когда пользователь открывает диалог городов
     *
     * @return возвращает коллекцию {@link Set} типа {@link String}, содержащий названия городов
     */
    public Set<String> getPositions() {
        return positions.keySet();
    }

    public Position getActivePosition() {
        return activePosition;
    }

    /**
     * Метод, с помощью которого удаляем локацию в списка "Избранных"
     * Вызывается, когда пользователь удяляет город из списка
     *
     * @param name объект типа {@link String}, содержащий название города
     */
    public void removePosition(String name) {
        if (positions.containsKey(name)) {
            positions.remove(name);
            dbManager.deleteTown(name);
        }
        if (isFavouriteCity(name)) {
            removeFavoriteCity(name);
        }
    }

    public void removePositions() {
        positions.clear();
        clearFavorites();
        dbManager.deleteTowns();
    }

    /**
     * Метод, с помощью которого получаем название рекущей локации
     *
     * @return возвращает {@link String}, содержащий названия города
     */
    public String getActivePositionCity() {
        if (activePosition == null) {
            return "";
        }
        return activePosition.getLocationName();
    }

    /**
     * Метод, с помощью которого из списка городов выбираем другую локацию в качестве текущей
     *
     * @param city объект типа {@link String}, содержащий название города
     */
    public void setActivePosition(String city) {
        if (city.isEmpty()) {
            activePosition = currentPosition;
        } else if (positions.containsKey(city)) {
            activePosition = positions.get(city);
        } else {
            if (activePosition.getCoordinate() == null || activePosition.getCoordinate().equals(new Coordinate(0, 0))) {
                sendMessage(R.string.error_get_coordinates, Snackbar.LENGTH_LONG);
            }
        }
    }

    public boolean positionInListPresent(String name) {
        try {
            return positions.containsKey(name);
        } catch (ClassCastException | NullPointerException e) {
            e.printStackTrace();
            return false;
        }
    }

    public boolean positionIsPresent(String name) {
        if (currentPosition.getLocationName().equals(name)) {
            return true;
        } else {
            try {
                return positions.containsKey(name);
            } catch (ClassCastException | NullPointerException e) {
                e.printStackTrace();
                return false;
            }
        }
    }

    /**
     * Пролучение локации из списка локаций
     *
     * @param name объект типа {@link String}, хранящий название населенного пункта
     * @return обьект типа {@link Position}
     */

    public Position getPosition(String name) {
        return positions.get(name);
    }

    /**
     * Пролучение локации из списка локаций
     *
     * @param coordinate объект типа {@link Coordinate}, указывающий на местоположение локации
     * @return обьект типа {@link Position}
     */
    private Position getPosition(Coordinate coordinate) {
        for (Position pos : positions.values()) {
            if (pos.getCoordinate().compareTo(coordinate) == 0) {
                return pos;
            }
        }
        return null;
    }

    /**
     * Пролучение локации из списка локаций по внутреннему идентификатору локации
     *
     * @param cityID идентификатор местоположения
     * @return обьект типа {@link Position}
     */
    public Position getPosition(int cityID) {
        if (cityID == 0) {
            return currentPosition;
        }
        for (Position pos : positions.values()) {
            if (pos.getCityID() == cityID) {
                return pos;
            }
        }
        return null;
    }

    public AppUtils.SpeedMetrics getSpeedMetric() {
        return speedMetric;
    }

    public void setSpeedMetric(AppUtils.SpeedMetrics sm) {
        speedMetric = sm;
    }

    public AppUtils.PressureMetrics getPressureMetric() {
        return pressureMetric;
    }

    public void setPressureMetric(AppUtils.PressureMetrics pm) {
        pressureMetric = pm;
    }

    public AppUtils.PressureMetrics changePressureMetric() {
        pressureMetric = pressureMetric.change();
        return pressureMetric;
    }

    public AppUtils.TemperatureMetrics getTemperatureMetric() {
        return temperatureMetric;
    }

    public void setTemperatureMetric(AppUtils.TemperatureMetrics tm) {
        temperatureMetric = tm;
    }

    public AppUtils.TemperatureMetrics changeTemperatureMetric() {
        temperatureMetric = temperatureMetric.change();
        return temperatureMetric;
    }

    /**
     * Метод, вызывемый активити, для обновления текущей погоды от текущей погодной станции
     */
    public void updateWeather() {
        lastResponseIsFailure = false;
        if (activePosition == null || !positionIsPresent(activePosition.getLocationName())) {
            sendMessage(R.string.update_error_location_not_found, Snackbar.LENGTH_LONG);
            return;
        }
        if (activePosition == currentPosition) {
            updateCurrentLocationCoordinates();
            if (currentPosition.getCoordinate() == null) {
                updateWeatherFromDB();
                return;
            }
        }
        sendRequest();
    }

    /**
     * Метод, отправляет запрос на обновление погоды
     */
    public void sendRequest() {
        if (activePosition.getCoordinate() == null) {
            if (!activePosition.getLocationName().isEmpty()) {
                updateWeatherFromDB();
            }
            sendMessage(R.string.coordinates_error, Snackbar.LENGTH_LONG);
        } else if (!AppUtils.isNetworkAvailable(MyApplication.getAppContext())) {
            if (!activePosition.getLocationName().isEmpty()) {
                updateWeatherFromDB();
            }
            sendMessage(R.string.update_error_net_not_available, Snackbar.LENGTH_LONG);
        } else {
            LinkedList<WeatherStation.ResponseType> requestQueue = new LinkedList<>();
            requestQueue.add(WeatherStation.ResponseType.CURRENT);
            try {
                if (receiver.receiveHourlyWeatherFirst()) {
                    requestQueue.addLast(WeatherStation.ResponseType.HOURLY);
                    requestQueue.addLast(WeatherStation.ResponseType.DAILY);
                } else {
                    requestQueue.addLast(WeatherStation.ResponseType.DAILY);
                    requestQueue.addLast(WeatherStation.ResponseType.HOURLY);
                }
                currStation.updateWeather(requestQueue, activePosition.getCityID(), activePosition.getCoordinate());
            } catch (NullPointerException e) {
                // Отсроченный запрос активити уже уничтожено
                e.printStackTrace();
                updateWeatherFromDB();
            }
        }
    }

    public void updateWeatherFromDB(WeatherStation.ResponseType responseType, String positionName) {
        try {
            switch (responseType) {
                case CURRENT:
                    receiver.updateInterface(responseType, getCurrentWeatherFromDB(currStation.getServiceType(), positionName));
                    break;
                case HOURLY:
                    receiver.updateInterface(responseType, getHourlyWeatherFromDB(currStation.getServiceType(), positionName));
                    break;
                case DAILY:
                    receiver.updateInterface(responseType, getDailyWeatherFromDB(currStation.getServiceType(), positionName));
                    break;
            }
        } catch (NullPointerException e) {
            // Отсроченный запрос активити уже уничтожено
            e.printStackTrace();
        }
    }

    public void updateWeatherFromDB(WeatherStation.ResponseType responseType, Position position) {
        try {
            updateWeatherFromDB(responseType, position.getLocationName());
        } catch (NullPointerException e) {
            e.printStackTrace();
        }
    }

    public void updateWeatherFromDB() {
        try {
            updateWeatherFromDB(activePosition.getLocationName());
        } catch (NullPointerException e) {
            e.printStackTrace();
        }
    }

    public void updateWeatherFromDB(String locationName) {
        updateWeatherFromDB(WeatherStation.ResponseType.CURRENT, locationName);
        updateWeatherFromDB(WeatherStation.ResponseType.HOURLY, locationName);
        updateWeatherFromDB(WeatherStation.ResponseType.DAILY, locationName);
    }

    /**
     * Метод для обновления погодных данных. Вызывается погодным сервисом, когда приходят актуальные данные
     *
     * @param requestList коллекция типа {@link LinkedList}, содержащая элементы {@link com.khasang.forecast.stations.WeatherStation.ResponseType}, хранит очередность запросов (текущий прогноз, прогноз на день или неделю)
     * @param cityId      внутренний идентификатор города, передается в погодную станцию во время запроса погоды
     * @param serviceType идентификатор погодного сервиса
     * @param weather     обьект типа {@link Weather}, содержащий погодные характеристики
     */
    public void onResponseReceived(LinkedList<WeatherStation.ResponseType> requestList, int cityId, WeatherStationFactory.ServiceType serviceType, Map<Calendar, Weather> weather) {
        lastResponseIsFailure = false;
        WeatherStation.ResponseType rType = requestList.pollFirst();
        if (rType == null) {
            return;
        }
        Position position = getPosition(cityId);
        if (activePosition.getCityID() == cityId && currStation.getServiceType() == serviceType && position != null) {
            for (Map.Entry<Calendar, Weather> entry : weather.entrySet()) {
                if (rType == WeatherStation.ResponseType.CURRENT) {
                    dbManager.deleteOldWeatherAllTowns(serviceType, entry.getKey());
                    // Для CURRENT погоды сохраняем дополнительно погоду с текущим локальным временем,
                    // иначе возможно расхождение с погодой из БД, например при смене метрик
                    // (ближайшая в БД может отличаться от "текущей" погоды со станции)
                    dbManager.saveWeather(serviceType, position.getLocationName(), Calendar.getInstance(), entry.getValue());
                }
                dbManager.saveWeather(serviceType, position.getLocationName(), entry.getKey(), entry.getValue());
            }

            for (Map.Entry<Calendar, Weather> entry : weather.entrySet()) {
                entry.setValue(AppUtils.formatWeather(entry.getValue(), temperatureMetric, speedMetric, pressureMetric));
            }
            try {
                receiver.updateInterface(rType, weather);
            } catch (NullPointerException e) {
                // Ответ пришел, когда активити уже уничтожено
                e.printStackTrace();
            }

            rType = requestList.peekFirst();
            if (rType == WeatherStation.ResponseType.HOURLY) {
                currStation.updateHourlyWeather(requestList, cityId, position.getCoordinate());
            } else if (rType == WeatherStation.ResponseType.DAILY) {
                currStation.updateWeeklyWeather(requestList, cityId, position.getCoordinate());
            }
        }
    }

    public void onFailureResponse(LinkedList<WeatherStation.ResponseType> requestList, int cityID, WeatherStationFactory.ServiceType sType) {
/*        if (!lastResponseIsFailure) {
            try {
                messageProvider.showToast(MyApplication.getAppContext().getString(R.string.update_error_from) + sType.toString());
            } catch (NullPointerException e) {
                e.printStackTrace();
            }
            lastResponseIsFailure = true;
        }*/
        WeatherStation.ResponseType rType = requestList.pollFirst();
        if (rType == null) {
            return;
        }
        Position position = getPosition(cityID);
        if (activePosition.getCityID() == cityID && currStation.getServiceType() == sType && position != null) {
            updateWeatherFromDB(rType, position);
            rType = requestList.peekFirst();
            if (rType == WeatherStation.ResponseType.HOURLY) {
                currStation.updateHourlyWeather(requestList, cityID, position.getCoordinate());
            } else if (rType == WeatherStation.ResponseType.DAILY) {
                currStation.updateWeeklyWeather(requestList, cityID, position.getCoordinate());
            }
        }
    }

    private HashMap<Calendar, Weather> getCurrentWeatherFromDB(WeatherStationFactory.ServiceType sType, String locationName) {
        return dbManager.loadWeather(sType, locationName, Calendar.getInstance(), temperatureMetric, speedMetric, pressureMetric);
    }

    private HashMap<Calendar, Weather> getHourlyWeatherFromDB(WeatherStationFactory.ServiceType sType, String locationName) {
        final int HOUR_PERIOD = 3;
        final int FORECASTS_COUNT = 8;
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR_OF_DAY, HOUR_PERIOD);
        calendar.set(Calendar.MINUTE, 0);
        HashMap<Calendar, Weather> forecast = new HashMap<>();
        for (int i = 0; i < FORECASTS_COUNT; i++) {
            HashMap<Calendar, Weather> temp = dbManager.loadWeather(sType, locationName, calendar, temperatureMetric, speedMetric, pressureMetric);
            if (temp == null || temp.size() == 0) {
                return null;
            }
            forecast.putAll(temp);
            calendar.add(Calendar.HOUR_OF_DAY, HOUR_PERIOD);
        }
        return forecast;
    }


    private HashMap<Calendar, Weather> getDailyWeatherFromDB(WeatherStationFactory.ServiceType sType, String locationName) {
        final int DAY_PERIOD = 1;
        final int FORECASTS_COUNT = 7;
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 12);
        calendar.set(Calendar.MINUTE, 0);
        HashMap<Calendar, Weather> forecast = new HashMap<>();
        for (int i = 0; i < FORECASTS_COUNT; i++) {
            HashMap<Calendar, Weather> temp = dbManager.loadWeather(sType, locationName, calendar, temperatureMetric, speedMetric, pressureMetric);
            if (temp == null || temp.size() == 0) {
                return null;
            }
            forecast.putAll(temp);
            calendar.add(Calendar.DAY_OF_YEAR, DAY_PERIOD);
        }
        return forecast;
    }

    @Override
    public void updatePositionCoordinate(String city, Coordinate coordinate) {
        Position position = getPosition(city);
        if (position == null) {
            return;
        }
        position.setCoordinate(coordinate);
        dbManager.updatePositionCoordinates(position);
    }

    @Override
    public void updateLocation(String city, Coordinate coordinate) {
        currentPosition.setLocationName(city);
        currentPosition.setCoordinate(coordinate);
        if (activePosition == currentPosition) {
            sendRequest();
        }
    }

    public void updatePositionTimeZone(Position city, int timeZone) {
        city.setTimeZone(timeZone);
        dbManager.updateCityTimeZone(city);
    }

    public void initLocationManager() {
        locationManager = new CurrentLocationManager();
        locationManager.giveGpsAccess(true);
        try {
            updateCurrentLocation(locationManager.getLastLocation());
        } catch (AccessFineLocationNotGrantedException | EmptyCurrentAddressException e) {
            e.printStackTrace();
        }
    }

    public boolean isSomeLocationProviderAvailable() {
        return locationManager.checkProviders();
    }

    public void setUseGpsModule(boolean useGpsModule) {
        locationManager.giveGpsAccess(useGpsModule);
    }

    public void updateCurrentLocationCoordinates() {
        try {
            locationManager.updateCurrLocCoordinates();
        } catch (NoAvailableLocationServiceException e) {
            sendMessage(R.string.error_location_services_are_not_active, Snackbar.LENGTH_LONG);
            e.printStackTrace();
        } catch (GpsIsDisabledException e) {
            sendMessage(R.string.error_gps_disabled, Snackbar.LENGTH_LONG);
            e.printStackTrace();
        } catch (AccessFineLocationNotGrantedException | NullPointerException e) {
            e.printStackTrace();
        }
    }

    public Coordinate getCurrentLocationCoordinates() {
        return currentPosition.getCoordinate();
    }

    public String getCurrentLocationName() {
        return currentPosition.getLocationName();
    }

    public void setCurrentLocationCoordinates(Location location) {
        boolean coordinatesUpdated = updateCurrentLocation(location);
        if (coordinatesUpdated && activePosition == currentPosition) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    sendRequest();
                }
            }, 3000);
        } else if (!coordinatesUpdated) {
            GoogleMapsGeocoding googleMapsGeocoding = new GoogleMapsGeocoding();
            googleMapsGeocoding.requestLocationName(location.getLatitude(), location.getLongitude(), this);
        }
    }

    private boolean updateCurrentLocation(Location location) {
        if (location == null) {
            sendMessage(R.string.error_service_not_available, Snackbar.LENGTH_LONG);
            return false;
        }
        Geocoder geocoder = new Geocoder(MyApplication.getAppContext());
        try {
            List<Address> list = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 3);
            currentPosition.setLocationName(new LocationParser(list).parseList().getAddressLine());
            currentPosition.setCoordinate(new Coordinate(location.getLatitude(), location.getLongitude()));
        } catch (IOException | IllegalArgumentException | EmptyCurrentAddressException | NoAvailableAddressesException | NullPointerException e) {
            e.printStackTrace();
            return false;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    private synchronized void sendMessage(CharSequence string, int length) {
        try {
            messageProvider.showSnackbar(string, length);
        } catch (NullPointerException e) {
            e.printStackTrace();
        }
    }

    private synchronized void sendMessage(int stringId, int length) {
        try {
            messageProvider.showSnackbar(stringId, length);
        } catch (NullPointerException e) {
            e.printStackTrace();
        }
    }

    public void generateIconSet(Context context) {
        iconsSet = AppUtils.createIconsSet(context);
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
        String iconsSet = sp.getString(context.getString(R.string.pref_icons_set_key), context.getString(R.string.pref_icons_set_default));
        currentWeatherIconColor = ContextCompat.getColor(context, R.color.current_weather_color);
        forecastWeatherIconColor = ContextCompat.getColor(context, R.color.text_primary);
        if (iconsSet.equals(context.getString(R.string.pref_icons_set_mike_color))) {
            isSvgIconsUsed = true;
            int currentNightMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
            String colorScheme = sp.getString(context.getString(R.string.pref_color_scheme_key), context.getString(R.string.pref_color_scheme_teal));
            if (currentNightMode == Configuration.UI_MODE_NIGHT_YES) {
            } else if (colorScheme.equals(context.getString(R.string.pref_color_scheme_brown))) {
                forecastWeatherIconColor = ContextCompat.getColor(context, R.color.primary_brown);
            } else if (colorScheme.equals(context.getString(R.string.pref_color_scheme_teal))) {
                forecastWeatherIconColor = ContextCompat.getColor(context, R.color.primary_teal);
            } else if (colorScheme.equals(context.getString(R.string.pref_color_scheme_indigo))) {
                forecastWeatherIconColor = ContextCompat.getColor(context, R.color.primary_indigo);
            } else if (colorScheme.equals(context.getString(R.string.pref_color_scheme_purple))) {
                forecastWeatherIconColor = ContextCompat.getColor(context, R.color.primary_purple);
            } else {
                forecastWeatherIconColor = ContextCompat.getColor(context, R.color.primary_green);
            }
        } else {
            isSvgIconsUsed = iconsSet.equals(context.getString(R.string.pref_icons_set_mike_bw));
        }
    }

    public Drawable getWeatherIcon(int iconNumber, boolean isCurrentWeatherIcon) {
        Drawable icon;
        try {
            if (iconsSet[iconNumber] != null) {
                icon = iconsSet[iconNumber];
                if (isSvgIconsUsed) {
                    if (isCurrentWeatherIcon) {
                        IconicsDrawable cIcon = ((IconicsDrawable) icon).clone();
                        cIcon.color(currentWeatherIconColor);
                        return cIcon;
                    } else {
                        icon = ((IconicsDrawable) icon)
                                .color(forecastWeatherIconColor);
                    }
                }
            } else if (isCurrentWeatherIcon) {
                IconicsDrawable cIcon = ((IconicsDrawable) iconsSet[AppUtils.ICON_INDEX_NA])
                        .clone();
                cIcon.color(currentWeatherIconColor);
                return cIcon;
            } else {
                icon = ((IconicsDrawable) iconsSet[AppUtils.ICON_INDEX_NA])
                        .color(forecastWeatherIconColor);
            }
        } catch (NullPointerException e) {
            e.printStackTrace();
            if (isCurrentWeatherIcon) {
                icon = iconNa.clone();
                ((IconicsDrawable) icon).color(currentWeatherIconColor);
            } else {
                icon = iconNa.color(forecastWeatherIconColor);
            }
        }
        return icon;
    }
} public class AppUtils {

    public static final String ApiCustomEvent = "Error";

    public static final double KELVIN_CELSIUS_DELTA = 273.15;
    public static final double HPA_TO_MM_HG = 1.33322;
    public static final double KM_TO_MILES = 0.62137;
    public static final double METER_TO_FOOT = 3.28083;

    //Icons set
    private static final int ICONS_COUNT = 84;

    public static final int ICON_INDEX_THUNDERSTORM_LIGHT_RAIN = 0;
    public static final int ICON_INDEX_THUNDERSTORM_RAIN = 1;
    public static final int ICON_INDEX_THUNDERSTORM_HEAVY_RAIN = 2;
    public static final int ICON_INDEX_LIGHT_THUNDERSTORM = 3;
    public static final int ICON_INDEX_THUNDERSTORM = 4;
    public static final int ICON_INDEX_HEAVY_THUNDERSTORM = 5;
    public static final int ICON_INDEX_RAGGED_THUNDERSTORM = 6;
    public static final int ICON_INDEX_THUNDERSTORM_LIGHT_DRIZZLE = 7;
    public static final int ICON_INDEX_THUNDERSTORM_DRIZZLE = 8;
    public static final int ICON_INDEX_THUNDERSTORM_HEAVY_DRIZZLE = 9;

    public static final int ICON_INDEX_LIGHT_INTENSITY_DRIZZLE = 10;
    public static final int ICON_INDEX_DRIZZLE = 11;
    public static final int ICON_INDEX_HEAVY_INTENSITY_DRIZZLE = 12;
    public static final int ICON_INDEX_LIGHT_INTENSITY_DRIZZLE_RAIN = 13;
    public static final int ICON_INDEX_DRIZZLE_RAIN = 14;
    public static final int ICON_INDEX_HEAVY_INTENSITY_DRIZZLE_RAIN = 15;
    public static final int ICON_INDEX_SHOWER_RAIN_AND_DRIZZLE = 16;
    public static final int ICON_INDEX_HEAVY_SHOWER_RAIN_AND_DRIZZLE = 17;
    public static final int ICON_INDEX_SHOWER_DRIZZLE = 18;

    public static final int ICON_INDEX_LIGHT_RAIN = 19;
    public static final int ICON_INDEX_MODERATE_RAIN = 20;
    public static final int ICON_INDEX_HEAVY_INTENSITY_RAIN = 21;
    public static final int ICON_INDEX_VERY_HEAVY_RAIN = 22;
    public static final int ICON_INDEX_EXTREME_RAIN = 23;
    public static final int ICON_INDEX_LIGHT_RAIN_NIGHT = 24;
    public static final int ICON_INDEX_MODERATE_RAIN_NIGHT = 25;
    public static final int ICON_INDEX_HEAVY_INTENSITY_RAIN_NIGHT = 26;
    public static final int ICON_INDEX_VERY_HEAVY_RAIN_NIGHT = 27;
    public static final int ICON_INDEX_EXTREME_RAIN_NIGHT = 28;
    public static final int ICON_INDEX_FREEZING_RAIN = 29;
    public static final int ICON_INDEX_LIGHT_INTENSITY_SHOWER_RAIN = 30;
    public static final int ICON_INDEX_SHOWER_RAIN = 31;
    public static final int ICON_INDEX_HEAVY_INTENSITY_SHOWER_RAIN = 32;
    public static final int ICON_INDEX_RAGGED_SHOWER_RAIN = 33;

    public static final int ICON_INDEX_LIGHT_SNOW = 34;
    public static final int ICON_INDEX_SNOW = 35;
    public static final int ICON_INDEX_HEAVY_SNOW = 36;
    public static final int ICON_INDEX_SLEET = 37;
    public static final int ICON_INDEX_SHOWER_SLEET = 38;
    public static final int ICON_INDEX_LIGHT_RAIN_AND_SNOW = 39;
    public static final int ICON_INDEX_RAIN_AND_SNOW = 40;
    public static final int ICON_INDEX_LIGHT_SHOWER_SNOW = 41;
    public static final int ICON_INDEX_SHOWER_SNOW = 42;
    public static final int ICON_INDEX_HEAVY_SHOWER_SNOW = 43;

    public static final int ICON_INDEX_MIST = 44;
    public static final int ICON_INDEX_SMOKE = 45;
    public static final int ICON_INDEX_HAZE = 46;
    public static final int ICON_INDEX_SAND_DUST_WHIRLS = 47;
    public static final int ICON_INDEX_FOG = 48;
    public static final int ICON_INDEX_SAND = 49;
    public static final int ICON_INDEX_DUST = 50;
    public static final int ICON_INDEX_VOLCANIC_ASH = 51;
    public static final int ICON_INDEX_SQUALLS = 52;
    public static final int ICON_INDEX_TORNADO = 53;

    public static final int ICON_INDEX_CLEAR_SKY_SUN = 54;
    public static final int ICON_INDEX_CLEAR_SKY_MOON = 55;

    public static final int ICON_INDEX_FEW_CLOUDS = 56;
    public static final int ICON_INDEX_SCATTERED_CLOUDS = 57;
    public static final int ICON_INDEX_BROKEN_CLOUDS = 58;
    public static final int ICON_INDEX_OVERCAST_CLOUDS = 59;
    public static final int ICON_INDEX_FEW_CLOUDS_NIGHT = 60;
    public static final int ICON_INDEX_SCATTERED_CLOUDS_NIGHT = 61;
    public static final int ICON_INDEX_BROKEN_CLOUDS_NIGHT = 62;
    public static final int ICON_INDEX_OVERCAST_CLOUDS_NIGHT = 63;

    public static final int ICON_INDEX_EXTREME_TORNADO = 64;
    public static final int ICON_INDEX_EXTREME_TROPICAL_STORM = 65;
    public static final int ICON_INDEX_EXTREME_HURRICANE = 66;
    public static final int ICON_INDEX_EXTREME_COLD = 67;
    public static final int ICON_INDEX_EXTREME_HOT = 68;
    public static final int ICON_INDEX_EXTREME_WINDY = 69;
    public static final int ICON_INDEX_EXTREME_HAIL = 70;

    public static final int ICON_INDEX_CALM = 71;
    public static final int ICON_INDEX_LIGHT_BREEZE = 72;
    public static final int ICON_INDEX_GENTLE_BREEZE = 73;
    public static final int ICON_INDEX_MODERATE_BREEZE = 74;
    public static final int ICON_INDEX_FRESH_BREEZE = 75;
    public static final int ICON_INDEX_STRONG_BREEZE = 76;
    public static final int ICON_INDEX_HIGH_WIND_NEAR_GALE = 77;
    public static final int ICON_INDEX_GALE = 78;
    public static final int ICON_INDEX_SEVERE_GALE = 79;
    public static final int ICON_INDEX_STORM = 80;
    public static final int ICON_INDEX_VIOLENT_STORM = 81;
    public static final int ICON_INDEX_HURRICANE = 82;

    public static final int ICON_INDEX_NA = 83;

    public enum TemperatureMetrics {
        KELVIN {
            public TemperatureMetrics change() {
                return CELSIUS;
            }

            public String toStringValue() {
                return MyApplication.getAppContext().getString(R.string.measure_temperature_kelvin);
            }
        },
        CELSIUS {
            public TemperatureMetrics change() {
                return FAHRENHEIT;
            }

            public String toStringValue() {
                return MyApplication.getAppContext().getString(R.string.measure_temperature_celsius);
            }

        },
        FAHRENHEIT {
            public TemperatureMetrics change() {
                return KELVIN;
            }

            public String toStringValue() {
                return MyApplication.getAppContext().getString(R.string.measure_temperature_fahrenheit);
            }
        };

        public abstract TemperatureMetrics change();

        public abstract String toStringValue();
    }

    public enum SpeedMetrics {
        METER_PER_SECOND {
            @Override
            public String toStringValue() {
                return MyApplication.getAppContext().getString(R.string.measure_speed_m_s);
            }
        },
        FOOT_PER_SECOND {
            @Override
            public String toStringValue() {
                return MyApplication.getAppContext().getString(R.string.measure_speed_fps);
            }
        },
        KM_PER_HOURS {
            @Override
            public String toStringValue() {
                return MyApplication.getAppContext().getString(R.string.measure_speed_km_h);
            }
        },
        MILES_PER_HOURS {
            @Override
            public String toStringValue() {
                return MyApplication.getAppContext().getString(R.string.measure_speed_mph);
            }
        };

        public abstract String toStringValue();
    }

    public enum PressureMetrics {
        HPA {
            public PressureMetrics change() {
                return MM_HG;
            }

            @Override
            public String toStringValue() {
                return MyApplication.getAppContext().getString(R.string.measure_pressure_hpa);
            }
        },
        MM_HG {
            public PressureMetrics change() {
                return HPA;
            }

            @Override
            public String toStringValue() {
                return MyApplication.getAppContext().getString(R.string.measure_pressure_mmHg);
            }
        };

        public abstract PressureMetrics change();

        public abstract String toStringValue();
    }

    public static void showSnackBar(Activity activity, View view, CharSequence string, int length) {
        if (view == null) {
            if (activity != null) {
                showInfoMessage(activity, string).show();
            } else {
                showInfoMessage(string).show();
            }
            return;
        }
        Snackbar snackbar = Snackbar.make(view, string, length);
        View snackbarView = snackbar.getView();
        //        Default background fill: #323232 100%
        //        snackbarView.setBackgroundColor(ContextCompat.getColor(MyApplication.getAppContext(), R.color.primary_dark));
        TextView textView = (TextView) snackbarView.findViewById(android.support.design.R.id.snackbar_text);
        textView.setTextColor(ContextCompat.getColor(MyApplication.getAppContext(), R.color.snackbar_text));
        snackbar.show();
    }

    public static Toast showInfoMessage(Activity activity, CharSequence string) {
        LayoutInflater inflater = activity.getLayoutInflater();
        View layout = inflater.inflate(R.layout.warning_toast, ((ViewGroup) activity.findViewById(R.id.toast_layout_root)));
        ((TextView) layout.findViewById(R.id.warningMessage)).setText(string);
        Toast toast = new Toast(MyApplication.getAppContext());
        toast.setDuration(Toast.LENGTH_SHORT);
        toast.setView(layout);
        return toast;
    }

    public static Toast showInfoMessage(CharSequence string) {
        return Toast.makeText(MyApplication.getAppContext(), string, Toast.LENGTH_SHORT);
    }


    /**
     * Метод для конвертирования ответа от API в коллекцию типа {@link Map}<{@link Calendar}, {@link Weather}>
     * для запроса текущего прогноза погоды.
     *
     * @param response объект типа {@link OpenWeatherMapResponse}, содержащий ответ от API.
     * @param cityID
     */
    public static Map<Calendar, Weather> convertToWeather(OpenWeatherMapResponse response, int cityID) {
        Map<Calendar, Weather> map = new HashMap<>();
        Weather weather = new Weather();
        int offset = PositionManager.getInstance().getPosition(cityID).getTimeZone();
        Calendar calendar = unixToCalendar(response.getDt() + offset);
        weather.setTemperature(response.getMain().getTemp());
        weather.setHumidity(response.getMain().getHumidity());
        weather.setPressure(response.getMain().getPressure());
        weather.setSunrise(response.getSys().getSunrise());
        weather.setSunset(response.getSys().getSunset());
        setPrecipitationType(response.getWeather().get(0).getId(), weather);
        double speed = response.getWind().getSpeed();
        double deg = response.getWind().getDeg();
        setWindDirectionAndSpeed(weather, speed, deg);
        String description = null;
        for (com.khasang.forecast.models.Weather descr : response.getWeather()) {
            description = descr.getDescription();
        }
        weather.setDescription(description);
        map.put(calendar, weather);
        return map;
    }

    /**
     * Метод для конвертирования ответа от API в коллекцию типа {@link Map}<{@link Calendar}, {@link Weather}>
     * для запроса почасового прогноза погоды.
     *
     * @param response объект типа {@link OpenWeatherMapResponse}, содержащий ответ от API.
     * @param cityID
     */
    public static Map<Calendar, Weather> convertToHourlyWeather(OpenWeatherMapResponse response, int cityID) {
        Map<Calendar, Weather> map = new HashMap<>();
        for (HourlyForecastList forecast : response.getList()) {
            int offset = PositionManager.getInstance().getPosition(cityID).getTimeZone();
            Calendar calendar = unixToCalendar(forecast.getDt() + offset);
            Weather weather = new Weather();
            weather.setTemperature(forecast.getMain().getTemp());
            weather.setHumidity(forecast.getMain().getHumidity());
            weather.setPressure(forecast.getMain().getPressure());
            double speed = forecast.getWind().getSpeed();
            double deg = forecast.getWind().getDeg();
            setWindDirectionAndSpeed(weather, speed, deg);
            setPrecipitationType(forecast.getWeather().get(0).getId(), weather);
            String description = null;
            for (com.khasang.forecast.models.Weather descr : forecast.getWeather()) {
                description = descr.getDescription();
            }
            weather.setDescription(description);
            map.put(calendar, weather);
        }
        return map;
    }

    /**
     * Метод для конвертирования ответа от API в коллекцию типа {@link Map}<{@link Calendar}, {@link Weather}>
     * для запроса прогноза погоды по дням.
     *
     * @param response объект типа {@link DailyResponse}, содержащий ответ от API.
     * @param cityID
     */
    public static Map<Calendar, Weather> convertToDailyWeather(DailyResponse response, int cityID) {
        Map<Calendar, Weather> map = new HashMap<>();
        for (DailyForecastList forecast : response.getList()) {
            int offset = PositionManager.getInstance().getPosition(cityID).getTimeZone();
            Calendar calendar = unixToCalendar(forecast.getDt() + offset);
            Weather weather = new Weather();
            weather.setTemperature(forecast.getTemp().getDay());
            weather.setHumidity(forecast.getHumidity());
            weather.setPressure(forecast.getPressure());
            double speed = forecast.getSpeed();
            double deg = forecast.getDeg();
            setWindDirectionAndSpeed(weather, speed, deg);
            setPrecipitationType(forecast.getWeather().get(0).getId(), weather);
            String description = null;
            for (com.khasang.forecast.models.Weather descr : forecast.getWeather()) {
                description = descr.getDescription();
            }
            weather.setDescription(description);
            map.put(calendar, weather);
        }
        return map;
    }

    /**
     * Метод преобразует градусы направления ветра в перечисление типа Wind.Direction,
     * а так же устанавливает свойства для класса {@link Weather}.
     *
     * @param weather объект типа {@link Weather}.
     * @param speed   скорость ветра в м/с.
     * @param deg     направление ветра в градусах.
     */
    private static void setWindDirectionAndSpeed(Weather weather, double speed, double deg) {
        if ((deg >= 0 && deg <= 22.5) || (deg > 337.5 && deg <= 360)) {
            weather.setWind(Wind.Direction.NORTH, speed);
        } else if (deg > 22.5 && deg <= 67.5) {
            weather.setWind(Wind.Direction.NORTHEAST, speed);
        } else if (deg > 67.5 && deg <= 112.5) {
            weather.setWind(Wind.Direction.EAST, speed);
        } else if (deg > 112.5 && deg <= 157.5) {
            weather.setWind(Wind.Direction.SOUTHEAST, speed);
        } else if (deg > 157.5 && deg <= 202.5) {
            weather.setWind(Wind.Direction.SOUTH, speed);
        } else if (deg > 202.5 && deg <= 247.5) {
            weather.setWind(Wind.Direction.SOUTHWEST, speed);
        } else if (deg > 247.5 && deg <= 292.5) {
            weather.setWind(Wind.Direction.WEST, speed);
        } else if (deg > 292.5 && deg <= 337.5) {
            weather.setWind(Wind.Direction.NORTHWEST, speed);
        }
    }

    /**
     * Метод, преобразующий UNIX-время в объект типа {@link Calendar}.
     *
     * @param unixTime UNIX-время.
     */
    private static Calendar unixToCalendar(long unixTime) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(unixTime * 1000L);
        return calendar;
    }

    public static Drawable[] createIconsSet(Context context) {
        Drawable[] iconsSet = new Drawable[ICONS_COUNT];
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
        String iconSetType = sp.getString(context.getString(R.string.pref_icons_set_key), context.getString(R.string.pref_icons_set_default));
        if (iconSetType.equals(context.getString(R.string.pref_icons_set_mike_color))) {
            iconsSet[ICON_INDEX_THUNDERSTORM_LIGHT_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_200).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_THUNDERSTORM_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_201).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_THUNDERSTORM_HEAVY_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_202).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_LIGHT_THUNDERSTORM] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_210).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_THUNDERSTORM] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_211).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_THUNDERSTORM] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_212).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_RAGGED_THUNDERSTORM] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_221).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_THUNDERSTORM_LIGHT_DRIZZLE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_230).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_THUNDERSTORM_DRIZZLE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_231).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_THUNDERSTORM_HEAVY_DRIZZLE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_232).sizeDp(80).paddingDp(4);

            iconsSet[ICON_INDEX_LIGHT_INTENSITY_DRIZZLE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_300).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_DRIZZLE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_301).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_INTENSITY_DRIZZLE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_302).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_LIGHT_INTENSITY_DRIZZLE_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_310).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_DRIZZLE_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_311).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_INTENSITY_DRIZZLE_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_312).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SHOWER_RAIN_AND_DRIZZLE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_313).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_SHOWER_RAIN_AND_DRIZZLE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_314).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SHOWER_DRIZZLE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_321).sizeDp(80).paddingDp(4);

            iconsSet[ICON_INDEX_LIGHT_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_day_500).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_MODERATE_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_day_501).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_INTENSITY_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_day_502).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_VERY_HEAVY_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_day_503).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_EXTREME_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_day_504).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_LIGHT_RAIN_NIGHT] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_night_500).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_MODERATE_RAIN_NIGHT] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_night_501).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_INTENSITY_RAIN_NIGHT] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_night_502).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_VERY_HEAVY_RAIN_NIGHT] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_night_503).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_EXTREME_RAIN_NIGHT] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_night_504).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_FREEZING_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_511).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_LIGHT_INTENSITY_SHOWER_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_520).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SHOWER_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_521).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_INTENSITY_SHOWER_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_522).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_RAGGED_SHOWER_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_531).sizeDp(80).paddingDp(4);

            iconsSet[ICON_INDEX_LIGHT_SNOW] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_600).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SNOW] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_601).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_SNOW] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_602).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SLEET] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_611).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SHOWER_SLEET] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_612).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_LIGHT_RAIN_AND_SNOW] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_615).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_RAIN_AND_SNOW] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_616).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_LIGHT_SHOWER_SNOW] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_620).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SHOWER_SNOW] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_621).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_SHOWER_SNOW] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_622).sizeDp(80).paddingDp(4);

            iconsSet[ICON_INDEX_MIST] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_731).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SMOKE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_711).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HAZE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_721).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SAND_DUST_WHIRLS] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_731).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_FOG] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_741).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SAND] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_sandstorm).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_DUST] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_sandstorm).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_VOLCANIC_ASH] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_volcano).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SQUALLS] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_771).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_TORNADO] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_781).sizeDp(80).paddingDp(4);

            iconsSet[ICON_INDEX_CLEAR_SKY_SUN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_day_800).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_CLEAR_SKY_MOON] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_night_800).sizeDp(80).paddingDp(4);

            iconsSet[ICON_INDEX_FEW_CLOUDS] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_day_801).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_FEW_CLOUDS_NIGHT] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_night_801).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SCATTERED_CLOUDS] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_day_802).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SCATTERED_CLOUDS_NIGHT] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_night_802).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_BROKEN_CLOUDS] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_803).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_BROKEN_CLOUDS_NIGHT] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_803).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_OVERCAST_CLOUDS] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_804).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_OVERCAST_CLOUDS_NIGHT] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_804).sizeDp(80).paddingDp(4);

            iconsSet[ICON_INDEX_EXTREME_TORNADO] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_900).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_EXTREME_TROPICAL_STORM] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_901).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_EXTREME_HURRICANE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_902).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_EXTREME_COLD] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_903).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_EXTREME_HOT] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_904).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_EXTREME_WINDY] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_strong_wind).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_EXTREME_HAIL] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_906).sizeDp(80).paddingDp(4);

            iconsSet[ICON_INDEX_CALM] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_1).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_LIGHT_BREEZE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_2).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_GENTLE_BREEZE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_3).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_MODERATE_BREEZE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_4).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_FRESH_BREEZE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_5).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_STRONG_BREEZE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_6).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HIGH_WIND_NEAR_GALE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_7).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_GALE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_8).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SEVERE_GALE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_9).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_STORM] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_10).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_VIOLENT_STORM] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_11).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HURRICANE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_12).sizeDp(80).paddingDp(4);

        } else if (iconSetType.equals(context.getString(R.string.pref_icons_set_mike_bw))) {

            iconsSet[ICON_INDEX_THUNDERSTORM_LIGHT_RAIN] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_cloud_flash_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_THUNDERSTORM_RAIN] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_cloud_flash_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_THUNDERSTORM_HEAVY_RAIN] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_cloud_flash_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_LIGHT_THUNDERSTORM] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_clouds_flash_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_THUNDERSTORM] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_clouds_flash_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_THUNDERSTORM] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_lightning).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_RAGGED_THUNDERSTORM] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_lightning).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_THUNDERSTORM_LIGHT_DRIZZLE] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_cloud_flash_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_THUNDERSTORM_DRIZZLE] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_cloud_flash_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_THUNDERSTORM_HEAVY_DRIZZLE] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_cloud_flash_inv).sizeDp(80).paddingDp(4);

            iconsSet[ICON_INDEX_LIGHT_INTENSITY_DRIZZLE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_raindrop).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_DRIZZLE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_raindrops).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_INTENSITY_DRIZZLE] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_LIGHT_INTENSITY_DRIZZLE_RAIN] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_DRIZZLE_RAIN] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_INTENSITY_DRIZZLE_RAIN] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SHOWER_RAIN_AND_DRIZZLE] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_drizzle_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_SHOWER_RAIN_AND_DRIZZLE] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SHOWER_DRIZZLE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_raindrops).sizeDp(80).paddingDp(4);

            iconsSet[ICON_INDEX_LIGHT_RAIN] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_raindrops).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_MODERATE_RAIN] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_INTENSITY_RAIN] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_VERY_HEAVY_RAIN] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_EXTREME_RAIN] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_LIGHT_RAIN_NIGHT] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_MODERATE_RAIN_NIGHT] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_INTENSITY_RAIN_NIGHT] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_VERY_HEAVY_RAIN_NIGHT] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_EXTREME_RAIN_NIGHT] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_FREEZING_RAIN] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_LIGHT_INTENSITY_SHOWER_RAIN] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SHOWER_RAIN] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_INTENSITY_SHOWER_RAIN] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_rain_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_RAGGED_SHOWER_RAIN] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_cloud_flash_inv).sizeDp(80).paddingDp(4);

            iconsSet[ICON_INDEX_LIGHT_SNOW] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_snow_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SNOW] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_snow_heavy_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_SNOW] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_snow_heavy_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SLEET] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_snow_heavy_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SHOWER_SLEET] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_snow_heavy_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_LIGHT_RAIN_AND_SNOW] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_snow_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_RAIN_AND_SNOW] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_snow_heavy_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_LIGHT_SHOWER_SNOW] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_snow_heavy_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SHOWER_SNOW] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_snow_heavy_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HEAVY_SHOWER_SNOW] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_snow_heavy_inv).sizeDp(80).paddingDp(4);

            iconsSet[ICON_INDEX_MIST] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_mist).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SMOKE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_smog).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HAZE] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_fog).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SAND_DUST_WHIRLS] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_fog).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_FOG] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_fog).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SAND] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_sandstorm).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_DUST] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_sandstorm).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_VOLCANIC_ASH] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_volcano).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SQUALLS] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_strong_wind).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_TORNADO] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_tornado).sizeDp(80).paddingDp(4);

            iconsSet[ICON_INDEX_CLEAR_SKY_SUN] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_sun_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_CLEAR_SKY_MOON] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_moon_inv).sizeDp(80).paddingDp(4);

            iconsSet[ICON_INDEX_FEW_CLOUDS] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_cloud_sun_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_FEW_CLOUDS_NIGHT] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_cloud_moon_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SCATTERED_CLOUDS] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_cloud_sun_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SCATTERED_CLOUDS_NIGHT] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_cloud_moon_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_BROKEN_CLOUDS] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_cloud_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_BROKEN_CLOUDS_NIGHT] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_cloud_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_OVERCAST_CLOUDS] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_clouds_inv).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_OVERCAST_CLOUDS_NIGHT] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_clouds_inv).sizeDp(80).paddingDp(4);

            iconsSet[ICON_INDEX_EXTREME_TORNADO] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_tornado).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_EXTREME_TROPICAL_STORM] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_lightning).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_EXTREME_HURRICANE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_902).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_EXTREME_COLD] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_903).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_EXTREME_HOT] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_owm_904).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_EXTREME_WINDY] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_strong_wind).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_EXTREME_HAIL] = new IconicsDrawable(context).icon(Meteoconcs.Icon.met_hail_inv).sizeDp(80).paddingDp(4);

            iconsSet[ICON_INDEX_CALM] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_1).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_LIGHT_BREEZE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_2).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_GENTLE_BREEZE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_3).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_MODERATE_BREEZE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_4).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_FRESH_BREEZE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_5).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_STRONG_BREEZE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_6).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HIGH_WIND_NEAR_GALE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_7).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_GALE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_8).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_SEVERE_GALE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_9).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_STORM] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_10).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_VIOLENT_STORM] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_11).sizeDp(80).paddingDp(4);
            iconsSet[ICON_INDEX_HURRICANE] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_wind_beaufort_12).sizeDp(80).paddingDp(4);
        } else {
            Drawable thunderstorm = ContextCompat.getDrawable(context, R.drawable.ic_thunderstorm);
            Drawable drizzle = ContextCompat.getDrawable(context, R.drawable.ic_drizzle);
            Drawable rain = ContextCompat.getDrawable(context, R.drawable.ic_rain);
            Drawable snow = ContextCompat.getDrawable(context, R.drawable.ic_snow);
            Drawable atmosphere = ContextCompat.getDrawable(context, R.drawable.ic_fog);
            Drawable sun = ContextCompat.getDrawable(context, R.drawable.ic_sun);
            Drawable moon = ContextCompat.getDrawable(context, R.drawable.ic_moon);
            Drawable clouds = ContextCompat.getDrawable(context, R.drawable.ic_cloud);
            Drawable extreme = ContextCompat.getDrawable(context, R.drawable.ic_extreme);

            for (int i = ICON_INDEX_THUNDERSTORM_LIGHT_RAIN; i <= ICON_INDEX_THUNDERSTORM_HEAVY_DRIZZLE; i++) {
                iconsSet[i] = thunderstorm;
            }
            for (int i = ICON_INDEX_LIGHT_INTENSITY_DRIZZLE; i <= ICON_INDEX_SHOWER_DRIZZLE; i++) {
                iconsSet[i] = drizzle;
            }
            for (int i = ICON_INDEX_LIGHT_RAIN; i <= ICON_INDEX_RAGGED_SHOWER_RAIN; i++) {
                iconsSet[i] = rain;
            }
            for (int i = ICON_INDEX_LIGHT_SNOW; i <= ICON_INDEX_HEAVY_SHOWER_SNOW; i++) {
                iconsSet[i] = snow;
            }
            for (int i = ICON_INDEX_MIST; i <= ICON_INDEX_TORNADO; i++) {
                iconsSet[i] = atmosphere;
            }
            iconsSet[ICON_INDEX_CLEAR_SKY_SUN] = sun;
            iconsSet[ICON_INDEX_CLEAR_SKY_MOON] = moon;
            for (int i = ICON_INDEX_FEW_CLOUDS; i <= ICON_INDEX_OVERCAST_CLOUDS_NIGHT; i++) {
                iconsSet[i] = clouds;
            }
            for (int i = ICON_INDEX_EXTREME_TORNADO; i <= ICON_INDEX_EXTREME_HAIL; i++) {
                iconsSet[i] = extreme;
            }
            for (int i = ICON_INDEX_CALM; i <= ICON_INDEX_HURRICANE; i++) {
                iconsSet[i] = extreme;
            }
        }
        iconsSet[ICON_INDEX_NA] = new IconicsDrawable(context).icon(WeatherIcons.Icon.wic_na).sizeDp(80).paddingDp(4);
        return iconsSet;
    }

    /**
     * Метод преобразует полученный тип осадков в перечисление типа Precipitation.Type, а так же
     * устанавливает свойства для класса {@link Weather}.
     *
     * @param id      идентификатор типа осадков.
     * @param weather объект типа {@link Weather}.
     */
    private static void setPrecipitationType(int id, Weather weather) {
        if (id >= 200 && id < 300) {
            switch (id) {
                case 200:
                    weather.setPrecipitation(Precipitation.Type.THUNDERSTORM_LIGHT_RAIN);
                    break;
                case 201:
                    weather.setPrecipitation(Precipitation.Type.THUNDERSTORM_RAIN);
                    break;
                case 202:
                    weather.setPrecipitation(Precipitation.Type.THUNDERSTORM_HEAVY_RAIN);
                    break;
                case 210:
                    weather.setPrecipitation(Precipitation.Type.LIGHT_THUNDERSTORM);
                    break;
                case 212:
                    weather.setPrecipitation(Precipitation.Type.HEAVY_THUNDERSTORM);
                    break;
                case 221:
                    weather.setPrecipitation(Precipitation.Type.RAGGED_THUNDERSTORM);
                    break;
                case 230:
                    weather.setPrecipitation(Precipitation.Type.THUNDERSTORM_LIGHT_DRIZZLE);
                    break;
                case 231:
                    weather.setPrecipitation(Precipitation.Type.THUNDERSTORM_DRIZZLE);
                    break;
                case 232:
                    weather.setPrecipitation(Precipitation.Type.THUNDERSTORM_HEAVY_DRIZZLE);
                    break;
                default:
                    weather.setPrecipitation(Precipitation.Type.THUNDERSTORM); // 211
                    break;
            }
        } else if (id >= 300 && id < 400) {
            switch (id) {
                case 300:
                    weather.setPrecipitation(Precipitation.Type.LIGHT_INTENSITY_DRIZZLE);
                    break;
                case 302:
                    weather.setPrecipitation(Precipitation.Type.HEAVY_INTENSITY_DRIZZLE);
                    break;
                case 310:
                    weather.setPrecipitation(Precipitation.Type.LIGHT_INTENSITY_DRIZZLE_RAIN);
                    break;
                case 311:
                    weather.setPrecipitation(Precipitation.Type.DRIZZLE_RAIN);
                    break;
                case 312:
                    weather.setPrecipitation(Precipitation.Type.HEAVY_INTENSITY_DRIZZLE_RAIN);
                    break;
                case 313:
                    weather.setPrecipitation(Precipitation.Type.SHOWER_RAIN_AND_DRIZZLE);
                    break;
                case 314:
                    weather.setPrecipitation(Precipitation.Type.HEAVY_SHOWER_RAIN_AND_DRIZZLE);
                    break;
                case 321:
                    weather.setPrecipitation(Precipitation.Type.SHOWER_DRIZZLE);
                    break;
                default:
                    weather.setPrecipitation(Precipitation.Type.DRIZZLE); // 301
                    break;
            }
        } else if (id >= 500 && id < 600) {
            switch (id) {
                case 500:
                    weather.setPrecipitation(Precipitation.Type.LIGHT_RAIN);
                    break;
                case 501:
                    weather.setPrecipitation(Precipitation.Type.MODERATE_RAIN);
                    break;
                case 502:
                    weather.setPrecipitation(Precipitation.Type.HEAVY_INTENSITY_RAIN);
                    break;
                case 503:
                    weather.setPrecipitation(Precipitation.Type.VERY_HEAVY_RAIN);
                    break;
                case 504:
                    weather.setPrecipitation(Precipitation.Type.EXTREME_RAIN);
                    break;
                case 511:
                    weather.setPrecipitation(Precipitation.Type.FREEZING_RAIN);
                    break;
                case 520:
                    weather.setPrecipitation(Precipitation.Type.LIGHT_INTENSITY_SHOWER_RAIN);
                    break;
                case 521:
                    weather.setPrecipitation(Precipitation.Type.SHOWER_RAIN);
                    break;
                case 522:
                    weather.setPrecipitation(Precipitation.Type.HEAVY_INTENSITY_SHOWER_RAIN);
                    break;
                case 531:
                    weather.setPrecipitation(Precipitation.Type.RAGGED_SHOWER_RAIN);
                    break;
                default:
                    weather.setPrecipitation(Precipitation.Type.RAIN);  // DEFAULT == SHOWER_RAIN
                    break;
            }
        } else if (id >= 600 && id < 700) {
            switch (id) {
                case 600:
                    weather.setPrecipitation(Precipitation.Type.LIGHT_SNOW);
                    break;
                case 602:
                    weather.setPrecipitation(Precipitation.Type.HEAVY_SNOW);
                    break;
                case 611:
                    weather.setPrecipitation(Precipitation.Type.SLEET);
                    break;
                case 612:
                    weather.setPrecipitation(Precipitation.Type.SHOWER_SLEET);
                    break;
                case 615:
                    weather.setPrecipitation(Precipitation.Type.LIGHT_RAIN_AND_SNOW);
                    break;
                case 616:
                    weather.setPrecipitation(Precipitation.Type.RAIN_AND_SNOW);
                    break;
                case 620:
                    weather.setPrecipitation(Precipitation.Type.LIGHT_SHOWER_SNOW);
                    break;
                case 621:
                    weather.setPrecipitation(Precipitation.Type.SHOWER_SNOW);
                    break;
                case 622:
                    weather.setPrecipitation(Precipitation.Type.HEAVY_SHOWER_SNOW);
                    break;
                default:
                    weather.setPrecipitation(Precipitation.Type.SNOW);  // 601
                    break;
            }
        } else if (id >= 700 && id < 800) {
            switch (id) {
                case 701:
                    weather.setPrecipitation(Precipitation.Type.MIST);
                    break;
                case 711:
                    weather.setPrecipitation(Precipitation.Type.SMOKE);
                    break;
                case 721:
                    weather.setPrecipitation(Precipitation.Type.HAZE);
                    break;
                case 731:
                    weather.setPrecipitation(Precipitation.Type.SAND_DUST_WHIRLS);
                    break;
                case 741:
                    weather.setPrecipitation(Precipitation.Type.FOG);
                    break;
                case 751:
                    weather.setPrecipitation(Precipitation.Type.SAND);
                    break;
                case 761:
                    weather.setPrecipitation(Precipitation.Type.DUST);
                    break;
                case 762:
                    weather.setPrecipitation(Precipitation.Type.VOLCANIC_ASH);
                    break;
                case 771:
                    weather.setPrecipitation(Precipitation.Type.SQUALLS);
                    break;
                case 781:
                    weather.setPrecipitation(Precipitation.Type.TORNADO);
                    break;
                default:
                    weather.setPrecipitation(Precipitation.Type.ATMOSPHERE);    // DEFAULT == FOG
                    break;
            }
        } else if (id == 800) {
            weather.setPrecipitation(Precipitation.Type.CLEAR_SKY);
        } else if (id > 800 && id < 805) {
            switch (id) {
                case 801:
                    weather.setPrecipitation(Precipitation.Type.FEW_CLOUDS);
                    break;
                case 802:
                    weather.setPrecipitation(Precipitation.Type.SCATTERED_CLOUDS);
                    break;
                case 803:
                    weather.setPrecipitation(Precipitation.Type.BROKEN_CLOUDS);
                    break;
                case 804:
                    weather.setPrecipitation(Precipitation.Type.OVERCAST_CLOUDS);
                    break;
                default:
                    weather.setPrecipitation(Precipitation.Type.SCATTERED_CLOUDS);  // DEFAULT == SCATTERED_CLOUDS
                    break;
            }
        } else if (id >= 900 && id < 910) {
            switch (id) {
                case 900:
                    weather.setPrecipitation(Precipitation.Type.EXTREME_TORNADO);
                    break;
                case 901:
                    weather.setPrecipitation(Precipitation.Type.EXTREME_TROPICAL_STORM);
                    break;
                case 902:
                    weather.setPrecipitation(Precipitation.Type.EXTREME_HURRICANE);
                    break;
                case 903:
                    weather.setPrecipitation(Precipitation.Type.EXTREME_COLD);
                    break;
                case 904:
                    weather.setPrecipitation(Precipitation.Type.EXTREME_HOT);
                    break;
                case 905:
                    weather.setPrecipitation(Precipitation.Type.EXTREME_WINDY);
                    break;
                case 906:
                    weather.setPrecipitation(Precipitation.Type.EXTREME_HAIL);
                    break;
                default:
                    weather.setPrecipitation(Precipitation.Type.EXTREME);   // DEFAULT == ICON_INDEX_EXTREME_TORNADO;
                    break;
            }
        } else if (id == 951) {
            weather.setPrecipitation(Precipitation.Type.CALM);
        } else if (id == 952) {
            weather.setPrecipitation(Precipitation.Type.LIGHT_BREEZE);
        } else if (id == 953) {
            weather.setPrecipitation(Precipitation.Type.GENTLE_BREEZE);
        } else if (id == 954) {
            weather.setPrecipitation(Precipitation.Type.MODERATE_BREEZE);
        } else if (id == 955) {
            weather.setPrecipitation(Precipitation.Type.FRESH_BREEZE);
        } else if (id == 956) {
            weather.setPrecipitation(Precipitation.Type.STRONG_BREEZE);
        } else if (id == 957) {
            weather.setPrecipitation(Precipitation.Type.HIGH_WIND_NEAR_GALE);
        } else if (id == 958) {
            weather.setPrecipitation(Precipitation.Type.GALE);
        } else if (id == 959) {
            weather.setPrecipitation(Precipitation.Type.SEVERE_GALE);
        } else if (id == 960) {
            weather.setPrecipitation(Precipitation.Type.STORM);
        } else if (id == 961) {
            weather.setPrecipitation(Precipitation.Type.VIOLENT_STORM);
        } else if (id == 962) {
            weather.setPrecipitation(Precipitation.Type.HURRICANE);
        } else {
            weather.setPrecipitation(Precipitation.Type.NO_DATA);
        }
    }

    /**
     * Метод для преобразования погодных характеристик в заданные пользователями метрики
     *
     * @param weather обьект класса {@link Weather}, в котором нужно привести погодные характеристики к заданным метрикам
     * @return обьект класса {@link Weather} с преобразованными погодными характеристиками
     */
    public static Weather formatWeather(Weather weather, AppUtils.TemperatureMetrics temperatureMetric, AppUtils.SpeedMetrics speedMetric, AppUtils.PressureMetrics pressureMetric) {
        weather.setTemperature(formatTemperature(weather.getTemperature(), temperatureMetric));
        weather.setPressure(formatPressure(weather.getPressure(), pressureMetric));
        weather.setWind(weather.getWindDirection(), formatSpeed(weather.getWindPower(), speedMetric));
        return weather;
    }

    /**
     * Метод для преобразования температуры в заданную пользователем метрику
     *
     * @param temperature       температура на входе (в Кельвинах)
     * @param temperatureMetric
     * @return температура в выбранной пользователем метрике
     */
    public static double formatTemperature(double temperature, AppUtils.TemperatureMetrics temperatureMetric) {
        switch (temperatureMetric) {
            case KELVIN:
                break;
            case CELSIUS:
                return kelvinToCelsius(temperature);
            case FAHRENHEIT:
                return kelvinToFahrenheit(temperature);
        }
        return temperature;
    }

    /**
     * Метод для преобразования скорости ветра в заданную пользователем метрику
     *
     * @param speed       преобразуемая скорость
     * @param speedMetric
     * @return скорость в выбранной пользователем метрике
     */
    public static double formatSpeed(double speed, AppUtils.SpeedMetrics speedMetric) {
        switch (speedMetric) {
            case METER_PER_SECOND:
                break;
            case FOOT_PER_SECOND:
                return meterInSecondToFootInSecond(speed);
            case KM_PER_HOURS:
                return meterInSecondToKmInHours(speed);
            case MILES_PER_HOURS:
                return meterInSecondToMilesInHour(speed);
        }
        return speed;
    }

    /**
     * Метод для преобразования давления в заданную пользователем метрику
     *
     * @param pressure       преобразуемое давление
     * @param pressureMetric
     * @return давление в выбранной пользователем метрике
     */
    public static double formatPressure(double pressure, AppUtils.PressureMetrics pressureMetric) {
        switch (pressureMetric) {
            case HPA:
                break;
            case MM_HG:
                return hpaToMmHg(pressure);
        }
        return pressure;
    }

    /**
     * Метод для преобразования температуры из Кельвинов в Цельсии
     *
     * @param temperature температура в Кельвинах
     * @return температура в Цельсиях
     */
    public static double kelvinToCelsius(double temperature) {
        return temperature - KELVIN_CELSIUS_DELTA;
    }

    /**
     * Метод для преобразования температуры из Кельвина в Фаренгейт
     *
     * @param temperature температура в Кельвинах
     * @return температура в Фаренгейтах
     */
    public static double kelvinToFahrenheit(double temperature) {
        return (kelvinToCelsius(temperature) * 9 / 5) + 32;
    }

    /**
     * Метод для преобразования скорости ветра из метров в секунду в футы в секунду
     *
     * @param speed скорость ветра в метрах в секунду
     * @return скорость ветра в футах в секунду
     */
    public static double meterInSecondToFootInSecond(double speed) {
        return speed * METER_TO_FOOT;
    }

    /**
     * Метод для преобразования скорости ветра из метров в секунду в километры в час
     *
     * @param speed скорость ветра в метрах в секунду
     * @return скорость ветра в километрах в час
     */
    public static double meterInSecondToKmInHours(double speed) {
        return speed * 3.6;
    }

    /**
     * Метод для преобразования скорости ветра из метров в секунду в мили в час
     *
     * @param speed скорость ветра в метрах в секунду
     * @return скорость ветра в милях в час
     */
    public static double meterInSecondToMilesInHour(double speed) {
        return meterInSecondToKmInHours(speed) * KM_TO_MILES;
    }

    /**
     * Метод для преобразования давления из килопаскалей в мм.рт.ст.
     *
     * @param pressure давление в килопаскалях
     * @return давление в мм.рт.ст.
     */
    public static double hpaToMmHg(double pressure) {
        return pressure / HPA_TO_MM_HG;
    }

    /**
     * Определение времени суток
     */
    public static boolean isDayFromString(String timeString) {
        timeString = timeString.substring(0, 2);
        try {
            int time = Integer.parseInt(timeString);
            return !(time >= 21 || time < 6);
        } catch (NumberFormatException nfe) {
            return true;
        }
    }

    /**
     * Получение дня
     **/
    public static String getDayName(Context context, Calendar calendar) {
        int rightNow = Calendar.getInstance(Locale.getDefault()).get(Calendar.DAY_OF_MONTH);
        int today = calendar.get(Calendar.DAY_OF_MONTH);
        if (rightNow == today) {
            return context.getString(R.string.today);
        } else if (today == rightNow + 1) {
            return context.getString(R.string.tomorrow);
        } else {
            SimpleDateFormat dayFormat = new SimpleDateFormat("EEE, d MMMM", Locale.getDefault());
            String myString = dayFormat.format(calendar.getTime());
            return myString.substring(0, 1).toUpperCase() + myString.substring(1);
        }
    }

    /**
     * Получение дня для графика
     **/
    public static String getChartDayName(Context context, Calendar calendar) {
        SimpleDateFormat dayFormat = new SimpleDateFormat("dd.MM", Locale.getDefault());
        return dayFormat.format(calendar.getTime());
    }

    /**
     * Получение времени
     **/
    public static String getTime(Context context, Calendar calendar, int timeZone) {
        SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm", Locale.getDefault());
        String time = timeFormat.format(calendar.getTime());
        return time;
    }

    /**
     * Получение времени для графика
     **/
    public static String getChartTime(Context context, Calendar calendar) {
        SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm", Locale.getDefault());
        return timeFormat.format(calendar.getTime());
    }


    public static boolean isNetworkAvailable(Context context) {
        ConnectivityManager connectivityManager = ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE));
        return connectivityManager.getActiveNetworkInfo() != null && connectivityManager.getActiveNetworkInfo().isConnected();
    }
} public class DelayedAutoCompleteTextView extends AutoCompleteTextView {

    private static final int MESSAGE_TEXT_CHANGED = 100;
    private static final int DEFAULT_AUTOCOMPLETE_DELAY = 750;

    private int mAutoCompleteDelay = DEFAULT_AUTOCOMPLETE_DELAY;
    private ProgressBar mLoadingIndicator;

    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            DelayedAutoCompleteTextView.super.performFiltering((CharSequence) msg.obj, msg.arg1);
        }
    };

    public DelayedAutoCompleteTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setLoadingIndicator(ProgressBar progressBar) {
        mLoadingIndicator = progressBar;
    }

    public void setAutoCompleteDelay(int autoCompleteDelay) {
        mAutoCompleteDelay = autoCompleteDelay;
    }

    @Override
    protected void performFiltering(CharSequence text, int keyCode) {
        if (mLoadingIndicator != null) {
            mLoadingIndicator.setVisibility(VISIBLE);
        }
        mHandler.removeMessages(MESSAGE_TEXT_CHANGED);
        mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_TEXT_CHANGED, text), mAutoCompleteDelay);
    }

    @Override
    public void onFilterComplete(int count) {
        if (mLoadingIndicator != null) {
            mLoadingIndicator.setVisibility(GONE);
        }
        super.onFilterComplete(count);
    }
}
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.khasang.forecast.Maps;
import com.khasang.forecast.R;
import com.khasang.forecast.adapters.CityPickerAdapter;
import com.khasang.forecast.adapters.GooglePlacesAutocompleteAdapter;
import com.khasang.forecast.adapters.etc.HidingScrollListener;
import com.khasang.forecast.api.GoogleMapsGeocoding;
import com.khasang.forecast.api.GoogleMapsTimezone;
import com.khasang.forecast.exceptions.EmptyCurrentAddressException;
import com.khasang.forecast.exceptions.NoAvailableAddressesException;
import com.khasang.forecast.interfaces.IMapDataReceiver;
import com.khasang.forecast.interfaces.IMessageProvider;
import com.khasang.forecast.location.LocationParser;
import com.khasang.forecast.position.Coordinate;
import com.khasang.forecast.position.PositionManager;
import com.khasang.forecast.utils.AppUtils;
import com.khasang.forecast.view.DelayedAutoCompleteTextView;
import com.mikepenz.community_material_typeface_library.CommunityMaterial;
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
import com.mikepenz.iconics.IconicsDrawable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Pattern;
import butterknife.BindView;
package com.khasang.forecast.activities;





/**
 * Created by CopyPasteStd on 29.11.15.
 * <p>
 * Activity для выбора местоположения
 */
public class CityPickerActivity extends BaseActivity implements View.OnClickListener, IMapDataReceiver,
        IMessageProvider {

    public final static String CITY_PICKER_TAG = "com.khasang.forecast.activities.CityPickerActivity";
    private final String TAG = this.getClass().getSimpleName();

    @BindView(R.id.infoTV)
    TextView infoTV;
    @BindView(R.id.recyclerView)
    RecyclerView recyclerView;
    @BindView(R.id.toolbar)
    Toolbar toolbar;
    @BindView(R.id.fabBtn)
    volatile FloatingActionButton fabBtn;
    GoogleMapsGeocoding googleMapsGeocoding;
    private CityPickerAdapter cityPickerAdapter;
    private List<String> cityList;
    private DelayedAutoCompleteTextView chooseCity;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_city_picker);

        setSupportActionBar(toolbar);
        //noinspection ConstantConditions
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setTitle(R.string.title_activity_city_picker);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                leaveActivity();
            }
        });

        cityList = new ArrayList<>();
        cityPickerAdapter = new CityPickerAdapter(cityList, this);
        recyclerView.setAdapter(cityPickerAdapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        googleMapsGeocoding = new GoogleMapsGeocoding();

        swapVisibilityTextOrList();

        /** Вычисляет степень прокрутки и выполняет нужное действие.*/
        recyclerView.addOnScrollListener(new HidingScrollListener() {
            @Override
            public void onHide() {
                hideViews();
            }

            @Override
            public void onShow() {
                showViews();
            }
        });
        IconicsDrawable icon = new IconicsDrawable(this)
                .color(ContextCompat.getColor(this, R.color.current_weather_color))
                .icon(CommunityMaterial.Icon.cmd_plus);
        fabBtn.setImageDrawable(icon);
        fabBtn.setOnClickListener(this);
        Animation animation = AnimationUtils.loadAnimation(this, R.anim.simple_grow);

        setupHeaderHeight();
        setupFooterHeight();
        createItemList();

        ItemTouchHelper.SimpleCallback simpleCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT |
                ItemTouchHelper.RIGHT) {
            @Override
            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView
                    .ViewHolder target) {
                return false;
            }

            @Override
            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                int position = recyclerView.getChildAdapterPosition(viewHolder.itemView) - 1;
                try {
                    PositionManager.getInstance().removePosition(cityList.get(position));