/*
 * 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.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.springframework.samples.petclinic.web.OwnerController.OWNER_FIND_VIEW;
import static org.springframework.samples.petclinic.web.OwnerController.OWNER_LIST_VIEW;

import java.util.ArrayList;

import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import org.springframework.samples.petclinic.Clinic;
import org.springframework.samples.petclinic.Owner;
import org.springframework.samples.petclinic.OwnerTests;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.MapBindingResult;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.bind.support.SimpleSessionStatus;


/**
 * Unit tests for {@link OwnerController}.
 *
 * @author Chris Beams
 */
public class OwnerControllerTests {
    private Clinic clinic;
    private OwnerController ownerController;

    private Model model;
    private BindingResult result;
    private SessionStatus status;

    @Before
    public void setUp() {
        model = new ExtendedModelMap();
        result = new MapBindingResult(model.asMap(), "owner");
        status = new SimpleSessionStatus();

        clinic = EasyMock.createMock(Clinic.class);
        ownerController = new OwnerController(clinic);
    }

    @Test
    public void loadOwner() {
        Owner expected = new Owner();
        EasyMock.expect(clinic.loadOwner(1)).andReturn(expected);
        EasyMock.replay(clinic);

        Owner actual = ownerController.createOwner(1);

        assertThat(actual, is(expected));
    }

    @Test
    public void createOwner() {
        Owner owner = ownerController.createOwner(null);
        assertNotNull(owner);
    }

    @Test
    public void formWithoutErrors() {
        Owner owner = OwnerTests.createValidOwner();

        clinic.storeOwner(owner);
        EasyMock.replay(clinic);

        String viewName = ownerController.form(owner, result, status);

        assertThat(viewName, equalTo(ViewUtils.getRedirectForOwner(owner)));
        assertThat(status.isComplete(), equalTo(true));
        EasyMock.verify(clinic);
    }

    @Test
    public void formWithBindingErrors() {
        EasyMock.replay(clinic); // expect no calls

        Owner owner = OwnerTests.createValidOwner();

        // fake a binding error
        result.addError(new FieldError("owner", "firstName", "is required"));

        String viewName = ownerController.form(owner, result, status);

        assertThat(viewName, equalTo(OwnerController.OWNER_FORM_VIEW));
        assertThat(status.isComplete(), equalTo(false));
        EasyMock.verify(clinic);
    }

    @Test
    public void formWithValidationErrors() {
        EasyMock.replay(clinic); // expect no calls

        Owner owner = OwnerTests.createValidOwner();
        owner.setFirstName(""); // owner is now invalid

        String viewName = ownerController.form(owner, result, status);

        assertThat(viewName, equalTo(OwnerController.OWNER_FORM_VIEW));
        assertThat(status.isComplete(), equalTo(false));
        EasyMock.verify(clinic);
    }

    @Test
    public void submitFindWithUnknownLastName() {
        Owner owner = new Owner();
        owner.setLastName("Smith");

        // mock up responding to a search for 'Smith' with an empty result
        EasyMock.expect(clinic.findOwners(owner.getLastName())).andReturn(new ArrayList<Owner>());
        EasyMock.replay(clinic);

        String viewName = ownerController.find(owner, result, model);

        EasyMock.verify(clinic);
        assertThat(viewName, equalTo(OWNER_FIND_VIEW));
        assertThat(result.hasErrors(), is(true));
        assertThat(result.getFieldError("lastName"), notNullValue());
    }

    @Test
    public void submitFindWithLastNameMatchingMultipleOwners() {
        Owner owner = new Owner();
        owner.setLastName("Jones");

        // mock up responding to a search for 'Jones' with two results
        ArrayList<Owner> matches = new ArrayList<Owner>();
        matches.add(new Owner());
        matches.add(new Owner());
        EasyMock.expect(clinic.findOwners(owner.getLastName())).andReturn(matches);
        EasyMock.replay(clinic);

        String viewName = ownerController.find(owner, result, model);

        EasyMock.verify(clinic);
        assertThat(viewName, equalTo(OWNER_LIST_VIEW));
        assertThat(result.hasErrors(), is(false));
    }

    @Test
    public void submitFindWithLastNameMatchingSingleResult() {
        Owner owner = new Owner();
        owner.setLastName("Obscure");

        // mock up responding to a search for 'Obscure' with a single result
        ArrayList<Owner> matches = new ArrayList<Owner>();
        Owner match1 = new Owner();
        match1.setId(32);
        matches.add(match1);
        EasyMock.expect(clinic.findOwners(owner.getLastName())).andReturn(matches);
        EasyMock.replay(clinic);

        String viewName = ownerController.find(owner, result, model);

        EasyMock.verify(clinic);
        assertThat(viewName, equalTo(ViewUtils.getRedirectForOwner(match1)));
    }
}
