/**
 * Copyright (c) 2006 Red Hat, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * Component of: Red Hat Application Server
 * 
 * Initial Developers: Greg Lapouchnian
 *                     Patrick Smith
 *
 */

package olstore.controller;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import olstore.domain.logic.OlstoreFacade;
import olstore.dto.ItemValue;
import olstore.dto.PictureValue;
import olstore.dto.PropertyValue;

import org.springframework.validation.BindException;
import org.springframework.validation.ValidationUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;

/**
 *  Controls the creating of a new item.
 */
public class ItemController extends SimpleFormController {

    // This form's olstore instance injected by spring.
    private OlstoreFacade olstore;

    /**
     * Creates a new item controller with values set for the form's view as well as
     * the command class to use as the form's backing object.
     *
     */
    public ItemController() {
        setSessionForm(true);
        setValidateOnBinding(false);
        setCommandClass(ItemValue.class);
        setFormView("createItem");
        setSuccessView("createItem");
    }

    /**
     * Spring injection method to set this form's olstore instance.
     * @param olstore this form's olstore instance object.
     */
    public void setOlstore(OlstoreFacade olstore) {
        this.olstore = olstore;
    }

    /**
     * Returns this form's backing object.
     * 
     * @param request the HttpServletRequest
     * @return this form's backing object.
     */
    protected Object formBackingObject(HttpServletRequest request)
            throws Exception {
        String itemId = request.getParameter("itemId");
        if (itemId != null) {
            return olstore.getItemById(itemId);
        } else {
            ItemValue value = new ItemValue();
            value.setTypeId(olstore.getDefaultType());
            value.setProperties(olstore.getPropertiesForType(olstore.getDefaultType()));
            value.setPrice(new BigDecimal(0));
            return value;
        }
    }

    /**
     * The validation method used to validate the fields of the command object.
     * 
     * @param request the HttpServletRequest 
     * @param command this form's backing object.
     * @param errors the errors that occurred while validating this form.
     */
    protected void onBindAndValidate(HttpServletRequest request,
            Object command, BindException errors) throws Exception {

        if (!isFormChangeRequest(request)) {
            ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name",
                    "NAME_REQUIRED", "Item name is required.");
            ValidationUtils.rejectIfEmptyOrWhitespace(errors, "shortDesc",
                    "SHRT_REQUIRED", "Short description is required.");
            ValidationUtils.rejectIfEmptyOrWhitespace(errors, "longDesc",
                    "LONG_REQUIRED", "Long description is required.");
            ItemValue item = (ItemValue) command;
            Iterator i = item.getProperties().iterator();
            while (i.hasNext()) {
                PropertyValue prop = (PropertyValue) i.next();
                if (prop.getName() == null || prop.getName().length() == 0) {
                    errors.rejectValue("properties", "PROP_REQUIRED",
                            "Property name is required.");
                }
            }
        }
    }

    /**
     * Returns a basic map to use in this form's view to store basic information.
     * @param request the HttpServletRequest.
     * @return the model for this form's view.
     */
    protected Map referenceData(HttpServletRequest request) throws Exception {
        Map model = ControllerHelper.initModel(request, olstore);
        model.put("page_title", "Create/Edit an Item - Olstore");
        model.put("types", this.olstore.getTypes());
        return model;
    }

    /**
     * Handles when this form is submitted and returns a new model and view
     * to represent the form.
     * 
     * @param request the HttpServletRequest.
     * @param response the HttpServletResponse.
     * @param errors the errors that occured during validation.
     * @return a new model and view to represent this form.
     */
    protected ModelAndView onSubmit(HttpServletRequest request,
            HttpServletResponse response, Object command, BindException errors)
            throws Exception {

        ItemValue item = (ItemValue) command;
        
        // Checks to see if there are any items or images already in this item
        // if there aren't any, set an empty one to prevent problems on the view.
        try {
            if (item.getProperties() == null) {
                item.setProperties(new ArrayList());
            }
            if (item.getPictures() == null) {
                item.setPictures(new ArrayList());
            }

            this.olstore.saveItem(item);
        } catch (Exception ex) {
            return showForm(request, response, errors);
        }

        // supply the errors to the view inside the model map
        Map model = errors.getModel();
        // add the reference data once again so it will continue to be displayed
        model.putAll(referenceData(request));
        return new ModelAndView("createItem", model);
    }

    /**
     * If the incoming request is to change the form, this method is invoked.
     * 
     * @param request the HttpServletRequest.
     * @param response the HttpServletResponse.
     * @param command this form's backing object.
     */
    protected void onFormChange(HttpServletRequest request,
            HttpServletResponse response, Object command) throws Exception {
        ItemValue item = (ItemValue) command;
        if (request.getParameter("add-picture") != null) {
            try {
                item.getPictures().add(new PictureValue());
            } catch (NullPointerException e) {
                Vector v = new Vector();
                v.add(new PictureValue());
                item.setPictures(v);
            }
        } else {
            item.setProperties(olstore.getPropertiesForType(item.getTypeId()));
        }
    }

    /**
     * Checks to see if the request is to change the form or a regular submit request.
     * 
     * @param request the HttpServletRequest.
     * @return true if the request is to change the form, false otherwise.
     */
    protected boolean isFormChangeRequest(HttpServletRequest request) {
        return request.getParameter("save-item") == null;
    }

}