/**
 * 
 */
package com.heavylead.presenters;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;

import junit.framework.TestCase;

import org.jmock.Expectations;
import org.jmock.Mockery;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.heavylead.injection.HeavyLeadTestModule;
import com.heavylead.models.interfaces.IGameSettingsModel;
import com.heavylead.views.interfaces.IEditSettingsView;
import com.heavylead.views.interfaces.IEditSettingsViewListener;
import com.heavylead.views.interfaces.INavigator;

/**
 * @author msimpson
 *
 */
public final class TestEditSettingsPresenter extends TestCase {
    private static final int TEST_WIDTH = 10;
    private static final int TEST_HEIGHT = 10;
    private static final int TEST_DEPTH = 16;
    private static final int TEST_FREQUENCY = 60;
    private static final boolean TEST_IS_FULLSCREEN = false;
    private static final String TEST_DISPLAYLANGUAGE = "en";

    /** The _test injector. */
    private Injector _testInjector;
    
    /** The _mockery. */
    private Mockery _mockery;

    /** The _mock view. */
    private IEditSettingsView _mockView;

    private IGameSettingsModel _gameSettingsModel;
    
    /** The _mock view loader. */
    private INavigator _mockNavigator;

    /** The _main menu presenter. */
    private EditSettingsPresenter _presenter;

    
    /**
     * Instantiates a new test edit settings presenter.
     */
    public TestEditSettingsPresenter() {        
    }
    
    /**
     * @see junit.framework.TestCase#setUp()
     */
    @Override
    public void setUp() {
        _testInjector = Guice.createInjector(new HeavyLeadTestModule());
        _mockery = _testInjector.getInstance(Mockery.class);
        
        _mockView = _testInjector.getInstance(IEditSettingsView.class);
        _gameSettingsModel = _testInjector.getInstance(IGameSettingsModel.class);
        _mockNavigator = _testInjector.getInstance(INavigator.class);
        
        final List<String> resolutions = new ArrayList<String>();
        final List<String> depthOptions = new ArrayList<String>();
        final List<String> frequencyOptions = new ArrayList<String>();
        final Dictionary<String, String> languageOptions = new Hashtable<String, String>();
        final String resolution = "";
        final String depth = "";
        final String frequency = "";
        final String displayLanguage = "";
        _mockery.checking(new Expectations() {
            {
                oneOf(_mockView).setViewListener(
                        with(any(IEditSettingsViewListener.class)));
                oneOf(_gameSettingsModel).getResolutionOptions();
                will(returnValue(resolutions));
                oneOf(_mockView).setResolutionOptions(resolutions);
                oneOf(_gameSettingsModel).getDepthOptions();
                will(returnValue(depthOptions));
                oneOf(_mockView).setDepthOptions(depthOptions);
                oneOf(_gameSettingsModel).getFrequencyOptions();
                will(returnValue(frequencyOptions));
                oneOf(_mockView).setFrequencyOptions(frequencyOptions);
                oneOf(_gameSettingsModel).getLanguageOptions();
                will(returnValue(languageOptions));
                oneOf(_mockView).setLanguageOptions(languageOptions);
                oneOf(_gameSettingsModel).getResolution();
                will(returnValue(resolution));
                oneOf(_mockView).setResolution(resolution);
                oneOf(_gameSettingsModel).getDepth();
                will(returnValue(depth));
                oneOf(_mockView).setDepth(depth);
                oneOf(_gameSettingsModel).getFrequency();
                will(returnValue(frequency));
                oneOf(_mockView).setFrequency(frequency);
                oneOf(_gameSettingsModel).getIsFullScreen();
                will(returnValue(false));
                oneOf(_mockView).setIsFullScreen(false);
                oneOf(_gameSettingsModel).getDisplayLanguage();
                will(returnValue(displayLanguage));
                oneOf(_mockView).setDisplayLanguage(displayLanguage);
                oneOf(_mockView).enableApply(false);
                oneOf(_mockView).enableOk(false);
            }
        });

        _presenter = new EditSettingsPresenter(_mockView, _gameSettingsModel, _mockNavigator);
    }

    /**
     * @see junit.framework.TestCase#tearDown()
     */
    @Override
    public void tearDown() {
        _mockery.assertIsSatisfied();
    }

    /**
     * Test change resolution.
     */
    public void testSelectionChangedModelIsDirty() {
        readSettingsFromViewAndApplyToModel();
        
        _mockery.checking(new Expectations() {
            {
                oneOf(_gameSettingsModel).isDirty();
                will(returnValue(true));
                
                oneOf(_mockView).enableApply(true);
                oneOf(_mockView).enableOk(true);
            }
        });

        _presenter.selectionChanged();
    }

    /**
     * Test selection changed model not dirty.
     */
    public void testSelectionChangedModelNotDirty() {
        readSettingsFromViewAndApplyToModel();
        
        _mockery.checking(new Expectations() {
            {
                oneOf(_gameSettingsModel).isDirty();
                will(returnValue(false));
                
                oneOf(_mockView).enableApply(false);
                oneOf(_mockView).enableOk(false);
            }
        });

        _presenter.selectionChanged();        
    }
    
    /**
     * Expect new settings.
     */
    private void readSettingsFromViewAndApplyToModel() {        
        _mockery.checking(new Expectations() {
            {
                oneOf(_mockView).getResolutionWidth();
                will(returnValue(TEST_WIDTH));
                oneOf(_mockView).getResolutionHeight();
                will(returnValue(TEST_HEIGHT));
                oneOf(_mockView).getDepth();
                will(returnValue(TEST_DEPTH));
                oneOf(_mockView).getFrequency();
                will(returnValue(TEST_FREQUENCY));
                oneOf(_gameSettingsModel).setDisplayWidth(TEST_WIDTH);
                oneOf(_gameSettingsModel).setDisplayHeight(TEST_HEIGHT);
                oneOf(_gameSettingsModel).setDepth(TEST_DEPTH);
                oneOf(_gameSettingsModel).setFrequency(TEST_FREQUENCY);
                oneOf(_mockView).isFullScreen();
                will(returnValue(TEST_IS_FULLSCREEN));
                oneOf(_gameSettingsModel).setIsFullScreen(TEST_IS_FULLSCREEN);
                oneOf(_mockView).getDisplayLanguage();
                will(returnValue(TEST_DISPLAYLANGUAGE));
                oneOf(_gameSettingsModel).setDisplayLanguage(TEST_DISPLAYLANGUAGE);
            }
        });
    }
    
    /**
     * Test save settings.
     * 
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public void testSaveSettings() throws IOException {       
        _mockery.checking(new Expectations() {
            {
                oneOf(_gameSettingsModel).save();
                oneOf(_mockNavigator).reinitDisplay();
                oneOf(_mockNavigator).hideEditSettings();
                oneOf(_mockNavigator).displayMainMenu();
            }
        });

        _presenter.saveSettingsPressed();
    }
    
    /**
     * Test save settings with exception.
     * 
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public void testSaveSettingsWithException() throws IOException {
        _mockery.checking(new Expectations() {
            {
                oneOf(_gameSettingsModel).save();
                will(throwException(new IOException()));
                oneOf(_mockView).showErrorDialog("Error", "error saving settings");
                oneOf(_mockNavigator).reinitDisplay();
                oneOf(_mockNavigator).hideEditSettings();
                oneOf(_mockNavigator).displayMainMenu();
            }
        });

        _presenter.saveSettingsPressed();
    }
    
    /**
     * Test apply.
     * 
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public void testApply() throws IOException {
        _mockery.checking(new Expectations() {
            {
                oneOf(_gameSettingsModel).save();
                oneOf(_mockNavigator).reinitDisplay();
            }
        });
        
        _presenter.applyPressed();
    }
    
    /**
     * Test cancel.
     */
    public void testCancel() {
        _mockery.checking(new Expectations() {
            {
                oneOf(_mockNavigator).hideEditSettings();
                oneOf(_mockNavigator).displayMainMenu();
            }
        });

        _presenter.cancelPressed();
    }
    
}