package de.flower.rmt.service;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.mysema.query.types.expr.BooleanExpression;
import de.flower.common.util.Check;
import de.flower.rmt.model.db.entity.CalItem;
import de.flower.rmt.model.db.entity.CalItem_;
import de.flower.rmt.model.db.entity.QCalItem;
import de.flower.rmt.model.db.entity.Team;
import de.flower.rmt.model.db.entity.User;
import de.flower.rmt.model.db.entity.event.Event;
import de.flower.rmt.model.dto.CalItemDto;
import de.flower.rmt.repository.ICalItemRepo;
import de.flower.rmt.service.type.CalendarFilter;
import de.flower.rmt.ui.markup.html.calendar.CalEvent;
import org.joda.time.DateTime;
import org.joda.time.LocalTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.metamodel.Attribute;
import java.util.Collection;
import java.util.List;
import static de.flower.rmt.repository.Specs.eq;
import static de.flower.rmt.repository.Specs.fetch;
import static org.springframework.data.jpa.domain.Specifications.where;
/**
* @author flowerrrr
*/
@Service
@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
public class CalendarManager extends AbstractService implements ICalendarManager {
@Autowired
private ICalItemRepo calItemRepo;
@Autowired
private IEventManager eventManager;
@Autowired
private ITeamManager teamManager;
@Autowired
private MessageSourceAccessor messageSource;
@Autowired
private IInvitationManager invitationManager;
@Override
public CalItem loadById(final Long id, Attribute... attributes) {
Specification fetch = fetch(attributes);
CalItem entity = calItemRepo.findOne(where(eq(CalItem_.id, id)).and(fetch));
Check.notNull(entity, "CalItem [" + id + "] not found");
return entity;
}
@Override
public void save(final CalItemDto dto, final User user) {
if (dto.isAllDay()) {
// set start time to 0:00 and end time to 23:59
dto.setStartTime(new LocalTime(0, 0));
dto.setEndTime(new LocalTime(0, 0).minusMillis(1));
}
CalItem entity;
if (dto.isNew()) {
entity = new CalItem();
entity.setUser(user);
} else {
entity = loadById(dto.getId());
}
dto.copyTo(entity);
validate(entity);
calItemRepo.save(entity);
dto.setId(entity.getId());
if (entity.isAutoDecline()) {
invitationManager.onAutoDeclineCalItem(entity);
}
}
@Override
public List<CalEvent> findAllByCalendarAndRange(List<CalendarFilter> calendarFilters, final DateTime start, final DateTime end) {
List<?> list = Lists.newArrayList();
for (CalendarFilter filter : calendarFilters) {
if (filter.type == CalendarFilter.Type.USER) {
list.addAll((Collection) findAllByUserAndRange(securityService.getUser(), start, end));
}
if (filter.type == CalendarFilter.Type.OTHERS) {
list.addAll((Collection) findAllByOthersAndRange(start, end));
}
if (filter.type == CalendarFilter.Type.CLUB) {
list.addAll((Collection) eventManager.findAllByDateRange(start, end));
}
if (filter.type == CalendarFilter.Type.TEAM) {
list.addAll((Collection) findAllByTeamAndRange(filter.team, start, end));
}
}
return transform(list);
}
@Override
public List<CalItem> findAllByUserAndRange(final User user, final DateTime calStart, final DateTime calEnd) {
BooleanExpression isUser = QCalItem.calItem.user.eq(user);
BooleanExpression isNotStartAfterCalEnd = QCalItem.calItem.startDateTime.after(calEnd).not();
BooleanExpression isNotEndBeforeCalStart = QCalItem.calItem.endDateTime.before(calStart).not();
return calItemRepo.findAll(isUser.and(isNotEndBeforeCalStart).and(isNotStartAfterCalEnd));
}
private List<CalItem> findAllByOthersAndRange(final DateTime calStart, final DateTime calEnd) {
BooleanExpression isNotCurrentUser = QCalItem.calItem.user.ne(securityService.getUser());
// NOTE (flowerrrr - 25.06.12) make calitem extend abstractclubrelatedentity and remove this expression
BooleanExpression isClub = QCalItem.calItem.user.club.eq(getClub());
BooleanExpression isNotStartAfterCalEnd = QCalItem.calItem.startDateTime.after(calEnd).not();
BooleanExpression isNotEndBeforeCalStart = QCalItem.calItem.endDateTime.before(calStart).not();
return calItemRepo.findAll(isNotCurrentUser.and(isClub).and(isNotEndBeforeCalStart).and(isNotStartAfterCalEnd));
}
private List<CalItem> findAllByTeamAndRange(final Team team, final DateTime calStart, final DateTime calEnd) {
BooleanExpression isTeam = QCalItem.calItem.user.players.any().team.eq(team);
BooleanExpression isNotStartAfterCalEnd = QCalItem.calItem.startDateTime.after(calEnd).not();
BooleanExpression isNotEndBeforeCalStart = QCalItem.calItem.endDateTime.before(calStart).not();
return calItemRepo.findAll(isTeam.and(isNotEndBeforeCalStart).and(isNotStartAfterCalEnd));
}
private List<CalEvent> transform(List<?> items) {
List<CalEvent> events = Lists.transform(items, new Function<Object, CalEvent>() {
@Override
public CalEvent apply(final Object item) {
if (item instanceof CalItem) {
return toCalEvent((CalItem) item);
} else if (item instanceof Event) {
return toCalEvent((Event) item);
} else {
throw new IllegalArgumentException("Unknown type [" + item + "].");
}
}
});
return Lists.newArrayList(Sets.newHashSet(events)); // filter duplicates
}
private CalEvent toCalEvent(final Event event) {
CalEvent calEvent = new CalEvent();
calEvent.id = Event.class.getSimpleName() + "|" + event.getId();
calEvent.entityId = event.getId();
calEvent.clazzName = Event.class.getName();
calEvent.title = event.getTeam().getName() + ": " + messageSource.getMessage(event.getEventType().getResourceKey());
calEvent.start = event.getDateTime().toDate();
calEvent.end = event.getDateTimeEnd().toDate();
calEvent.allDay = false;
calEvent.className = "cal-type-event";
// calEvent.url = urlProvider.deepLinkEvent(event.getId());
return calEvent;
}
private CalEvent toCalEvent(CalItem calItem) {
CalEvent calEvent = new CalEvent();
calEvent.id = CalItem.class.getSimpleName() + "|" + calItem.getId();
calEvent.entityId = calItem.getId();
calEvent.clazzName = CalItem.class.getName();
if (calItem.getType() == CalItem.Type.OTHER) {
calEvent.title = (calItem.getSummary() == null) ? "" : calItem.getSummary();
} else {
calEvent.title = messageSource.getMessage(CalItem.Type.getResourceKey(calItem.getType()));
calEvent.title += (calItem.getSummary() == null) ? "" : ": " + calItem.getSummary();
}
calEvent.title = calItem.getUser().getFullname() + ": " + calEvent.title;
calEvent.start = calItem.getStartDateTime().toDate();
calEvent.end = calItem.getEndDateTime().toDate();
calEvent.allDay = calItem.isAllDay();
calEvent.className = (securityService.isCurrentUser(calItem.getUser())) ? "cal-type-user" : "cal-type-others";
return calEvent;
}
@Override
public void delete(final Long id) {
CalItem entity = loadById(id);
// no security assertions yet.
calItemRepo.delete(entity);
}
@Override
public List<CalendarFilter> getCalendarFilters() {
List<CalendarFilter> filters = Lists.newArrayList();
filters.add(CalendarFilter.USER);
filters.add(CalendarFilter.CLUB);
filters.add(CalendarFilter.OTHERS);
for (Team team : teamManager.findAll()) {
filters.add(new CalendarFilter(CalendarFilter.Type.TEAM, team));
}
return filters;
}
}