/*
 * Copyright 2002-2008 the original author or authors.
 *
 * 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 org.springframework.samples.petclinic.web;

import static org.springframework.samples.petclinic.web.PageType.FORM;
import static org.springframework.samples.petclinic.web.ViewUtils.PET;
import static org.springframework.samples.petclinic.web.ViewUtils.PET_OBJ_NAME;
import static org.springframework.samples.petclinic.web.ViewUtils.buildViewName;
import static org.springframework.samples.petclinic.web.ViewUtils.getRedirectForOwner;

import java.util.Collection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.Clinic;
import org.springframework.samples.petclinic.Owner;
import org.springframework.samples.petclinic.Pet;
import org.springframework.samples.petclinic.PetType;
import org.springframework.samples.petclinic.validation.PetValidator;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
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.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;

/**
 * Controller that handles all {@link Pet}-related requests,
 * i.e.: all requests for /petclinic/main/pet/*
 *
 * @author Juergen Hoeller
 * @author Ken Krebs
 * @author Chris Beams
 */
@Controller
@SessionAttributes(PET_OBJ_NAME)
public class PetController {
    
    static final String PET_FORM_VIEW = buildViewName(PET, FORM);

    private final Clinic clinic;
    
    @Autowired
    public PetController(Clinic clinic) {
        this.clinic = clinic;
    }

    /**
     * Returns a collection of all existing {@link PetType}s to be used
     * as 'reference data' when rendering the option list for pet types.
     * <p/>
     * Note that this method is annotated with {@code @ModelAttribute}
     * which signifies that the returned object will be registered into
     * the ui model.  Default naming conventions are used in this case,
     * which means that the list of PetType objects will be named
     * {@literal petTypeList}.
     * <p/>
     * This method will be called as part of the handler lifecycle for
     * every request routed to this controller.
     * 
     * @return all known PetTypes
     * 
     * @see WEB-INF/jsp/pet/form.jsp
     */
    @ModelAttribute
    public Collection<PetType> populatePetTypes() {
        return this.clinic.getPetTypes();
    }

    /**
     * Custom handler for displaying the 'Add Pet' form,
     * i.e.: GET requests for /petclinic/main/pet/add.
     * <p/>
     * Note that this handler returns a string instead of a {@link ModelAndView},
     * signifying the logical view name that should be rendered.  The ui
     * {@link Model} is supplied as a parameter to the method and populated with
     * the new {@link Pet} object to be rendered.
     *
     * @param ownerId the id of the owner that the newly created pet will be added to
     * @param model the ui model to be populated with a new Pet object
     * @return the name of the view to be rendered
     * 
     * @see #update(Pet, BindingResult, SessionStatus)
     * @see WEB-INF/jsp/pet/form.jsp
     */
    @RequestMapping(method = RequestMethod.GET)
    public String add(@RequestParam int ownerId, Model model) {
        Owner owner = this.clinic.loadOwner(ownerId);
        Pet pet = new Pet();
        owner.addPet(pet);
        model.addAttribute(PET_OBJ_NAME, pet);
        return PET_FORM_VIEW;
    }
    
    /**
     * Custom handler for displaying the 'Edit Pet' form,
     * i.e.: GET requests for /petclinic/main/pet/edit.
     * <p/>
     * Note that this handler returns a string instead of a {@link ModelAndView},
     * signifying the logical view name that should be rendered.  The ui {@link Model}
     * is supplied as a parameter to the method and populated with the new Pet object
     * to be rendered.
     *
     * @param id the id of the Pet to be edited
     * @param model the ui model to be populated with the matching Pet object
     * @return the name of the view to be rendered
     * 
     * @see #update(Pet, BindingResult, SessionStatus)
     * @see WEB-INF/jsp/pet/form.jsp
     */
    @RequestMapping(method = RequestMethod.GET)
    public String edit(@RequestParam int id, Model model) {
        Pet pet = this.clinic.loadPet(id);
        model.addAttribute(PET_OBJ_NAME, pet);
        return PET_FORM_VIEW;
    }

    /**
     * Custom handler for processing the submission of the 'Add Pet' and
     * 'Edit Pet' forms, i.e.: POST requests for /petclinic/main/pet/add
     * or /petclinic/main/pet/edit.
     * <p/>
     * Note that this handler returns a string instead of a {@link ModelAndView},
     * signifying the logical view name that should be rendered.
     *
     * @param owner the newly-bound Pet object containing values from the form
     * @param result the result of the form-to-object binding process, including
     *        any errors
     * @param status allows the controller to signify that the session-scoped
     *        visit object should may be cleaned up
     *        
     * @return the name of the view to be rendered
     * 
     * @see #add(int, Model)
     * @see #edit(Model)
     * @see PetValidator
     * @see SessionStatus
     * @see BindingResult
     * @see ViewUtils#getRedirectForOwner(Owner)
     * @see WEB-INF/jsp/pet/form.jsp
     * @see WEB-INF/jsp/owner/show.jsp
     */
    @RequestMapping(method = RequestMethod.POST)
    public String update(@ModelAttribute Pet pet, BindingResult result, SessionStatus status) {
        new PetValidator().validate(pet, result);
        if (result.hasErrors()) {
            return PET_FORM_VIEW;
        }
        else {
            this.clinic.storePet(pet);
            status.setComplete();
            return getRedirectForOwner(pet.getOwner());
        }
    }
    
}
