public BaseResponseAjaxModel LikeDislike(int tripId, string userId, bool value)
        {
            var dbTrip = this.GetById(tripId);
            var response = new BaseResponseAjaxModel();

            if (dbTrip == null)
            {
                response.ErrorMessage = "No such trip.";
                return response;
            }

            Like like = dbTrip.Likes
                .Where(l => l.UserId == userId && l.IsDeleted == false)
                .FirstOrDefault();

            if (like == null)
            {
                like = new Like()
                {
                    TripId = dbTrip.Id,
                    UserId = userId,
                    Value = value
                };

                dbTrip.Likes.Add(like);
            }
            else
            {
                like.Value = value;
            }

            this.tripRepos.Save();

            response.Status = true;
            response.Data = this.GetLikesCount(dbTrip);

            return response;
        }
        public BaseResponseAjaxModel DisapproveJoinRequest(int tripId, string username, string actionUserId)
        {
            var dbTrip = this.GetById(tripId);
            var response = new BaseResponseAjaxModel();

            if (dbTrip == null)
            {
                response.ErrorMessage = "No such trip.";
                return response;
            }

            if (dbTrip.DriverId != actionUserId)
            {
                response.ErrorMessage = "Only driver of the trip is authorized to perfome this action.";
                return response;
            }

            var passengerTrip = dbTrip.Passengers
                .Where(p => p.TripId == tripId && p.User.UserName == username && p.Approved == false && p.IsDeleted == false)
                .FirstOrDefault();

            if (passengerTrip == null)
            {
                response.ErrorMessage = "Such join request does not exist.";
                return response;
            }

            this.notificationServices.Create(
                dbTrip.Id,
                actionUserId,
                passengerTrip.UserId,
                NotificationConstants.TripRequestDisaprovedTitle,
                string.Format(NotificationConstants.TripRequestDisaprovedFormat, passengerTrip.User.UserName, dbTrip.From.Name, dbTrip.To.Name, dbTrip.DateOfLeaving.ToString("dd/MM/yyyy HH:mm")),
                NotificationKey.JoinTripDisApproved,
                dbTrip.DateOfLeaving);

            passengerTrip.IsDeleted = true;
            this.tripRepos.Save();

            response.Status = true;
            response.Data = new ApprovedJoinRequestResponseModel()
            {
                PendingApproveUsersCount = dbTrip.Passengers.Where(p => p.Approved == false && p.IsDeleted == false).Count(),
            };
            response.SignalRModel = this.notificationServices.SendNotifications(new string[] { passengerTrip.UserId });

            return response;
        }
        public BaseResponseAjaxModel LoadComments(int tripId, int offset)
        {
            var dbTrip = this.GetById(tripId);
            var response = new BaseResponseAjaxModel();

            if (dbTrip == null)
            {
                response.ErrorMessage = "No such trip.";
                return response;
            }

            var comments = dbTrip.Comments
                .Where(c => c.IsDeleted == false)
                .OrderByDescending(c => c.CreatedOn)
                .Skip(offset)
                .Take(WebApplicationConstants.CommentsOfset)
                .Select(c => new CommentResponseModel()
                {
                    FirstName = c.Author.FirstName,
                    LastName = c.Author.LastName,
                    UserUrl = ServicesDataProvider.GetProfileUrl(c.Author.UserName, c.Author.FirstName, c.Author.LastName),
                    UserImageSrc = ServicesDataProvider.GetUserImageSmallUrl(c.Author.Avatar.FileName),
                    CreatedOnFormatted = c.CreatedOn.ToString("dd.MM.yyyy HH:mm"),
                    CommentText = c.Text
                })
                .ToList();

            if (comments.Count() > 0)
            {
                int newOffset = offset + WebApplicationConstants.CommentsOfset;
                bool hasMoreCommentsToLoad = this.CheckIfTripHasMoreCommentsToLoad(dbTrip.Id, newOffset);

                response.Status = true;
                response.Data = new LoadedCommentsResponseModel()
                {
                    HasMoreCommentsToLoad = hasMoreCommentsToLoad,
                    Offset = newOffset,
                    Comments = comments
                };
            }

            return response;
        }
        public BaseResponseAjaxModel ApproveJoinRequest(int tripId, string username, string actionUserId)
        {
            var dbTrip = this.GetById(tripId);
            var response = new BaseResponseAjaxModel();

            if (dbTrip == null)
            {
                response.ErrorMessage = "No such trip.";
                return response;
            }

            if (dbTrip.DriverId != actionUserId)
            {
                response.ErrorMessage = "Only driver of the trip is authorized to perfome this action.";
                return response;
            }

            var passengerTrip = dbTrip.Passengers
                .Where(p => p.TripId == tripId && p.User.UserName == username && p.Approved == false && p.IsDeleted == false)
                .FirstOrDefault();

            if (passengerTrip == null)
            {
                response.ErrorMessage = "Such join request does not exist.";
                return response;
            }

            bool tripHasAvailableSeats = dbTrip.AvailableSeats > 0;

            if (!tripHasAvailableSeats)
            {
                response.ErrorMessage = "Sorry, no available seats left.";

                return response;
            }

            passengerTrip.Approved = true;
            dbTrip.AvailableSeats = dbTrip.AvailableSeats - 1;
            this.tripRepos.Save();

            this.notificationServices.Create(
                dbTrip.Id,
                actionUserId,
                passengerTrip.UserId,
                NotificationConstants.TripRequestApprovedTitle,
                string.Format(NotificationConstants.TripRequestApprovedFormat, passengerTrip.User.UserName, dbTrip.From.Name, dbTrip.To.Name, dbTrip.DateOfLeaving.ToString("dd/MM/yyyy HH:mm")),
                NotificationKey.JoinTripApproved,
                dbTrip.DateOfLeaving);

            response.Status = true;
            response.Data = new ApprovedJoinRequestResponseModel()
            {
                PassengersCount = dbTrip.Passengers.Where(p => p.Approved == true && p.IsDeleted == false).Count(),
                AvailableSeatsCount = dbTrip.AvailableSeats,
                PendingApproveUsersCount = dbTrip.Passengers.Where(p => p.Approved == false && p.IsDeleted == false).Count(),
                FirstName = passengerTrip.User.FirstName,
                LastName = passengerTrip.User.LastName,
                ImageSrc = ServicesDataProvider.GetUserImageSmallUrl(passengerTrip.User.Avatar.FileName),
                UserProfileLink = ServicesDataProvider.GetProfileUrl(passengerTrip.User.UserName, passengerTrip.User.FirstName, passengerTrip.User.LastName)
            };

            response.SignalRModel = this.notificationServices.SendNotifications(new string[] { passengerTrip.UserId });
            return response;
        }
        public BaseResponseAjaxModel AddComment(int tripId, string userId, string commentText)
        {
            var response = new BaseResponseAjaxModel();

            if (commentText.Length < ModelConstants.CommentTextMinLength || commentText.Length > ModelConstants.CommentTextMaxLength)
            {
                response.ErrorMessage = string.Format("Comment text should be between {0} and {1} symbols long", ModelConstants.CommentTextMinLength, ModelConstants.CommentTextMaxLength);
                return response;
            }

            var dbTrip = this.GetById(tripId);

            if (dbTrip == null)
            {
                response.ErrorMessage = "No such trip";
                return response;
            }

            TripComment comment = new TripComment()
            {
                TripId = tripId,
                AuthorId = userId,
                Text = commentText
            };

            dbTrip.Comments.Add(comment);
            this.tripRepos.Save();
            this.tripRepos.Reload(dbTrip);

            var author = this.userServices.GetById(userId);

            response.Status = true;
            response.Data = new CommentResponseModel()
            {
                FirstName = author.FirstName,
                LastName = author.LastName,
                UserUrl = ServicesDataProvider.GetProfileUrl(author.UserName, author.FirstName, author.LastName),
                UserImageSrc = ServicesDataProvider.GetUserImageSmallUrl(author.Avatar.FileName),
                CreatedOnFormatted = comment.CreatedOn.ToString("dd.MM.yyyy HH:mm"),
                CommentText = comment.Text,
                CommentTotalCount = dbTrip.Comments.Count
            };

            return response;
        }
        public BaseResponseAjaxModel LeaveTrip(int tripId, string userId)
        {
            var response = new BaseResponseAjaxModel();
            var dbTrip = this.GetById(tripId);

            if (dbTrip == null)
            {
                response.ErrorMessage = "No such trip";
                return response;
            }

            var passengerTrip = dbTrip.Passengers
                .Where(p => p.UserId == userId && p.IsDeleted == false)
                .FirstOrDefault();

            if (passengerTrip == null)
            {
                response.ErrorMessage = "You first need to send join request.";
                return response;
            }

            var passengerToLeave = this.userServices.GetById(userId);

            passengerTrip.IsDeleted = true;
            this.tripRepos.Save();

            // Add 1 available seat to trip
            if (passengerTrip.Approved == true)
            {
                dbTrip.AvailableSeats = dbTrip.AvailableSeats + 1;
            }

            this.notificationServices.Create(
                dbTrip.Id,
                userId,
                dbTrip.Driver.Id,
                NotificationConstants.PassengerLeftTripTitle,
                string.Format(NotificationConstants.PassengerLeftTripMessageFormat, passengerTrip.User.UserName, dbTrip.From.Name, dbTrip.To.Name, dbTrip.DateOfLeaving.ToString("dd/MM/yyyy HH:mm")),
                NotificationKey.PassengerLeftTrip,
                dbTrip.DateOfLeaving);

            response.Status = true;
            response.Data = new LeftTripResponseModel()
            {
                PassengersCount = dbTrip.Passengers.Where(p => p.Approved == true && p.IsDeleted == false).Count(),
                AvailableSeatsCount = dbTrip.AvailableSeats,
                UserName = passengerToLeave.UserName
            };
            response.SignalRModel = this.notificationServices.SendNotifications(new string[] { dbTrip.DriverId });
            return response;
        }
        public BaseResponseAjaxModel JoinRequest(int tripId, string userId)
        {
            var response = new BaseResponseAjaxModel();
            var dbTrip = this.GetById(tripId);

            if (dbTrip == null)
            {
                response.ErrorMessage = "No such trip";
                return response;
            }

            bool tripHasAvailableSeats = dbTrip.AvailableSeats > 0;

            if (!tripHasAvailableSeats)
            {
                response.ErrorMessage = "Sorry, no available seats left.";
                return response;
            }

            bool currentPassengerAlreadyHasJoinRequest = dbTrip.Passengers
                .Where(p => p.UserId == userId && p.IsDeleted == false)
                .FirstOrDefault()
                != null ? true : false;

            if (currentPassengerAlreadyHasJoinRequest)
            {
                response.ErrorMessage = "You already has pending join request";
                return response;
            }

            PassengerTrip passengerTrip = new PassengerTrip()
            {
                Trip = dbTrip,
                UserId = userId,
                Approved = false
            };

            dbTrip.Passengers.Add(passengerTrip);
            this.tripRepos.Save();

            var passenger = this.userServices.GetById(userId);
            this.notificationServices.Create(
                dbTrip.Id,
                userId,
                dbTrip.DriverId,
                NotificationConstants.JoinTripRequestTitle,
                string.Format(NotificationConstants.JoinTripRequestMessageFormat, passenger.UserName, dbTrip.From.Name, dbTrip.To.Name, dbTrip.DateOfLeaving.ToString("dd/MM/yyyy HH:mm")),
                NotificationKey.JoinTripRequest,
                dbTrip.DateOfLeaving);

            response.Status = true;
            response.SignalRModel = this.notificationServices.SendNotifications(new string[] { dbTrip.DriverId });
            return response;
        }
        public BaseResponseAjaxModel Edit(int tripId, DateTime dateOfLeaving, int leftAvailableSeats, string placeOfLeaving, bool pickUpFromAddress, string description, DateTime eta, IEnumerable<string> usernamesToBeRemoved)
        {
            var dbTrip = this.GetById(tripId);

            int availableSeats = leftAvailableSeats;
            dbTrip.AvailableSeats = availableSeats;

            dbTrip.DateOfLeaving = dateOfLeaving;
            dbTrip.PlaceOfLeaving = placeOfLeaving;
            dbTrip.PickUpFromAddress = pickUpFromAddress;
            dbTrip.Description = description;
            dbTrip.ETA = eta;

            var userIdsToBeNotified = new List<string>();

            foreach (var username in usernamesToBeRemoved)
            {
                PassengerTrip passengerToRemove = dbTrip.Passengers
                    .Where(p => p.User.UserName == username && p.Approved == true && p.IsDeleted == false)
                    .FirstOrDefault();

                if (passengerToRemove != null)
                {
                    this.notificationServices.Create(
                    dbTrip.Id,
                    dbTrip.DriverId,
                    passengerToRemove.UserId,
                    NotificationConstants.DriverRemovePassegerTitle,
                    string.Format(NotificationConstants.DriverRemovePassegerFormat, dbTrip.Driver.UserName, dbTrip.From.Name, dbTrip.To.Name, dbTrip.DateOfLeaving.ToString("dd/MM/yyyy HH:mm")),
                    NotificationKey.DriverRemovePassenger,
                    dbTrip.DateOfLeaving);

                    userIdsToBeNotified.Add(passengerToRemove.UserId);
                    this.passengerTripsRepos.HardDelete(passengerToRemove);
                }
            }

            foreach (var passenger in dbTrip.Passengers.Where(p => p.Approved == true))
            {
                this.notificationServices.Create(
                    dbTrip.Id,
                    dbTrip.DriverId,
                    passenger.UserId,
                    NotificationConstants.TripChangedTitle,
                    string.Format(NotificationConstants.TripChangedpMessageFormat, dbTrip.Driver.UserName, dbTrip.From.Name, dbTrip.To.Name, dbTrip.DateOfLeaving.ToString("dd/MM/yyyy HH:mm")),
                    NotificationKey.TripChanged,
                    dbTrip.DateOfLeaving);

                userIdsToBeNotified.Add(passenger.UserId);
            }

            this.passengerTripsRepos.Save();
            this.tripRepos.Save();

            var response = new BaseResponseAjaxModel();
            response.SignalRModel = this.notificationServices.SendNotifications(userIdsToBeNotified);

            return response;
        }