


package org.jasig.schedassist.web.visitor;

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

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.schedassist.RelationshipDao;
import org.jasig.schedassist.SchedulingAssistantService;
import org.jasig.schedassist.impl.owner.OwnerDao;
import org.jasig.schedassist.impl.owner.PublicProfileDao;
import org.jasig.schedassist.impl.visitor.NotAVisitorException;
import org.jasig.schedassist.model.AvailableBlock;
import org.jasig.schedassist.model.IScheduleOwner;
import org.jasig.schedassist.model.IScheduleVisitor;
import org.jasig.schedassist.model.Preferences;
import org.jasig.schedassist.model.PublicProfile;
import org.jasig.schedassist.model.Relationship;
import org.jasig.schedassist.model.VisibleSchedule;
import org.jasig.schedassist.model.VisibleScheduleRequestConstraints;
import org.jasig.schedassist.web.security.CalendarAccountUserDetailsImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

/**
 * Controller that displays the {@link VisibleSchedule} for a particular
 * {@link IScheduleOwner}.
 *  
 * @author Nicholas Blair, nblair@doit.wisc.edu
 * @version $Id: VisibleScheduleDisplayController.java 3006 2011-01-28 19:58:30Z npblair $
 */
@Controller
public class VisibleScheduleDisplayController {

	protected final Log log = LogFactory.getLog(this.getClass());
	private SchedulingAssistantService schedulingAssistantService;
	private RelationshipDao relationshipDao;
	private OwnerDao ownerDao;
	private PublicProfileDao publicProfileDao;

	/**
	 * @param schedulingAssistantService the schedulingAssistantService to set
	 */
	@Autowired
	public void setSchedulingAssistantService(SchedulingAssistantService schedulingAssistantService) {
		this.schedulingAssistantService = schedulingAssistantService;
	}
	/**
	 * @param relationshipDao the relationshipDao to set
	 */
	@Autowired
	public void setRelationshipDao(@Qualifier("composite") RelationshipDao relationshipDao) {
		this.relationshipDao = relationshipDao;
	}
	/**
	 * @param ownerDao the ownerDao to set
	 */
	@Autowired
	public void setOwnerDao(OwnerDao ownerDao) {
		this.ownerDao = ownerDao;
	}
	/**
	 * @param publicProfileDao the publicProfileDao to set
	 */
	@Autowired
	public void setPublicProfileDao(PublicProfileDao publicProfileDao) {
		this.publicProfileDao = publicProfileDao;
	}
	/**
	 * @return the schedulingAssistantService
	 */
	public SchedulingAssistantService getSchedulingAssistantService() {
		return schedulingAssistantService;
	}
	/**
	 * @return the relationshipDao
	 */
	public RelationshipDao getRelationshipDao() {
		return relationshipDao;
	}
	/**
	 * @return the ownerDao
	 */
	public OwnerDao getOwnerDao() {
		return ownerDao;
	}
	/**
	 * @return the publicProfileDao
	 */
	public PublicProfileDao getPublicProfileDao() {
		return publicProfileDao;
	}
	/**
	 * 
	 * @param ownerId
	 * @param highContrast
	 * @return
	 * @throws NotAVisitorException
	 * @throws OwnerNotFoundException
	 */
	@RequestMapping(value="/schedule/{ownerIdentifier}/view.html", method=RequestMethod.GET)
	public ModelAndView displaySchedule(@PathVariable("ownerIdentifier") String ownerIdentifier, 
			@RequestParam(value="highContrast", required=false, defaultValue="false") boolean highContrast,
			@RequestParam(value="weekStart", required=false, defaultValue="0") int weekStart) throws NotAVisitorException, OwnerNotFoundException {
		CalendarAccountUserDetailsImpl currentUser = (CalendarAccountUserDetailsImpl) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		IScheduleVisitor visitor = currentUser.getScheduleVisitor();

		IScheduleOwner selectedOwner = locateOwnerFromIdentifier(ownerIdentifier, visitor);
		VisibleScheduleRequestConstraints requestConstraints = VisibleScheduleRequestConstraints.newInstance(selectedOwner, weekStart);
		if(log.isDebugEnabled()) {
			log.debug("displaySchedule request, currentUser: " + currentUser + "; weekStart: " + weekStart + "requestConstraints " + requestConstraints);
		}
		
		Map<String, Object> model = new HashMap<String, Object>();
		final String noteboard = selectedOwner.getPreference(Preferences.NOTEBOARD);
		String [] noteboardSentences = noteboard.split("\n");
		model.put("noteboardSentences", noteboardSentences);
		model.put("owner", selectedOwner);
		model.put("highContrast", highContrast);
		
		VisibleSchedule schedule;

		if(selectedOwner.hasMeetingLimit()) {
			// we have to look at the whole visible schedule for attendings
			schedule = schedulingAssistantService.getVisibleSchedule(
					visitor, selectedOwner);
			if(selectedOwner.isExceedingMeetingLimit(schedule.getAttendingCount())) {	
				// return attending only view
				List<AvailableBlock> attendingList = schedule.getAttendingList();
				model.put("attendingList", attendingList);
				return new ModelAndView("visitor/visitor-already-attending", model);
			} else {
				// extract start->end from visibleSchedule
				schedule = schedule.subset(requestConstraints.getTargetStartDate(), requestConstraints.getTargetEndDate());
			}
			
		} else {	
			// only pull start->end of schedule
			schedule = schedulingAssistantService.getVisibleSchedule(
					visitor, selectedOwner, requestConstraints.getTargetStartDate(), requestConstraints.getTargetEndDate());
		}
		
		model.put("visibleSchedule", schedule);
		model.put("scheduleStart", schedule.getScheduleStart());
		model.put("prevWeekStart", requestConstraints.getPrevWeekIndex());
		model.put("nextWeekStart", requestConstraints.getNextWeekIndex());
		model.put("weekStart", requestConstraints.getConstrainedWeekStart());
		model.put("ownerVisitorSamePerson", selectedOwner.isSamePerson(visitor));
		return new ModelAndView("visitor/visitor-visible-schedule", model);
	}

	/**
	 * 
	 * @param ownerIdentifier
	 * @param visitor
	 * @return
	 * @throws OwnerNotFoundException
	 */
	private IScheduleOwner locateOwnerFromIdentifier(final String ownerIdentifier, final IScheduleVisitor visitor) throws OwnerNotFoundException {
		IScheduleOwner selectedOwner = null;
		if(StringUtils.isNumeric(ownerIdentifier)) {
			Long ownerId = Long.parseLong(ownerIdentifier);
			selectedOwner = findOwnerForVisitor(visitor, ownerId);
		} else {
			PublicProfile profile = publicProfileDao.locatePublicProfileByKey(ownerIdentifier);
			if(null != profile) {
				selectedOwner = ownerDao.locateOwnerByAvailableId(profile.getOwnerId());
			}
		}

		if(null == selectedOwner) {
			throw new OwnerNotFoundException("no owner found for " + ownerIdentifier);
		}

		return selectedOwner;
	}
	/**
	 * 
	 * @param visitor
	 * @param ownerId
	 * @return
	 * @throws OwnerNotFoundException
	 */
	private IScheduleOwner findOwnerForVisitor(IScheduleVisitor visitor, long ownerId) throws OwnerNotFoundException {
		List<Relationship> relationships = relationshipDao.forVisitor(visitor);
		for(Relationship potential : relationships) {
			if(potential.getOwner().getId() == ownerId) {
				return potential.getOwner();
			}
		}

		throw new OwnerNotFoundException("owner id " + ownerId + " not found");
	}
	
	
}
