package com.ciandt.techgallery.service.impl.profile;
import java.util.List;
import com.ciandt.techgallery.persistence.dao.impl.profile.UserProfileDaoImpl;
import com.ciandt.techgallery.persistence.model.Endorsement;
import com.ciandt.techgallery.persistence.model.Skill;
import com.ciandt.techgallery.persistence.model.TechGalleryUser;
import com.ciandt.techgallery.persistence.model.Technology;
import com.ciandt.techgallery.persistence.model.TechnologyComment;
import com.ciandt.techgallery.persistence.model.TechnologyRecommendation;
import com.ciandt.techgallery.persistence.model.profile.UserProfile;
import com.ciandt.techgallery.persistence.model.profile.UserProfileItem;
import com.ciandt.techgallery.service.impl.TechnologyServiceImpl;
import com.ciandt.techgallery.service.impl.UserServiceTGImpl;
import com.ciandt.techgallery.service.profile.UserProfileService;
import com.google.api.server.spi.response.BadRequestException;
import com.google.api.server.spi.response.InternalServerErrorException;
import com.google.api.server.spi.response.NotFoundException;
import com.google.appengine.api.users.User;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.Ref;
public class UserProfileServiceImpl implements UserProfileService {
private static UserProfileServiceImpl instance;
static final int RECOMMEND_TECHNOLOGY_POSITIVELY = 1;
static final int RECOMMEND_TECHNOLOGY_NEGATIVELY = 2;
static final int REMOVE_TECHNOLOGY_RECOMMENDATION = 3;
static final int MAKE_COMMENT = 4;
static final int REMOVE_COMMENT = 5;
static final int SET_SKILL = 6;
static final int ENDORSE = 7;
static final int REMOVE_ENDORSEMENT = 8;
private UserProfileServiceImpl() {}
/**
* Singleton method for the service.
*
* @return UserProfileServiceImpl instance.
*/
public static UserProfileServiceImpl getInstance() {
if (instance == null) {
instance = new UserProfileServiceImpl();
}
return instance;
}
private UserProfile findUserProfileByOwner(TechGalleryUser user) {
return UserProfileDaoImpl.getInstance().findByUser(Key.create(user));
}
private UserProfileItem getTechnologyItem(Technology technology, UserProfile profile) {
// If the user already has an item for this technology, find it.
UserProfileItem item = profile.getItem(Key.create(technology));
// Create a new one if it doesn't exist
if (item == null) {
item = new UserProfileItem(technology);
}
return item;
}
private Boolean itemHasOtherPropertiesSet(UserProfileItem item) {
return item.getSkillLevel() > 0 || !item.getComments().isEmpty()
|| item.getEndorsementQuantity() > 0;
}
@Override
public UserProfile findUserProfileByEmail(String email) throws NotFoundException {
TechGalleryUser owner = UserServiceTGImpl.getInstance().getUserByEmail(email);
return findUserProfileByOwner(owner);
}
public List<UserProfile> findAllUsersProfile() throws NotFoundException {
return UserProfileDaoImpl.getInstance().findAll();
}
@Override
public UserProfile addItem(Technology technology, User user)
throws NotFoundException, BadRequestException, InternalServerErrorException {
TechGalleryUser owner = UserServiceTGImpl.getInstance().getUserByEmail(user.getEmail());
UserProfile profile = findUserProfileByOwner(owner);
technology = TechnologyServiceImpl.getInstance().getTechnologyById(technology.getId(), user);
UserProfileItem newItem = new UserProfileItem(technology);
profile.addItem(UserProfile.POSITIVE_RECOMMENDATION, Key.create(technology), newItem);
profile.addItem(UserProfile.NEGATIVE_RECOMMENDATION, Key.create(technology), newItem);
profile.addItem(UserProfile.OTHER, Key.create(technology), newItem);
UserProfileDaoImpl.getInstance().add(profile);
return profile;
}
// TODO cache profile
@Override
public UserProfile createProfile(TechGalleryUser tgUser) {
UserProfile profile = findUserProfileByOwner(tgUser);
if (profile == null) {
profile = new UserProfile(tgUser);
UserProfileDaoImpl.getInstance().add(profile);
}
return profile;
}
/**
* Given a recommendation (active or inactive, positive or negative) places the Technology item in
* the category according to the recommendation score and status.
*
* @param recommendation the reference to the recommendation to be handled
*/
@Override
public void handleRecommendationChanges(TechnologyRecommendation recommendation) {
Ref<Technology> technologyRef = recommendation.getTechnology();
Technology technology = technologyRef.get();
Key<Technology> technologyKey = technologyRef.getKey();
UserProfile profile = findUserProfileByOwner(recommendation.getRecommender().get());
if (profile != null) {
UserProfileItem item = getTechnologyItem(technology, profile);
// If recommendation is active, add to positive/negative categories according to
// recommendation score
if (recommendation.getActive()) {
if (recommendation.getScore()) {
profile.addItem(UserProfile.POSITIVE_RECOMMENDATION, technologyKey, item);
} else {
profile.addItem(UserProfile.NEGATIVE_RECOMMENDATION, technologyKey, item);
}
// If recommendation is not active, move to category "other" only if item has other
// properties set
} else {
if (itemHasOtherPropertiesSet(item)) {
profile.addItem(UserProfile.OTHER, technologyKey, item);
} else {
profile.removeItem(technologyKey);
}
}
UserProfileDaoImpl.getInstance().add(profile);
}
}
/**
* Given a comment (active or inactive), applies the following rules:<br>
* If it is an active comment:<br>
* If it's the first user activity on the technology, creates a new item on "other". Otherwise,
* just add the comment on the item.<br>
* If it is an inactive comment:<br>
* Removes the comment from the item If the item is on "other" and is the last activity (no more
* comments, skill or endorsements for the user), removes the whole item.
*
* @param comment the comment that was added or removed
*/
@Override
public void handleCommentChanges(TechnologyComment comment) {
Ref<Technology> technologyRef = comment.getTechnology();
Technology technology = technologyRef.get();
Key<Technology> technologyKey = technologyRef.getKey();
UserProfile profile = findUserProfileByOwner(comment.getAuthor().get());
if (profile != null) {
UserProfileItem item = getTechnologyItem(technology, profile);
Integer category = profile.getItemCategory(technologyKey);
// Adds a comment to the item and inserts the item into "other" if it's a new item
if (comment.getActive()) {
item.addComment(comment);
// No previous category means new item
if (category == null) {
profile.addItem(UserProfile.OTHER, technologyKey, item);
} else {
profile.addItem(category, technologyKey, item);
}
} else {
// Comment deletion case
item.removeComment(comment);
if (category == UserProfile.OTHER) {
if (!itemHasOtherPropertiesSet(item)) {
profile.removeItem(technologyKey);
}
}
}
UserProfileDaoImpl.getInstance().add(profile);
}
}
/**
* When a user sets a new skill level, this method is called to propagate such change on the
* user's profile.
*
* @param skill the changed skill
*/
@Override
public void handleSkillChanges(Skill skill) {
Ref<Technology> technologyRef = skill.getTechnology();
Technology technology = technologyRef.get();
Key<Technology> technologyKey = technologyRef.getKey();
UserProfile profile = findUserProfileByOwner(skill.getTechGalleryUser().get());
if (profile != null) {
UserProfileItem item = getTechnologyItem(technology, profile);
Integer category = profile.getItemCategory(technologyKey);
if (skill.getValue() != null && skill.getValue() > 0 && skill.getActive()) {
item.setSkillLevel(skill.getValue());
// No previous category means new item
if (category == null) {
profile.addItem(UserProfile.OTHER, technologyKey, item);
} else {
profile.addItem(category, technologyKey, item);
}
} else {
// Skill deletion case
item.setSkillLevel(0);
if (category == null || category == UserProfile.OTHER) {
if (!itemHasOtherPropertiesSet(item)) {
profile.removeItem(technologyKey);
}
}
}
UserProfileDaoImpl.getInstance().add(profile);
}
}
/**
* When a user endorses another user, this method is called to propagate such change on the
* endorsed user profile.
*
* @param endorsement the recently changed endorsement
*/
@Override
public void handleEndorsement(Endorsement endorsement) {
Ref<Technology> technologyRef = endorsement.getTechnology();
Technology technology = technologyRef.get();
Key<Technology> technologyKey = technologyRef.getKey();
UserProfile profile = findUserProfileByOwner(endorsement.getEndorsed().get());
if (profile != null) {
UserProfileItem item = getTechnologyItem(technology, profile);
Integer category = profile.getItemCategory(technologyKey);
if (endorsement.isActive()) {
item.addToEndorsementsCounter(1);
// No previous category means new item
if (category == null) {
profile.addItem(UserProfile.OTHER, technologyKey, item);
} else {
profile.addItem(category, technologyKey, item);
}
} else {
// Endorsement decrement case
item.addToEndorsementsCounter(-1);
if (category == UserProfile.OTHER) {
if (!itemHasOtherPropertiesSet(item)) {
profile.removeItem(technologyKey);
}
}
}
UserProfileDaoImpl.getInstance().add(profile);
}
}
}