package com.heavylead.presenters;

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.IHeavyLeadGame;
import com.heavylead.injection.HeavyLeadTestModule;
import com.heavylead.models.interfaces.IGameSettingsModel;
import com.heavylead.models.interfaces.ISelectCampaignModel;
import com.heavylead.models.interfaces.ITranslator;
import com.heavylead.views.interfaces.IEditSettingsView;
import com.heavylead.views.interfaces.IEditSettingsViewListener;
import com.heavylead.views.interfaces.IMainMenuView;
import com.heavylead.views.interfaces.IMainMenuViewListener;
import com.heavylead.views.interfaces.ISelectCampaignView;
import com.heavylead.views.interfaces.ISelectCampaignViewListener;
import com.heavylead.wrappers.interfaces.IGameStateManager;

/**
 * The Class TestGbuiViewLoader.
 */
public final class TestNavigator extends TestCase {
    private Injector _testInjector;
    
    /** The _mockery. */
    private Mockery _mockery;

    /** The _mock translator. */
    private ITranslator _mockTranslator;

    private IGameStateManager _gameStateManager;
    
    /** The _gbui view loader. */
    private Navigator _navigator;

    private IMainMenuView _mainMenuView;
    private ISelectCampaignView _selectCampaignView;
    
    private IGameSettingsModel _gameSettingsModel;
    
    private IEditSettingsView _editSettingsView;
    
    /**
     * Instantiates a new test gbui view loader.
     */
    public TestNavigator() {
    }

    /**
     * @see junit.framework.TestCase#setUp()
     */
    public void setUp() {
        _testInjector = Guice.createInjector(new HeavyLeadTestModule());

        _mockery = _testInjector.getInstance(Mockery.class);
        
        _mockTranslator = _testInjector.getInstance(ITranslator.class);

        _gameStateManager = _testInjector.getInstance(IGameStateManager.class);
        _mainMenuView = _testInjector.getInstance(IMainMenuView.class);
        _selectCampaignView = _testInjector.getInstance(ISelectCampaignView.class);
        _gameSettingsModel = _testInjector.getInstance(IGameSettingsModel.class);
        _editSettingsView = _testInjector.getInstance(IEditSettingsView.class);
        
        _navigator = new Navigator();
        _navigator.setInjector(_testInjector);
        _testInjector.injectMembers(_navigator);
    }

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

    /**
     * Test display main menu.
     */
    public void testDisplayMainMenu() {
        displayMainMenu();
    }

    /**
     * Display main menu.
     */
    private void displayMainMenu() {
        final int displayWidth = 10;
        final int displayHeight = 10;
        
        _mockery.checking(new Expectations() {
            {
                oneOf(_mainMenuView).setViewListener(
                        with(any(IMainMenuViewListener.class)));
                oneOf(_mainMenuView).bindKeys();
                oneOf(_mainMenuView).getTranslationTags();
                oneOf(_mockTranslator).getTranslatedPhrases(
                        new ArrayList<String>());
                will(returnValue(new Hashtable<String, String>()));
                oneOf(_mainMenuView).setTranslationPhrases(
                        new Hashtable<String, String>());
                oneOf(_mainMenuView).activate();
                oneOf(_gameStateManager).attachChild(_mainMenuView);
                
                oneOf(_gameSettingsModel).getDisplayWidth();
                will(returnValue(displayWidth));
                
                oneOf(_gameSettingsModel).getDisplayHeight();
                will(returnValue(displayHeight));
                
                oneOf(_mainMenuView).layout(displayWidth, displayHeight);
            }
        });
        
        _navigator.displayMainMenu();
    }

    /**
     * Test hide main menu.
     */
    public void testHideMainMenu() {
        displayAndHideMainMenu();
    }

    /**
     * Display and hide main menu.
     */
    private void displayAndHideMainMenu() {
        displayMainMenu();

        hideMainMenu();
    }

    /**
     * What happens if we call hideMainMenu twice?
     */
    public void testDoubleHideMainMenu() {
        displayAndHideMainMenu();

        hideMainMenu();
    }

    /**
     * Hide main menu.
     */
    private void hideMainMenu() {
        _mockery.checking(new Expectations() {
            {
                oneOf(_gameStateManager).hasChild(_mainMenuView);
                will(returnValue(true));
                oneOf(_mainMenuView).deactivate();
                oneOf(_mainMenuView).unbindKeys();
                oneOf(_gameStateManager).detachChild(_mainMenuView);
            }
        });

        _navigator.hideMainMenu();
    }

    /**
     * Test display select campaign.
     */
    public void testDisplaySelectCampaign() {
        displaySelectCampaign();
    }

    /**
     * Display select campaign.
     */
    private void displaySelectCampaign() {
        final List<String> campaignNames = new ArrayList<String>();
        
        final ISelectCampaignModel selectCampaignModel =
            _testInjector.getInstance(ISelectCampaignModel.class);
        
        final int displayWidth = 10;
        final int displayHeight = 10;
        
        _mockery.checking(new Expectations() {
            {
                oneOf(_selectCampaignView).setViewListener(
                        with(any(ISelectCampaignViewListener.class)));
                oneOf(_selectCampaignView).bindKeys();
                oneOf(_selectCampaignView).getTranslationTags();
                oneOf(_mockTranslator).getTranslatedPhrases(new ArrayList<String>());
                will(returnValue(new Hashtable<String, String>()));                
                oneOf(_selectCampaignView).setTranslationPhrases(
                        new Hashtable<String, String>());
                oneOf(_selectCampaignView).activate();
                oneOf(_gameStateManager).attachChild(_selectCampaignView);
                oneOf(_selectCampaignView).enableContinueCampaign(false);
                oneOf(_selectCampaignView).enableStartNewCampaign(false);
                oneOf(selectCampaignModel).getCampaignNames();
                will(returnValue(campaignNames));
                oneOf(_selectCampaignView).setCampaignNames(campaignNames);
                
                oneOf(_gameSettingsModel).getDisplayWidth();
                will(returnValue(displayWidth));
                
                oneOf(_gameSettingsModel).getDisplayHeight();
                will(returnValue(displayHeight));
                
                oneOf(_selectCampaignView).layout(displayWidth, displayHeight);
            }
        });        

        _navigator.displaySelectCampaign();
    }

    /**
     * Test hide select campaign.
     */
    public void testHideSelectCampaign() {
        displaySelectCampaign();

        _mockery.checking(new Expectations() {
            {
                oneOf(_gameStateManager).hasChild(_selectCampaignView);
                will(returnValue(true));
                oneOf(_selectCampaignView).deactivate();
                oneOf(_selectCampaignView).unbindKeys();
                oneOf(_gameStateManager).detachChild(_selectCampaignView);
            }
        });
        
        _navigator.hideSelectCampaign();
    }

    /**
     * Test show edit settings.
     */
    public void testDisplayEditSettings() {
        final int displayWidth = 10;
        final int displayHeight = 10;
        final List<String> translationTags = new ArrayList<String>();
        
        mockDefaultValues();
        
        _mockery.checking(new Expectations() {
            {
                oneOf(_editSettingsView).setViewListener(
                    with(any(IEditSettingsViewListener.class)));
                
                oneOf(_editSettingsView).bindKeys();
                oneOf(_gameSettingsModel).getDisplayWidth();
                will(returnValue(displayWidth));
                oneOf(_gameSettingsModel).getDisplayHeight();
                will(returnValue(displayHeight));
                oneOf(_editSettingsView).layout(displayWidth, displayHeight);
                oneOf(_editSettingsView).getTranslationTags();
                will(returnValue(translationTags));
                oneOf(_mockTranslator).getTranslatedPhrases(translationTags);
                oneOf(_editSettingsView).setTranslationPhrases(null);
                oneOf(_editSettingsView).activate();
                oneOf(_gameStateManager).attachChild(_editSettingsView);
            }
        });
        
        _navigator.displayEditSettings();
    }
    
    /**
     * Mock default values.
     */
    private void mockDefaultValues() {
        final List<String> resolutionOptions = 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 colorBits = "";
        final String frequency = "";
        final boolean isFullScreen = false;
        final String displayLanguage = "";

        _mockery.checking(new Expectations() {
            {
                oneOf(_gameSettingsModel).getResolutionOptions();
                will(returnValue(resolutionOptions));
                oneOf(_editSettingsView).setResolutionOptions(resolutionOptions);
                
                oneOf(_gameSettingsModel).getDepthOptions();
                will(returnValue(depthOptions));
                oneOf(_editSettingsView).setDepthOptions(depthOptions);
                
                oneOf(_gameSettingsModel).getFrequencyOptions();
                will(returnValue(frequencyOptions));
                oneOf(_editSettingsView).setFrequencyOptions(frequencyOptions);
                
                oneOf(_gameSettingsModel).getLanguageOptions();
                will(returnValue(languageOptions));
                oneOf(_editSettingsView).setLanguageOptions(languageOptions);
                
                oneOf(_gameSettingsModel).getResolution();
                will(returnValue(resolution));
                oneOf(_editSettingsView).setResolution(resolution);
                
                oneOf(_gameSettingsModel).getDepth();
                will(returnValue(colorBits));
                oneOf(_editSettingsView).setDepth(colorBits);
                
                oneOf(_gameSettingsModel).getFrequency();
                will(returnValue(frequency));
                oneOf(_editSettingsView).setFrequency(frequency);
                
                oneOf(_gameSettingsModel).getIsFullScreen();
                will(returnValue(isFullScreen));
                oneOf(_editSettingsView).setIsFullScreen(isFullScreen);
                
                oneOf(_gameSettingsModel).getDisplayLanguage();
                will(returnValue(displayLanguage));
                oneOf(_editSettingsView).setDisplayLanguage(displayLanguage);

                oneOf(_editSettingsView).enableApply(false);
                oneOf(_editSettingsView).enableOk(false);
            }
        }); 
    }
    
    /**
     * Test hide edit settings.
     */
    public void testHideEditSettings() {
        mockDefaultValues();

        _mockery.checking(new Expectations() {
            {
                oneOf(_editSettingsView).setViewListener(
                    with(any(IEditSettingsViewListener.class)));
                
                oneOf(_gameStateManager).hasChild(_editSettingsView);
                will(returnValue(true));
                oneOf(_editSettingsView).deactivate();
                oneOf(_editSettingsView).unbindKeys();
                oneOf(_gameStateManager).detachChild(_editSettingsView);
            }
        });
        
        _navigator.hideEditSettings();
    }
    
    /**
     * Test exit.
     */
    public void testExit() {
        final IHeavyLeadGame heavyLeadGame = _testInjector.getInstance(IHeavyLeadGame.class);
        _mockery.checking(new Expectations() {
            {
                oneOf(heavyLeadGame).stop();
            }
        });

        _navigator.exit();
    }

    /**
     * Test display select campaign scenario.
     */
    public void testDisplaySelectCampaignScenario() {
        _navigator.displaySelectCampaignScenario();
    }

    /**
     * Test display connect to server.
     */
    public void testDisplayConnectToServer() {
        _navigator.displayConnectToServer();
    }
    
    /**
     * Test reinit display.
     */
    public void testReinitDisplay() {
        final int displayWidth = 10;
        final int displayHeight = 10;
        final IMainMenuView mainMenuView = _testInjector.getInstance(IMainMenuView.class);
        final IGameSettingsModel gameSettings =
            _testInjector.getInstance(IGameSettingsModel.class);
        final ITranslator translator = _testInjector.getInstance(ITranslator.class);
        final List<String> translationTags = new ArrayList<String>();
        _mockery.checking(new Expectations() {
            {                
                oneOf(mainMenuView).setViewListener(
                        with(any(IMainMenuViewListener.class)));
                oneOf(mainMenuView).bindKeys();
                oneOf(gameSettings).getDisplayWidth();
                will(returnValue(displayWidth));
                oneOf(gameSettings).getDisplayHeight();
                will(returnValue(displayHeight));
                oneOf(mainMenuView).layout(displayWidth, displayHeight);
                oneOf(mainMenuView).getTranslationTags();
                will(returnValue(translationTags));
                oneOf(translator).getTranslatedPhrases(translationTags);
                oneOf(mainMenuView).setTranslationPhrases(null);
                oneOf(mainMenuView).activate();
                oneOf(_gameStateManager).attachChild(mainMenuView);
            }
        });
        
        _navigator.displayMainMenu();

        final IHeavyLeadGame heavyLeadGame = _testInjector.getInstance(IHeavyLeadGame.class);
        _mockery.checking(new Expectations() {
            {                
                oneOf(heavyLeadGame).reinitVideo();
                oneOf(gameSettings).getDisplayWidth();
                will(returnValue(displayWidth));
                oneOf(gameSettings).getDisplayHeight();
                will(returnValue(displayHeight));
                oneOf(mainMenuView).layout(displayWidth, displayHeight);
                oneOf(mainMenuView).getTranslationTags();
                will(returnValue(translationTags));
                oneOf(translator).getTranslatedPhrases(translationTags);
                oneOf(mainMenuView).setTranslationPhrases(null);
            }
        });
        _navigator.reinitDisplay();
    }
}