it.smartcommunitylab.carpooling.managers.CarPoolingManager.java Source code

Java tutorial

Introduction

Here is the source code for it.smartcommunitylab.carpooling.managers.CarPoolingManager.java

Source

/**
 * Copyright 2015 Smart Community Lab
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package it.smartcommunitylab.carpooling.managers;

import it.sayservice.platform.smartplanner.data.message.Itinerary;
import it.smartcommunitylab.carpooling.exceptions.CarPoolingCustomException;
import it.smartcommunitylab.carpooling.model.Booking;
import it.smartcommunitylab.carpooling.model.Community;
import it.smartcommunitylab.carpooling.model.Discussion;
import it.smartcommunitylab.carpooling.model.GameProfile;
import it.smartcommunitylab.carpooling.model.Message;
import it.smartcommunitylab.carpooling.model.Notification;
import it.smartcommunitylab.carpooling.model.Recurrency;
import it.smartcommunitylab.carpooling.model.RecurrentBooking;
import it.smartcommunitylab.carpooling.model.RecurrentTravel;
import it.smartcommunitylab.carpooling.model.Travel;
import it.smartcommunitylab.carpooling.model.TravelProfile;
import it.smartcommunitylab.carpooling.model.TravelRequest;
import it.smartcommunitylab.carpooling.model.User;
import it.smartcommunitylab.carpooling.model.UserInfo;
import it.smartcommunitylab.carpooling.model.Zone;
import it.smartcommunitylab.carpooling.mongo.repos.CommunityRepository;
import it.smartcommunitylab.carpooling.mongo.repos.DiscussionRepository;
import it.smartcommunitylab.carpooling.mongo.repos.NotificationRepository;
import it.smartcommunitylab.carpooling.mongo.repos.RecurrentTravelRepository;
import it.smartcommunitylab.carpooling.mongo.repos.TravelRepository;
import it.smartcommunitylab.carpooling.mongo.repos.TravelRequestRepository;
import it.smartcommunitylab.carpooling.mongo.repos.UserRepository;
import it.smartcommunitylab.carpooling.notification.SendPushNotification;
import it.smartcommunitylab.carpooling.utils.CarPoolingUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.http.HttpStatus;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
 * 
 * @author nawazk
 * 
 */
@Component
public class CarPoolingManager {

    private static final transient Log logger = LogFactory.getLog(CarPoolingManager.class);

    @Autowired
    private TravelRequestRepository travelRequestRepository;
    @Autowired
    private TravelRepository travelRepository;
    @Autowired
    private RecurrentTravelRepository reccurrentTravelRepository;
    @Autowired
    private CommunityRepository communityRepository;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private DiscussionRepository discussionRepository;
    @Autowired
    private MobilityPlanner mobilityPlanner;
    @Autowired
    private NotificationRepository notificationRepository;
    @Autowired
    private SendPushNotification sendPushNotification;

    /**
     * Save Non Recurrent Travel.
     * 
     * @param travel
     * @param userId
     * @return Travel
     * @throws CarPoolingCustomException
     */
    public Travel saveTravel(Travel travel, String userId) throws CarPoolingCustomException {

        // search for plan.
        List<Itinerary> itns = mobilityPlanner.plan(travel.getFrom(), travel.getTo(), travel.getWhen());

        if (!itns.isEmpty() && hasValidPolyLine(itns.get(0))) {

            String fromName = "";
            String toName = "";
            String fromAddr = "";
            String toAddr = "";

            travel.setUserId(userId);
            travel.setRoute(itns.get(0));
            travel.setActive(true);

            if (travel.getFrom().getName() != null && !travel.getFrom().getName().isEmpty()) {
                fromName = travel.getFrom().getName();
            }

            if (travel.getFrom().getAddress() != null && !travel.getFrom().getAddress().isEmpty()) {
                fromAddr = travel.getFrom().getAddress();
            }

            if (travel.getTo().getName() != null && !travel.getTo().getName().isEmpty()) {
                toName = travel.getTo().getName();
            }

            if (travel.getTo().getAddress() != null && !travel.getTo().getAddress().isEmpty()) {
                toAddr = travel.getTo().getAddress();
            }
            // from.
            Zone updateFrom = new Zone(fromName, fromAddr, travel.getFrom().getLatitude(),
                    travel.getFrom().getLongitude(), travel.getFrom().getRange());
            travel.setFrom(updateFrom);
            // to
            Zone updateTo = new Zone(toName, toAddr, travel.getTo().getLatitude(), travel.getTo().getLongitude(),
                    travel.getTo().getRange());
            travel.setTo(updateTo);

            if (travel.getCommunityIds().isEmpty()) {
                for (Community community : communityRepository.findByUserId(userId)) {
                    if (!travel.getCommunityIds().contains(community.getId())) {
                        travel.getCommunityIds().add(community.getId());
                    }
                }
            }

            travelRepository.save(travel);

            // loop on all trip request and check if this new travel matches any
            // of those.
            for (TravelRequest travelRequest : travelRequestRepository.findAllMatchTravelRequest(travel)) {
                String travelRequestId = travelRequest.getId();
                String targetUserId = travelRequest.getUserId();
                Map<String, String> data = new HashMap<String, String>();
                data.put("travelRequestId", travelRequestId);
                Notification tripAvailability = new Notification(targetUserId,
                        CarPoolingUtils.NOTIFICATION_AVALIABILITY, data, false, travel.getId(),
                        System.currentTimeMillis());
                notificationRepository.save(tripAvailability);
                // notify via parse.
                try {
                    sendPushNotification.sendNotification(targetUserId, tripAvailability);
                } catch (JSONException e) {
                    throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
                }
            }
        } else {
            throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(),
                    "travel itinerary not found");
        }

        return travel;
    }

    /**
     * Has Valid PolyLine Checker.
     * 
     * @param itinerary
     * @return
     */
    private boolean hasValidPolyLine(Itinerary itinerary) {

        boolean validGeometry = false;

        String polyLine = itinerary.getLeg().get(0).getLegGeometery().getPoints();

        if (polyLine != null && !polyLine.isEmpty()) {
            validGeometry = true;

        }

        return validGeometry;
    }

    /**
     * Save Recurrent Travel.
     * 
     * @param recurrentTravel
     * @param userId
     * @return Recurrent Travel.
     * @throws CarPoolingCustomException
     */
    public RecurrentTravel saveRecurrentTravel(RecurrentTravel recurrentTravel, String userId)
            throws CarPoolingCustomException {
        // search for plan.
        List<Itinerary> itns = mobilityPlanner.plan(recurrentTravel.getFrom(), recurrentTravel.getTo(),
                recurrentTravel.getWhen());

        if (!itns.isEmpty() && hasValidPolyLine(itns.get(0))) {

            String fromName = "";
            String toName = "";
            String fromAddr = "";
            String toAddr = "";

            recurrentTravel.setUserId(userId);
            recurrentTravel.setRoute(itns.get(0));
            recurrentTravel.setActive(true);

            if (recurrentTravel.getFrom().getName() != null && !recurrentTravel.getFrom().getName().isEmpty()) {
                fromName = recurrentTravel.getFrom().getName();
            }

            if (recurrentTravel.getFrom().getAddress() != null
                    && !recurrentTravel.getFrom().getAddress().isEmpty()) {
                fromAddr = recurrentTravel.getFrom().getAddress();
            }

            if (recurrentTravel.getTo().getName() != null && !recurrentTravel.getTo().getName().isEmpty()) {
                toName = recurrentTravel.getTo().getName();
            }

            if (recurrentTravel.getTo().getAddress() != null && !recurrentTravel.getTo().getAddress().isEmpty()) {
                toAddr = recurrentTravel.getTo().getAddress();
            }
            // from.
            Zone updateFrom = new Zone(fromName, fromAddr, recurrentTravel.getFrom().getLatitude(),
                    recurrentTravel.getFrom().getLongitude(), recurrentTravel.getFrom().getRange());
            recurrentTravel.setFrom(updateFrom);
            // to
            Zone updateTo = new Zone(toName, toAddr, recurrentTravel.getTo().getLatitude(),
                    recurrentTravel.getTo().getLongitude(), recurrentTravel.getTo().getRange());
            recurrentTravel.setTo(updateTo);

            if (recurrentTravel.getCommunityIds().isEmpty()) {
                for (Community community : communityRepository.findByUserId(userId)) {
                    if (!recurrentTravel.getCommunityIds().contains(community.getId())) {
                        recurrentTravel.getCommunityIds().add(community.getId());
                    }
                }
            }

            reccurrentTravelRepository.save(recurrentTravel);

            /** create instances of non recurrent travels. **/

            for (int extendDay = 0; extendDay <= CarPoolingUtils.INSTANCES_THRESHOLD; extendDay++) {

                Recurrency recurrency = recurrentTravel.getRecurrency();

                long temp = CarPoolingUtils.adjustNumberOfDaysToWhen(recurrentTravel.getWhen(), extendDay);
                // last instance when to be updated in parent recurrent travel
                // object.
                if (extendDay == CarPoolingUtils.INSTANCES_THRESHOLD) {
                    recurrentTravel.setLastInstance(temp);
                    reccurrentTravelRepository.save(recurrentTravel);
                }

                // create instance if recurrency applies.
                if (CarPoolingUtils.ifRecurrencyApplies(recurrency, temp)) {
                    Travel instance = new Travel();
                    // set parent Id.
                    instance.setRecurrentId(recurrentTravel.getId());
                    instance.setFrom(recurrentTravel.getFrom());
                    instance.setTo(recurrentTravel.getTo());
                    instance.setWhen(temp);
                    instance.setRoute(recurrentTravel.getRoute());
                    instance.setUserId(recurrentTravel.getUserId());
                    instance.setPlaces(recurrentTravel.getPlaces());
                    instance.setIntermediateStops(recurrentTravel.isIntermediateStops());
                    instance.setActive(recurrentTravel.isActive());
                    instance.setCommunityIds(recurrentTravel.getCommunityIds());

                    travelRepository.save(instance);
                }

            }

            // loop on all trip request and check if this new travel matches any
            // of those.
            for (TravelRequest travelRequest : travelRequestRepository.findAllMatchTravelRequest(recurrentTravel)) {

                String travelRequestId = travelRequest.getId();
                String targetUserId = travelRequest.getUserId();
                Map<String, String> data = new HashMap<String, String>();
                data.put("travelRequestId", travelRequestId);

                // get travelId of the instance of recurrent travel.
                Travel instance = travelRepository.findOneInstanceOfRecurrTravel(travelRequest,
                        recurrentTravel.getId());

                Notification tripAvailability = new Notification(targetUserId,
                        CarPoolingUtils.NOTIFICATION_AVALIABILITY, data, false, instance.getId(),
                        System.currentTimeMillis());

                notificationRepository.save(tripAvailability);
                // notify via parse.
                try {
                    sendPushNotification.sendNotification(targetUserId, tripAvailability);
                } catch (JSONException e) {
                    throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
                }
            }
        } else {
            throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(),
                    "travel itinerary not found");
        }

        return recurrentTravel;
    }

    @Scheduled(cron = "0 59 23 * * ?")
    public void autoExtendRecurrTravelInstances() throws CarPoolingCustomException {

        logger.info("/**** Extending NonRecurrent instances of RecurrentTravel with window of 30 days.****/ ");

        for (RecurrentTravel recurrentTravel : reccurrentTravelRepository
                .searchTravelsToExtend(CarPoolingUtils.INSTANCES_THRESHOLD)) {

            // calculate the number of days from lastInstance timestamp.
            int pendingDays = CarPoolingUtils.getDaysBetweenDates(recurrentTravel.getLastInstance(),
                    System.currentTimeMillis());

            if (pendingDays != 1) {
                logger.warn("encountering abnormal behaviour");
            }

            long temp = recurrentTravel.getLastInstance();
            Recurrency recurrency = recurrentTravel.getRecurrency();

            for (int day = 0; day < pendingDays; day++) {

                temp = CarPoolingUtils.adjustNumberOfDaysToWhen(temp, 1);

                if (CarPoolingUtils.ifRecurrencyApplies(recurrency, temp)) {
                    Travel instance = new Travel();
                    // set parent Id.
                    instance.setRecurrentId(recurrentTravel.getId());
                    instance.setFrom(recurrentTravel.getFrom());
                    instance.setTo(recurrentTravel.getTo());
                    instance.setWhen(temp);
                    instance.setRoute(recurrentTravel.getRoute());
                    instance.setUserId(recurrentTravel.getUserId());
                    instance.setPlaces(recurrentTravel.getPlaces());
                    instance.setIntermediateStops(recurrentTravel.isIntermediateStops());
                    instance.setActive(recurrentTravel.isActive());
                    instance.setCommunityIds(recurrentTravel.getCommunityIds());
                    for (RecurrentBooking recurrentBooking : recurrentTravel.getBookings()) {
                        Booking book = new Booking();
                        book.setRecurrent(true);
                        book.setTraveller(recurrentBooking.getTraveller());
                        book.setAccepted(recurrentBooking.getAccepted());
                        book.setDate(new java.util.Date(System.currentTimeMillis()));
                        instance.getBookings().add(book);
                    }
                    // save new instance.
                    travelRepository.save(instance);

                } else {
                    logger.info("no instance create as recurrency doesn't apply " + recurrentTravel.getId());
                }
            }

            // update recurrent travel.
            recurrentTravel.setLastInstance(temp);
            reccurrentTravelRepository.save(recurrentTravel);

        }

    }

    public List<TravelRequest> getTravelRequest(String userId) {
        return travelRequestRepository.findByUserId(userId);

    }

    public List<TravelRequest> getMonitoredTravelRequest(String userId) {
        return travelRequestRepository.findMonitoredTravelRequest(userId);
    }

    public void saveTravelRequest(TravelRequest travelRequest) {
        travelRequestRepository.save(travelRequest);
    }

    public List<Travel> getPassengerTrips(String passengerId, int start, int count, Long from, Long to, int order,
            Boolean boarded, Boolean accepted, String communityId) {
        return travelRepository.findTravelByPassengerId(passengerId, start, count, from, to, order, boarded,
                accepted, communityId);
    }

    public List<Travel> getDriverTrips(String userId, int start, int count, Long from, Long to, int order) {

        // Page<Travel> travels = travelRepository.findTravelByDriverId(userId,
        // new PageRequest(start, count,
        // Direction.DESC, "route.startime"));
        //
        // return travels.getContent();
        return travelRepository.findTravelByDriverId(userId, start, count, from, to, order);
    }

    public List<Travel> searchTravels(TravelRequest travelRequest, String userId) {

        List<Travel> searchTravels = new ArrayList<Travel>();

        searchTravels = travelRepository.searchTravelsExtended(travelRequest);

        if (travelRequest.isMonitored()) {

            String fromName = "";
            String toName = "";
            String fromAddr = "";
            String toAddr = "";
            // make sure if its the logged in user.
            travelRequest.setUserId(userId);

            if (travelRequest.getCommunityIds().isEmpty()) {
                List<String> communityIds = communityRepository.getCommunityIdsForUser(userId);
                travelRequest.setCommunityIds(communityIds);
            }

            if (travelRequest.getFrom().getName() != null && !travelRequest.getFrom().getName().isEmpty()) {
                fromName = travelRequest.getFrom().getName();
            }

            if (travelRequest.getFrom().getAddress() != null && !travelRequest.getFrom().getAddress().isEmpty()) {
                fromAddr = travelRequest.getFrom().getAddress();
            }

            if (travelRequest.getTo().getName() != null && !travelRequest.getTo().getName().isEmpty()) {
                toName = travelRequest.getTo().getName();
            }

            if (travelRequest.getTo().getAddress() != null && !travelRequest.getTo().getAddress().isEmpty()) {
                toAddr = travelRequest.getTo().getAddress();
            }
            // from.
            Zone updateFrom = new Zone(fromName, fromAddr, travelRequest.getFrom().getLatitude(),
                    travelRequest.getFrom().getLongitude(), travelRequest.getFrom().getRange());
            travelRequest.setFrom(updateFrom);
            // to
            Zone updateTo = new Zone(toName, toAddr, travelRequest.getTo().getLatitude(),
                    travelRequest.getTo().getLongitude(), travelRequest.getTo().getRange());
            travelRequest.setTo(updateTo);

            travelRequestRepository.save(travelRequest);
        }

        return searchTravels;
    }

    public List<Travel> searchCommunityTravels(String communityId, Long timeInMillies) {

        List<Travel> communityTravels = travelRepository.searchCommunityTravels(communityId, timeInMillies);

        return communityTravels;
    }

    public RecurrentTravel bookRecurrentTravel(String travelId, RecurrentBooking reqBooking, String userId)
            throws CarPoolingCustomException {

        RecurrentTravel travel = reccurrentTravelRepository.findOne(travelId);

        if (travel != null) {

            travel = updateRecurrentTravelBooking(travel, reqBooking, userId);

        } else {
            throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "travel not found.");
        }

        return travel;
    }

    /**
     * Update Booking of Recurrent Travel + Instances.
     * 
     * @param recurrentTravel
     * @param reqBooking
     * @param userId
     * @return
     * @throws CarPoolingCustomException
     */
    private RecurrentTravel updateRecurrentTravelBooking(RecurrentTravel recurrentTravel,
            RecurrentBooking reqBooking, String userId) throws CarPoolingCustomException {

        List<Travel> tranistInstances = travelRepository.findFutureInstanceOfRecurrTravel(recurrentTravel.getId());

        if (tranistInstances != null && !tranistInstances.isEmpty()) {

            // booking instance to replicate.
            Booking instanceBooking = new Booking();
            instanceBooking.setAccepted(0);
            instanceBooking.setTraveller(reqBooking.getTraveller());
            instanceBooking.setRecurrent(true);
            instanceBooking.setDate(new java.util.Date(System.currentTimeMillis()));

            for (Travel instance : tranistInstances) {

                List<Booking> transitStateBooking = instance.getBookings();

                int availability = instance.getPlaces();

                if (transitStateBooking.isEmpty()) {
                    // add new booking to instance.
                    transitStateBooking.add(instanceBooking);

                } else {

                    List<Booking> temp = new ArrayList<Booking>();
                    temp.addAll(transitStateBooking);

                    boolean updatedNewBooking = false;
                    for (Booking uBooking : temp) {

                        if (uBooking.getTraveller().getUserId().equalsIgnoreCase(userId)) {
                            // 1. check if user is present with recurrent
                            // booking -> throw exception [USER ALREADY
                            // BOOKED].
                            if (uBooking.isRecurrent()) {
                                throw new CarPoolingCustomException(HttpStatus.FORBIDDEN.value(),
                                        "user has already booked.");
                            }
                            // 2. if user is present with non recurrent booking
                            // -> override it.
                            if (!uBooking.isRecurrent()) {
                                transitStateBooking.remove(uBooking);
                                uBooking.setRecurrent(true);
                                uBooking.setAccepted(0);
                                transitStateBooking.add(uBooking);
                                updatedNewBooking = true;
                                break;
                            }
                        } else if (uBooking.getAccepted() != -1) {
                            availability--; // 3. if not present check for
                            // availability
                        }
                    }
                    if (availability < 1) {
                        throw new CarPoolingCustomException(HttpStatus.PRECONDITION_FAILED.value(),
                                "travel not bookable.");
                    }
                    if (!updatedNewBooking) {
                        // add new booking to instance.
                        transitStateBooking.add(instanceBooking);
                    }
                }
            }

            // update recurrent travel.
            reqBooking.getTraveller().setUserId(userId);
            reqBooking.setAccepted(0);

            boolean alreadyBooked = false;
            List<RecurrentBooking> tmpList = new ArrayList<RecurrentBooking>();
            if (recurrentTravel.getBookings() != null)
                tmpList.addAll(recurrentTravel.getBookings());
            for (RecurrentBooking uBooking : tmpList) {
                if (userId.equals(uBooking.getTraveller().getUserId())) {
                    alreadyBooked = true;
                    // if in the past was rejected, allow for being re-booked
                    // again? consider rejecting
                    if (uBooking.getAccepted() == -1) {
                        uBooking.setAccepted(0);
                        reccurrentTravelRepository.save(recurrentTravel);
                    }
                    break;
                }
            }
            if (!alreadyBooked) {
                recurrentTravel.getBookings().add(reqBooking);
                reccurrentTravelRepository.save(recurrentTravel);
            }

            // update travel instances of recurrent travel.
            travelRepository.save(tranistInstances);

            // create notification.
            String targetUserId = recurrentTravel.getUserId();
            Map<String, String> data = new HashMap<String, String>();
            data.put("senderId", userId);
            User user = userRepository.findOne(userId);
            data.put("senderFullName", user.fullName());
            // always notify with instance of recurrent travel.
            Notification bookingNotification = new Notification(targetUserId, CarPoolingUtils.NOTIFICATION_BOOKING,
                    data, false, tranistInstances.get(0).getId(), System.currentTimeMillis());
            notificationRepository.save(bookingNotification);
            // notify via parse.
            try {
                sendPushNotification.sendNotification(targetUserId, bookingNotification);
            } catch (JSONException e) {
                throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
            }

        } else {
            throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(),
                    "no instance found for reccurrent travel.");
        }

        return recurrentTravel;

    }

    public Travel bookNonRecurrent(String travelId, Booking reqBooking, String userId)
            throws CarPoolingCustomException {

        Travel travel = travelRepository.findOne(travelId);

        if (travel != null) {

            if (CarPoolingUtils.isValidUser(travel, userId, reqBooking)) {

                if (CarPoolingUtils.havePlaces(travel, reqBooking, userId)) {
                    reqBooking.setRecurrent(false);
                    reqBooking.getTraveller().setUserId(userId);
                    reqBooking.setAccepted(0);
                    reqBooking.setDate(new java.util.Date(System.currentTimeMillis()));
                    travel.getBookings().add(reqBooking);
                    // save travel.
                    travelRepository.save(travel);

                } else {
                    throw new CarPoolingCustomException(HttpStatus.PRECONDITION_FAILED.value(),
                            "travel not bookable.");
                }
                // create notification.
                String targetUserId = travel.getUserId();
                Map<String, String> data = new HashMap<String, String>();
                data.put("senderId", userId);
                User user = userRepository.findOne(userId);
                data.put("senderFullName", user.fullName());
                Notification bookingNotification = new Notification(targetUserId,
                        CarPoolingUtils.NOTIFICATION_BOOKING, data, false, travel.getId(),
                        System.currentTimeMillis());
                notificationRepository.save(bookingNotification);
                // notify via parse.
                try {
                    sendPushNotification.sendNotification(targetUserId, bookingNotification);
                } catch (JSONException e) {
                    throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
                }

            } else {
                throw new CarPoolingCustomException(HttpStatus.FORBIDDEN.value(), "user has already booked.");
            }
        } else {
            throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "travel not found.");
        }

        return travel;
    }

    /**
     * @param tripId
     * @return
     * @throws CarPoolingCustomException
     */
    public Travel getTrip(String tripId) throws CarPoolingCustomException {
        Travel travel = travelRepository.findOne(tripId);

        if (travel != null) {
            return travel;
        }
        throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "travel not found.");
    }

    public RecurrentTravel acceptRecurrentTrip(String travelId, RecurrentBooking booking, String userId)
            throws CarPoolingCustomException {

        RecurrentTravel travel = reccurrentTravelRepository.findTravelByIdAndDriverId(travelId, userId);
        Travel instanceOfReccTravel = null;

        boolean found = false;

        if (travel != null) {
            for (RecurrentBooking book : travel.getBookings()) {
                if (book.equals(booking)) {
                    book.setAccepted(booking.getAccepted());
                    found = true;
                    /**
                     * update instances. (reject instances where recurrentId is
                     * travelId and booking.traveller.userId is
                     * recurrBooking->traveller.userId
                     */
                    // passengerId.
                    String passengerId = booking.getTraveller().getUserId();

                    for (Travel instanceRT : travelRepository.findInstanceOfRecurrTravel(travelId)) {
                        for (Booking instanceBooking : instanceRT.getBookings()) {
                            if (instanceBooking.getTraveller().getUserId().equalsIgnoreCase(passengerId)) {
                                if (instanceOfReccTravel == null) {
                                    instanceOfReccTravel = instanceRT;
                                }
                                instanceBooking.setAccepted(booking.getAccepted());
                                travelRepository.save(instanceRT);
                            }
                        }
                    }
                    reccurrentTravelRepository.save(travel);
                    break;
                }
            }

            if (found && instanceOfReccTravel != null) {

                String targetUserId = booking.getTraveller().getUserId();
                Map<String, String> data = new HashMap<String, String>();
                data.put("status", "" + booking.getAccepted());
                // always notify with instance of recurrent travel.
                Notification confirmNotification = new Notification(targetUserId,
                        CarPoolingUtils.NOTIFICATION_CONFIRM, data, false, instanceOfReccTravel.getId(),
                        System.currentTimeMillis());
                notificationRepository.save(confirmNotification);
                try {
                    sendPushNotification.sendNotification(targetUserId, confirmNotification);
                } catch (JSONException e) {
                    throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
                }
            } else {
                throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "booking not found");
            }
        } else {
            throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "travel not found");
        }

        return travel;
    }

    public Travel acceptNonRecurrentTrip(String travelId, Booking booking, String userId)
            throws CarPoolingCustomException {

        Travel travel = travelRepository.findTravelByIdAndDriverId(travelId, userId);
        // travelRepository.findOne(travelId);

        boolean found = false;

        if (travel != null) {
            for (Booking book : travel.getBookings()) {
                if (book.equals(booking)) {
                    book.setAccepted(booking.getAccepted());
                    found = true;
                    break;
                }
            }

            if (found) {
                travelRepository.save(travel);
                String targetUserId = booking.getTraveller().getUserId();
                Map<String, String> data = new HashMap<String, String>();
                data.put("status", "" + booking.getAccepted());
                Notification confirmNotification = new Notification(targetUserId,
                        CarPoolingUtils.NOTIFICATION_CONFIRM, data, false, travel.getId(),
                        System.currentTimeMillis());
                notificationRepository.save(confirmNotification);
                try {
                    sendPushNotification.sendNotification(targetUserId, confirmNotification);
                } catch (JSONException e) {
                    throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
                }
            } else {
                throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "booking not found");
            }
        } else {
            throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "travel not found");
        }

        return travel;
    }

    public List<Community> readCommunities(String userId) {

        List<Community> filteredCommunities = new ArrayList<Community>();
        List<Community> communities = communityRepository.findByUserId(userId);

        for (Community community : communities) {
            Community temp = new Community(community.getId(), community.getName(), community.getUsers());
            temp.setColor(community.getColor());
            filteredCommunities.add(temp);
        }

        return filteredCommunities;
    }

    public List<Community> readCommunitiesWithDetails(String userId) {
        List<Community> detailedCommunities = new ArrayList<Community>();
        List<Community> communities = communityRepository.findByUserId(userId);

        for (Community community : communities) {

            int nrOfCars = 0;

            for (String id : community.getUsers()) {
                User user = userRepository.findOne(id);
                if (user != null) {
                    community.getUserObjs().add(user);
                    // incremet car total(if present).
                    if (user.getAuto() != null) {
                        nrOfCars = nrOfCars + 1;
                    }
                }

            }
            community.setCars(nrOfCars);
            detailedCommunities.add(community);
        }

        return detailedCommunities;
    }

    public Community readCommunity(String communityId) {

        Community community = communityRepository.findOne(communityId);

        if (community != null) {

            int nrOfCars = 0;

            for (String id : community.getUsers()) {
                User user = userRepository.findOne(id);
                if (user != null) {
                    community.getUserObjs().add(user);
                    // incremet car total(if present).
                    if (user.getAuto() != null) {
                        nrOfCars = nrOfCars + 1;
                    }
                }

            }
            community.setCars(nrOfCars);
        }

        return community;
    }

    public TravelProfile saveTravelProfile(TravelProfile travelProfile, String userId) {

        User user = userRepository.findOne(userId);
        TravelProfile saveProfile = null;

        if (user != null) {
            user.setTravelProfile(travelProfile);
            user = userRepository.save(user);
            saveProfile = user.getTravelProfile();
        }

        return saveProfile;

    }

    public TravelProfile readTravelProfile(String userId) throws CarPoolingCustomException {

        TravelProfile travelProfile = null;
        User user = userRepository.findOne(userId);

        if (user != null) {
            if (!user.getTravelProfile().getRoutes().isEmpty()) {
                travelProfile = user.getTravelProfile();
            }

        } else {
            throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "user not found");
        }

        return travelProfile;

    }

    public Map<String, String> ratePassenger(String userId, String passengerId, int rating) {

        Map<String, String> errorMap = new HashMap<String, String>();

        if (userId.equalsIgnoreCase(passengerId)) {

            errorMap.put(CarPoolingUtils.ERROR_CODE, String.valueOf(HttpStatus.FORBIDDEN.value()));
            errorMap.put(CarPoolingUtils.ERROR_MSG, "passenger cannot self rate.");

            return errorMap;

        }

        User passenger = userRepository.findOne(passengerId);

        if (passenger != null) {

            GameProfile gameProfile = passenger.getGameProfile();

            if (gameProfile != null) {
                gameProfile.getPassengerRatings().put(userId, rating);
                recalculateRatings(passenger);
            } else {
                errorMap.put(CarPoolingUtils.ERROR_CODE, String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
                errorMap.put(CarPoolingUtils.ERROR_MSG, "passenger has null game profile.");
            }
        } else {

            errorMap.put(CarPoolingUtils.ERROR_CODE, String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
            errorMap.put(CarPoolingUtils.ERROR_MSG, "passenger does not exist.");

        }

        return errorMap;

    }

    public Integer getMyRatingForPassenger(String userId, String passengerId) throws CarPoolingCustomException {

        Integer rating = null;

        User passenger = userRepository.findOne(passengerId);

        if (passenger != null) {

            GameProfile gameProfile = passenger.getGameProfile();

            if (gameProfile != null && gameProfile.getPassengerRatings().containsKey(userId)) {

                rating = gameProfile.getPassengerRatings().get(userId);

            } else {

                throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(),
                        "passenger rating not found");
            }
        } else {

            throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "passenger not found");
        }

        return rating;
    }

    public void recalculateRatings(User user) {

        GameProfile gameProfile = user.getGameProfile();

        double totalPRater = 0;
        double totalPRating = 0;

        for (String key : gameProfile.getPassengerRatings().keySet()) {

            totalPRating = totalPRating + gameProfile.getPassengerRatings().get(key);
            totalPRater++;
        }

        gameProfile.setPassengerRating(totalPRating / totalPRater);

        double totalDRater = 0;
        double totalDRating = 0;

        for (String key : gameProfile.getDriverRatings().keySet()) {

            totalDRating = totalDRating + gameProfile.getDriverRatings().get(key);
            totalDRater++;
        }

        gameProfile.setDriverRating(totalDRating / totalDRater);

        user.setGameProfile(gameProfile);

        userRepository.save(user);

    }

    public Map<String, String> rateDriver(String userId, String driverId, int rating) {

        Map<String, String> errorMap = new HashMap<String, String>();

        if (userId.equalsIgnoreCase(driverId)) {

            errorMap.put(CarPoolingUtils.ERROR_CODE, String.valueOf(HttpStatus.FORBIDDEN.value()));
            errorMap.put(CarPoolingUtils.ERROR_MSG, "driver cannot self rate.");

            return errorMap;
        }

        User driver = userRepository.findOne(driverId);

        if (driver != null) {
            GameProfile gameProfile = driver.getGameProfile();

            if (gameProfile != null) {

                gameProfile.getDriverRatings().put(userId, rating);
                recalculateRatings(driver);

            } else {

                errorMap.put(CarPoolingUtils.ERROR_CODE, String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
                errorMap.put(CarPoolingUtils.ERROR_MSG, "driver has null game profile.");

            }

        } else {

            errorMap.put(CarPoolingUtils.ERROR_CODE, String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
            errorMap.put(CarPoolingUtils.ERROR_MSG, "driver does not exist.");

        }

        return errorMap;
    }

    /**
     * Get My Rating For Driver.
     * 
     * @param userId
     * @param driverId
     * @return
     * @throws CarPoolingCustomException
     */
    public Integer getMyRatingForDriver(String userId, String driverId) throws CarPoolingCustomException {

        Integer rating = null;

        User driver = userRepository.findOne(driverId);

        if (driver != null) {

            GameProfile gameProfile = driver.getGameProfile();

            if (gameProfile != null && gameProfile.getDriverRatings().containsKey(userId)) {

                rating = gameProfile.getDriverRatings().get(userId);

            } else {
                throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(),
                        "driver rating not found");
            }
        } else {
            throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "driver not found");

        }

        return rating;
    }

    public Map<String, String> updateUserInfo(String userId, UserInfo userInfo) {

        Map<String, String> errorMap = new HashMap<String, String>();

        User driver = userRepository.findOne(userId);

        if (driver != null) {
            if (userInfo != null && userInfo.getAuto() != null) {
                driver.setAuto(userInfo.getAuto());
            }
            if (userInfo.getDisplayName() != null) {
                driver.setDpName(userInfo.getDisplayName());
            }
            if (userInfo.getTelephone() != null) {
                driver.setTelephone(userInfo.getTelephone());
            }
            userRepository.save(driver);
        } else {
            errorMap.put(CarPoolingUtils.ERROR_CODE, String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
            errorMap.put(CarPoolingUtils.ERROR_MSG, "driver does not exist.");

        }

        return errorMap;
    }

    public Map<String, String> sendMessage(String userId, String travelId, Message message) {

        Map<String, String> status = new HashMap<String, String>();

        try {
            Discussion discussion = discussionRepository.findOne(travelId);

            if (discussion == null) {
                discussion = new Discussion();
                discussion.setTravelId(travelId);
            }

            discussion.getMessages().add(message);
            discussionRepository.save(discussion);

            String targetUserId = message.getTargetUserId();
            Map<String, String> data = new HashMap<String, String>();
            data.put("senderId", userId);
            User user = userRepository.findOne(userId);
            data.put("senderFullName", user.fullName());
            data.put("message", message.getMessage());
            Notification chatNotification = new Notification(targetUserId, CarPoolingUtils.NOTIFICATION_CHAT, data,
                    false, travelId, System.currentTimeMillis());
            notificationRepository.save(chatNotification);
            // notify via parse.
            try {
                sendPushNotification.sendNotification(targetUserId, chatNotification);
            } catch (JSONException e) {
                throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
            }

        } catch (Exception e) {
            status.put(CarPoolingUtils.ERROR_CODE, String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
            status.put(CarPoolingUtils.ERROR_MSG, e.getMessage());
        }

        return status;

    }

    public Discussion readDiscussion(String userId, String travelId, String targetUserId) {

        Discussion response = new Discussion();
        response.setTravelId(travelId);
        response.setPersonName(userRepository.findOne(targetUserId).fullName());

        Discussion discussion = discussionRepository.findOne(travelId);

        if (discussion != null) {

            // msgs are ordered by the insertion at server side, since it can be
            // sent from diff timezones.
            for (Message msg : discussion.getMessages()) {
                if ((msg.getUserId().equalsIgnoreCase(userId)
                        && (msg.getTargetUserId().equalsIgnoreCase(targetUserId)))
                        | (msg.getTargetUserId().equalsIgnoreCase(userId)
                                && msg.getUserId().equalsIgnoreCase(targetUserId))) { // targetUserId
                                                                                                                                                                                                                                                 // ==
                                                                                                                                                                                                                                                 // userId.(for
                                                                                                                                                                                                                                                 // drivers)
                                                                                                                                                                                                                                                 // or
                                                                                                                                                                                                                                                 // they
                                                                                                                                                                                                                                                 // understand
                                                                                                                                                                                                                                                 // it
                                                                                                                                                                                                                                                 // from
                                                                                                                                                                                                                                                 // bookings
                    response.getMessages().add(msg);
                }
            }

        }

        return response;
    }

    /**
     * read user.
     * 
     * @param userId
     * @return
     */
    public User readUser(String userId) {
        User user = userRepository.findOne(userId);
        if (user != null) {
            // get count of user offered travels(as driver).
            user.setOfferedTravels(travelRepository.countTravelByDriverId(userId));
            // get count user participated travel(as passenger)
            user.setParticipatedTravels(travelRepository.countTravelByPassengerId(userId));
        }
        return user;
    }

    /**
     * read notifications.
     * 
     * @param userId
     * @param start
     * @param count
     * @return
     */
    public List<Notification> readNotifications(String userId, int start, int count) {

        Page<Notification> notifications = notificationRepository.findByTargetUserId(userId,
                new PageRequest(start, count, Direction.DESC, "timestamp"));

        return notifications.getContent();

    }

    /**
     * read notifications of travel
     * 
     * @param userId
     * @param travelId
     * @return
     */
    public List<Notification> readNotificationsOfTravelId(String travelId) {

        List<Notification> notifications = notificationRepository.findByTravelId(travelId);

        return notifications;
    }

    /**
     * mark notification as read.
     * 
     * @param id
     * @return
     */
    public Map<String, String> markNotification(String id) {

        Map<String, String> errorMap = new HashMap<String, String>();

        Notification notification = notificationRepository.findOne(id);

        if (notification != null) {
            notification.setStatus(true);
            notificationRepository.save(notification);
        } else {
            errorMap.put(CarPoolingUtils.ERROR_CODE, String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
            errorMap.put(CarPoolingUtils.ERROR_MSG, "notification does not exist.");

        }

        return errorMap;
    }

    /**
     * delete notification id.
     * 
     * @param notificationId
     * @return
     */
    public Map<String, String> deleteNotification(String notificationId) {

        Map<String, String> errorMap = new HashMap<String, String>();

        Notification notification = notificationRepository.findOne(notificationId);

        if (notification != null) {
            notificationRepository.delete(notification);
        } else {
            errorMap.put(CarPoolingUtils.ERROR_CODE, String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
            errorMap.put(CarPoolingUtils.ERROR_MSG, "notification does not exist.");

        }

        return errorMap;
    }

    /**
     * delete travel request.
     * 
     * @param travelRequestId
     * @return
     */
    public Map<String, String> deleteTravelRequest(String id, String ownerId) {

        Map<String, String> errorMap = new HashMap<String, String>();

        TravelRequest travelRequest = travelRequestRepository.findTravelRequestIdAndUserId(id, ownerId);

        if (travelRequest != null) {
            travelRequestRepository.delete(travelRequest);
        } else {
            errorMap.put(CarPoolingUtils.ERROR_CODE, String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
            errorMap.put(CarPoolingUtils.ERROR_MSG, "travelRequest does not exist.");

        }

        return errorMap;
    }

    /**
     * Delete Travel.
     * 
     * @param travelId
     * @param userId
     * @return
     * @throws CarPoolingCustomException
     */
    public Map<String, String> deleteTravel(String travelId, String userId) throws CarPoolingCustomException {

        Map<String, String> errorMap = new HashMap<String, String>();

        Travel travel = travelRepository.findTravelByIdAndDriverId(travelId, userId);

        if (travel != null) {
            // check if travel can be deleted.
            if (CarPoolingUtils.isPossibleToDeleteTravel(travel)) {
                travelRepository.delete(travel);
            } else {
                throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(),
                        "cannot delete travel");
            }

        } else {
            throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "travel not found");
        }

        return errorMap;
    }

    /**
     * Delete Recurrent Travel
     * 
     * @param recurrentTravelId
     * @param userId
     * @return
     */
    public Map<String, String> deleteRecurrentTravel(String recurrentTravelId, String userId)
            throws CarPoolingCustomException {

        Map<String, String> errorMap = new HashMap<String, String>();

        RecurrentTravel recurrentTravel = reccurrentTravelRepository.findTravelByIdAndDriverId(recurrentTravelId,
                userId);

        if (recurrentTravel != null) {

            // get all future instances of recurrent travel.
            List<Travel> futureInstances = travelRepository.findFutureInstanceOfRecurrTravel(recurrentTravelId);

            // check if recurrent travel can be deleted.
            if (CarPoolingUtils.isPossibleToDeleteRecurrTravel(recurrentTravel, futureInstances)) {

                // delete future instances.
                if (!futureInstances.isEmpty()) {
                    travelRepository.delete(futureInstances);
                }

                // delete recurrent travel;
                reccurrentTravelRepository.delete(recurrentTravel);
            } else {
                throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(),
                        "cannot delete recurrent travel");
            }

        } else {
            throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(),
                    "recurrent travel not found");
        }

        return errorMap;
    }

    @Scheduled(cron = "0 0 0/1 * * ?")
    public void autoSendEvaluationNotification() throws CarPoolingCustomException {
        logger.info("/**** Firing Rating Notifications****/ ");

        // search for travels that are completed at this time.
        for (Travel travel : travelRepository.searchCompletedTravels(System.currentTimeMillis())) {

            // check if travel is already rated, look in notification.
            List<Notification> travelRatingNotifications = notificationRepository
                    .findByTravelIdAndNotificationType(travel.getId(), CarPoolingUtils.NOTIFICATION_RATING);

            if (travelRatingNotifications != null && travelRatingNotifications.size() > 0) {
                continue;
            } else {
                try {

                    String travelId = travel.getId();
                    Long timestamp = System.currentTimeMillis();

                    // create notifications for passengers.
                    Map<String, String> dataPassengerNotification = new HashMap<String, String>();
                    dataPassengerNotification.put("message",
                            "Si prega di valutare il conducente di viaggio completato");
                    dataPassengerNotification.put("travelId", travelId);

                    boolean nofityDriver = false;

                    for (Booking booking : travel.getBookings()) {
                        if (booking.getAccepted() == 1 && booking.getBoarded() == 1) {
                            nofityDriver = true;
                            String passengerId = booking.getTraveller().getUserId();
                            Notification passengerRatingNotification = new Notification(passengerId,
                                    CarPoolingUtils.NOTIFICATION_RATING, dataPassengerNotification, false, travelId,
                                    timestamp);
                            notificationRepository.save(passengerRatingNotification);
                            sendPushNotification.sendNotification(passengerId, passengerRatingNotification);
                        }
                    }

                    if (nofityDriver) {

                        // create notification for driver only if there is
                        // atleast a passenger accepted.
                        String driverId = travel.getUserId();
                        Map<String, String> dataDriverNotification = new HashMap<String, String>();
                        dataDriverNotification.put("message",
                                "Si prega di valutare i passeggeri del suo viaggio completato");
                        dataDriverNotification.put("travelId", travelId);

                        Notification driverRatingNotification = new Notification(driverId,
                                CarPoolingUtils.NOTIFICATION_RATING, dataDriverNotification, false, travelId,
                                timestamp);
                        notificationRepository.save(driverRatingNotification);
                        sendPushNotification.sendNotification(driverId, driverRatingNotification);

                    }
                } catch (JSONException e) {
                    throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
                }
            }
        }
    }

    // public boolean performUpdateRecurrBooking(RecurrentTravel travel,
    // RecurrentBooking reqBooking, String userId) {
    //
    // boolean bookable = false;
    // int capacity = travel.getPlaces();
    //
    // for (RecurrentBooking booking : travel.getBookings()) {
    // if (booking.getAccepted() != -1) {
    // capacity--;
    // }
    // }
    //
    // // check that there are places in the bookings of all the Travel objects
    // // with this recurrencyId
    // if (capacity > 0) {
    // List<Travel> instances =
    // travelRepository.findFutureInstanceOfRecurrTravel(travel.getId());
    //
    // for (Travel instance : instances) {
    // int seats = instance.getPlaces();
    // for (Booking booking : instance.getBookings()) {
    // if (booking.getAccepted() != -1) {
    // seats--;
    // }
    // }
    // // user must not have booking of himself with recurrent.
    // if (seats < 1) {
    // bookable = false;
    // break;
    // }
    // }
    // }
    // return bookable;
    // }

    public Booking updateBoarding(String tripId, String userId, int boarding) throws CarPoolingCustomException {

        Travel travel = travelRepository.findOne(tripId);

        Booking foundBooking = null;

        for (Booking booking : travel.getBookings()) {
            if (booking.getTraveller().getUserId().equalsIgnoreCase(userId)) {
                booking.setBoarded(boarding);
                foundBooking = booking;
                break;
            }
        }

        if (foundBooking != null) {
            travelRepository.save(travel);
            return foundBooking;
        } else {
            throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "booking not found");
        }

    }

    /**
     * @param tripId
     * @return
     * @throws CarPoolingCustomException
     */
    public Recurrency getRecurrency(String tripId) throws CarPoolingCustomException {
        RecurrentTravel rt = reccurrentTravelRepository.findOne(tripId);
        if (rt != null)
            return rt.getRecurrency();
        throw new CarPoolingCustomException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "recurrent travel not found");
    }

    public List<Community> searchCommunity(String location, String searchText) {
        List<Community> list = communityRepository.searchCommunity(location, searchText);
        for (Community community : list) {
            int nrOfCars = 0;
            for (String id : community.getUsers()) {
                User user = userRepository.findOne(id);
                if (user != null) {
                    if (user.getAuto() != null) {
                        nrOfCars = nrOfCars + 1;
                    }
                }

            }
            community.setCars(nrOfCars);
        }
        return list;
    }

    public Map<String, String> joinCommunity(String userId, String communityId) {

        Map<String, String> errorMap = new HashMap<String, String>();

        Community community = communityRepository.findOne(communityId);

        if (community != null) {
            if (!community.getUsers().contains(userId)) {
                community.getUsers().add(userId);
                communityRepository.save(community);
            } else {
                errorMap.put(CarPoolingUtils.ERROR_CODE, String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
                errorMap.put(CarPoolingUtils.ERROR_MSG, "user already present in community");
            }
        } else {
            errorMap.put(CarPoolingUtils.ERROR_CODE, String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
            errorMap.put(CarPoolingUtils.ERROR_MSG, "no community found");
        }

        return errorMap;

    }

    public Map<String, String> leaveCommunity(String userId, String communityId) {
        Map<String, String> errorMap = new HashMap<String, String>();

        Community community = communityRepository.findOne(communityId);

        if (community != null) {
            if (community.getUsers().contains(userId)) {
                community.getUsers().remove(userId);
                communityRepository.save(community);
            } else {
                errorMap.put(CarPoolingUtils.ERROR_CODE, String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
                errorMap.put(CarPoolingUtils.ERROR_MSG, "user not found in community");
            }

        } else {
            errorMap.put(CarPoolingUtils.ERROR_CODE, String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
            errorMap.put(CarPoolingUtils.ERROR_MSG, "no community found");
        }

        return errorMap;

    }

    /**
     * @param userId
     * @return
     */
    public Long countNotifications(String userId) {
        return notificationRepository.countReadByTargetUserId(userId);
    }

}