/*
	Rogue Trader.
	Copyright (c) 2007, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################
//
//
// Class Name:   GuiGalaxyMap
// Purpose:      A little widget that draws the galaxy map. also allows star
//               system information to be viewed as well as allowing the player
//               to travel to other star systems in the galaxy.
//
//
//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################

#include "GuiGalaxyMap.h"

//------------------------------------------------------------------------------
// Constant initialisation
//------------------------------------------------------------------------------

const float GuiGalaxyMap::BACKGROUND_R  = 0.0f;     // background color for map: r
const float GuiGalaxyMap::BACKGROUND_G  = 0.0f;     // background color for map: g
const float GuiGalaxyMap::BACKGROUND_B  = 0.0f;     // background color for map: b

const float GuiGalaxyMap::GRID_LINE_R   = 0.3f;     // map grid line color: r
const float GuiGalaxyMap::GRID_LINE_G   = 0.3f;     // map grid line color: g
const float GuiGalaxyMap::GRID_LINE_B   = 0.3f;     // map grid line color: b

const unsigned GuiGalaxyMap::STAR_RADIUS = 16;      // radius of stars in the display

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GuiGalaxyMap::GuiGalaxyMap()
Purpose:  Constructor for the galaxy map object.
Params:   game which gui will draw the map of. gui screen the widget belongs to.
          whether or not travel is allowed from this map widget.
Returns:  n/a

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

GuiGalaxyMap::GuiGalaxyMap( Game * game , GuiScreen * screen , bool travelEnabled )
{
    // Save the pointer to the game and gui screen:

    this->game      = game;
    this->guiScreen = screen;

    // Set the view as not being dragged intially:

    dragging = false;

    // Set whether travelling is allowed from this map:

    this->travelEnabled = travelEnabled;

    // Set the home button as not selected initially:

    homeButtonSelected = false;
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GuiGalaxyMap::centerView()
Purpose:  Centers the view over the system the player is currently in.
Params:   none
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GuiGalaxyMap::centerView()
{
    //--------------------------------------------------------------------------
    // Get the current system of the game:
    //--------------------------------------------------------------------------

    const StarSystem * system = game->getSystem();

    //--------------------------------------------------------------------------
    // Initialise map position over the current star system:
    //--------------------------------------------------------------------------

    this->mapX = system->getSectorX() * Galaxy::SECTOR_SIZE + system->getSectorOffsetX() - size_x / 2;
    this->mapY = system->getSectorY() * Galaxy::SECTOR_SIZE + system->getSectorOffsetY() - size_y / 2;
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GuiGalaxyMap::windowRedrawing()
Purpose:  Redraw event. Draws the galaxy map.
Params:   none
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GuiGalaxyMap::windowRedrawing()
{
    //--------------------------------------------------------------------------
    // First draw a black background for the map widget:
    //--------------------------------------------------------------------------

    // Set background color

    glColor4f
    (
        BACKGROUND_R,
        BACKGROUND_G,
        BACKGROUND_B,
        1
    );

    // Draw the background

    glBegin(GL_QUADS);

        glVertex2f
        (
            float( this->position_x				) ,
            float( this->position_y				)
        );

        glVertex2f
        (
            float( this->position_x + size_x	) ,
            float( this->position_y				)
        );

        glVertex2f
        (
            float( this->position_x + size_x	) ,
            float( this->position_y + size_y	)
        );

        glVertex2f
        (
            float( this->position_x				) ,
            float( this->position_y + size_y	)
        );

    glEnd();

    //--------------------------------------------------------------------------
    // Draw the grid lines:
    //--------------------------------------------------------------------------

    drawGridLines();

    //--------------------------------------------------------------------------
    // Draw the hyperspace range of the ship
    //--------------------------------------------------------------------------

    drawHyperspaceRange();

    //--------------------------------------------------------------------------
    // Draw all the stars in the view:
    //--------------------------------------------------------------------------

    drawStarSystems();

    //--------------------------------------------------------------------------
    // Draw the home button:
    //--------------------------------------------------------------------------

    drawHomeButton();
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GuiGalaxyMap::drawGridLines()
Purpose:  Draws all the grid lines in the map.
Params:   none
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GuiGalaxyMap::drawGridLines()
{
    //--------------------------------------------------------------------------
    // Set grid color and get the center of the widget:
    //--------------------------------------------------------------------------

    // Set grid color:

    glColor4f
    (
        GRID_LINE_R,
        GRID_LINE_G,
        GRID_LINE_B,
        1
    );

    //--------------------------------------------------------------------------
    // Start drawing lines:
    //--------------------------------------------------------------------------

    glBegin(GL_LINES);

    //--------------------------------------------------------------------------
    // Get how far the map view is between sectors:
    //--------------------------------------------------------------------------

    int sectorOffsetX = mapX % Galaxy::SECTOR_SIZE;
    int sectorOffsetY = mapY % Galaxy::SECTOR_SIZE;

    //--------------------------------------------------------------------------
    // Draw all the vertical lines in the map:
    //--------------------------------------------------------------------------

    for ( int x = 0 ; x < size_x + Galaxy::SECTOR_SIZE ; x += Galaxy::SECTOR_SIZE )
    {
        glVertex2f( float( x + position_x - sectorOffsetX	) , float( position_y			) );
        glVertex2f( float( x + position_x - sectorOffsetX	) , float( position_y + size_y	) );
    }

    //--------------------------------------------------------------------------
    // Draw all the horizontal lines in the map:
    //--------------------------------------------------------------------------

    for ( int y = 0 ; y < size_y + Galaxy::SECTOR_SIZE ; y += Galaxy::SECTOR_SIZE )
    {
        glVertex2f( float( position_x			) , float( y + position_y - sectorOffsetY	) );
        glVertex2f( float( position_x + size_x	) , float( y + position_y - sectorOffsetY	) );
    }

    //--------------------------------------------------------------------------
    // End drawing lines
    //--------------------------------------------------------------------------

    glEnd();
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GuiGalaxyMap::drawHomeButton()
Purpose:  Draws the home button in the map display.
Params:   none
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GuiGalaxyMap::drawHomeButton()
{
    //--------------------------------------------------------------------------
    // Setup the opengl state first
    //--------------------------------------------------------------------------

    // Enable texturing:

    glEnable(GL_TEXTURE_2D);

    // Disable blending:

    glDisable(GL_BLEND);

    // Set draw color as white:

    glColor4f(1,1,1,1);

    //--------------------------------------------------------------------------
    // First see if the mouse is over the home button:
    //--------------------------------------------------------------------------

    if ( homeButtonSelected == true )
    {
        // Bind the highlighted home button texture:

        GLTextureManager::getTexButtonHomeH()->bind();
    }
    else
    {
        // Bind the non highlighted home button texture:

        GLTextureManager::getTexButtonHome()->bind();
    }

    //--------------------------------------------------------------------------
    // Draw the home button:
    //--------------------------------------------------------------------------

    glBegin(GL_QUADS);

        glTexCoord2f(0,0);  glVertex2f( float( this->position_x + this->size_x - 32 ) , float( this->position_y			) );
        glTexCoord2f(1,0);  glVertex2f( float( this->position_x + this->size_x      ) , float( this->position_y			) );
        glTexCoord2f(1,1);  glVertex2f( float( this->position_x + this->size_x      ) , float( this->position_y + 32	) );
        glTexCoord2f(0,1);  glVertex2f( float( this->position_x + this->size_x - 32 ) , float( this->position_y + 32	) );

    glEnd();

}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GuiGalaxyMap::checkSelectedSystem()
Purpose:  checks to see what system the player has over the cursor and sets the
          currently selected system.
Params:   mouse position
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GuiGalaxyMap::checkSelectedSystem( int mouseX , int mouseY )
{
    //--------------------------------------------------------------------------
    // If the view is dragging or the home button is selected then set the
    // current system as the default null system meaning none is selected
    //--------------------------------------------------------------------------

    if ( dragging || homeButtonSelected )
    {
        selectedSystem = StarSystem(); return;
    }

    //--------------------------------------------------------------------------
    // If the mouse is out of the widget bounds the set the current system as
    // the default null system:
    //--------------------------------------------------------------------------

    if (
            mouseX < this->position_x
            ||
            mouseY < this->position_y
            ||
            mouseX >= this->position_x + this->size_x
            ||
            mouseY >= this->position_y + this->size_y
        )
    {
        // Mouse is out of widget bounds: set current system to the default null system:

        selectedSystem = StarSystem();

        // Quit the function:

        return;
    }
    
    //--------------------------------------------------------------------------
    // Get what sector of the galaxy the mouse is on:
    //--------------------------------------------------------------------------

    unsigned sectorX = ( mouseX - this->position_x + mapX ) / Galaxy::SECTOR_SIZE;
    unsigned sectorY = ( mouseY - this->position_y + mapY ) / Galaxy::SECTOR_SIZE;

    //--------------------------------------------------------------------------
    // Get how far the mouse position is in between sectors:
    //--------------------------------------------------------------------------

    unsigned sectorOffsetX = ( mouseX - this->position_x + mapX ) % Galaxy::SECTOR_SIZE;
    unsigned sectorOffsetY = ( mouseY - this->position_y + mapY ) % Galaxy::SECTOR_SIZE;

    //--------------------------------------------------------------------------
    // Get the star at the sector the mouse is on:
    //--------------------------------------------------------------------------

    StarSystem s = game->getGalaxy()->getSystem(sectorX,sectorY);

    //--------------------------------------------------------------------------
    // See if the mouse is close enough to the star being displayed on the map:
    //--------------------------------------------------------------------------

    if ( s.isNullSystem() )
    {
        //----------------------------------------------------------------------
        // Null system on this sector: don't bother with this check.
        //----------------------------------------------------------------------

        selectedSystem = s;
    }
    else
    {
        //----------------------------------------------------------------------
        // Star system on this sector: do a bounding box check to see if the
        // mouse is near the star being displayed on the screen:
        //----------------------------------------------------------------------

        if (
                int(sectorOffsetX) < int( s.getSectorOffsetX() ) - int( STAR_RADIUS )
                ||
                int(sectorOffsetX) > int( s.getSectorOffsetX() ) + int( STAR_RADIUS )
                ||
                int(sectorOffsetY) < int( s.getSectorOffsetY() ) - int( STAR_RADIUS )
                ||
                int(sectorOffsetY) > int( s.getSectorOffsetY() ) + int( STAR_RADIUS )
            )
        {
            //------------------------------------------------------------------
            // Cursor is not over a system: set current system as the null system:
            //------------------------------------------------------------------

            selectedSystem = StarSystem();
        }
        else
        {
            //------------------------------------------------------------------
            // Cursor is over the system: set the current system as the system
            // the mouse is over.
            //------------------------------------------------------------------

            // See if their was a system selected last: if not play the mouse over button sound

            if ( selectedSystem.isNullSystem() )
            {
                // No system selected before: play system over sound

                SoundSystem::playSound( SoundManager::getSndSystemOver() );
            }

            selectedSystem = s;

            //------------------------------------------------------------------
            // But.. If this system is the same as the current system the player is
            // in the make this the selected system. The reason for this is because
            // the player can trade in a spacestation and modify a systems markets,
            // but these changes will not be given to the galaxy until the player
            // leaves the system. So we want the most up-to-date information on the
            // system for this display really...
            //------------------------------------------------------------------

            if ( s == * game->getSystem() )
            {
                //--------------------------------------------------------------
                // This system is the system the player is currently in. use the
                // games copy of this system, which is the most up to date:
                //--------------------------------------------------------------

                selectedSystem = * game->getSystem();
            }
        }

    }   // end else of if the mouse cursor is on a sector with a null, non existant system
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GuiGalaxyMap::drawStarSystems()
Purpose:  Draws all the star systems in the map view.
Params:   none
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GuiGalaxyMap::drawStarSystems()
{
    //--------------------------------------------------------------------------
    // Get the galaxy from the game:
    //--------------------------------------------------------------------------

    const Galaxy * galaxy = game->getGalaxy();

    //--------------------------------------------------------------------------
    // Get the main game font from the font manager:
    //--------------------------------------------------------------------------

    GLFont * font = GLFontManager::getFont_main();

    //--------------------------------------------------------------------------
    // Get how far the map view is between sectors:
    //--------------------------------------------------------------------------

    int sectorOffsetX = mapX % Galaxy::SECTOR_SIZE;
    int sectorOffsetY = mapY % Galaxy::SECTOR_SIZE;

    //--------------------------------------------------------------------------
    // If a system is currently selected by the user then draw a circle around it:
    //--------------------------------------------------------------------------

    if ( selectedSystem.isNullSystem() == false )
    {
        // Get the current sector of the view in the galaxy:

        unsigned sectorX = ( mapX ) / Galaxy::SECTOR_SIZE;
        unsigned sectorY = ( mapY ) / Galaxy::SECTOR_SIZE;

        // Get the sector the selected system is on relative to this:

        unsigned relativeSectorX = selectedSystem.getSectorX() - sectorX;
        unsigned relativeSectorY = selectedSystem.getSectorY() - sectorY;

        // Now figure out what position in the view the star is at:

        float positionX;

        positionX  = float( relativeSectorX * Galaxy::SECTOR_SIZE	);
        positionX -= float( sectorOffsetX							);
        positionX += float( selectedSystem.getSectorOffsetX()		);
        positionX += float( this->position_x						);

        float positionY;

        positionY  = float( relativeSectorY * Galaxy::SECTOR_SIZE	);
        positionY -= float( sectorOffsetY							);
        positionY += float( selectedSystem.getSectorOffsetY()		);
        positionY += float( this->position_y						);

        //----------------------------------------------------------------------
        // Now draw a halo of two times the star size around it:
        //----------------------------------------------------------------------

        // Enable texturing:

        glEnable(GL_TEXTURE_2D);

        // Enable additive blending:

        glEnable(GL_BLEND); glBlendFunc(GL_ONE,GL_ONE);

        // Set the texture of the halo:

        GLTextureManager::getTexGradientCircle()->bind();

        // Set the color of the halo:

        glColor4f(0.3f,0.3f,0.3f,1.0f);

        // Draw the halo:

        glBegin(GL_QUADS);

            glTexCoord2f(0,0);  glVertex2f( positionX - STAR_RADIUS * 2 ,  positionY - STAR_RADIUS * 2 );
            glTexCoord2f(1,0);  glVertex2f( positionX + STAR_RADIUS * 2 ,  positionY - STAR_RADIUS * 2 );
            glTexCoord2f(1,1);  glVertex2f( positionX + STAR_RADIUS * 2 ,  positionY + STAR_RADIUS * 2 );
            glTexCoord2f(0,1);  glVertex2f( positionX - STAR_RADIUS * 2 ,  positionY + STAR_RADIUS * 2 );

        glEnd();

    }

    //--------------------------------------------------------------------------
    // Draw the stars in every sector:
    //--------------------------------------------------------------------------

    // Draw all the stars

    for ( int y = -Galaxy::SECTOR_SIZE; y < size_y + Galaxy::SECTOR_SIZE; y += Galaxy::SECTOR_SIZE )
    for ( int x = -Galaxy::SECTOR_SIZE; x < size_x + Galaxy::SECTOR_SIZE; x += Galaxy::SECTOR_SIZE )
    {
        // Get the current sector in the galaxy:

        unsigned sectorX = ( x + mapX ) / Galaxy::SECTOR_SIZE;
        unsigned sectorY = ( y + mapY ) / Galaxy::SECTOR_SIZE;

        // Get the star system at this sector:

        StarSystem s = galaxy->getSystem(sectorX,sectorY);

        //----------------------------------------------------------------------
        // If this is a non-null star system then draw it:
        //----------------------------------------------------------------------

        if ( s.isNullSystem() == false )
        {
            // Make sure texturing is enabled:

            glEnable(GL_TEXTURE_2D);

            // Enable alpha blending:

            glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

            // Bind the star texture:

            GLTextureManager::getTexStar()->bind();

            // Get the position of the star in the display:

            int positionX = x + this->position_x - sectorOffsetX + s.getSectorOffsetX();
            int positionY = y + this->position_y - sectorOffsetY + s.getSectorOffsetY();

            // Get the color of the star:

            float col[4]; s.getStarColor(col);

            // Set the draw color to the color of the star:

            glColor4f( col[0], col[1] , col[2], 1 );

            // Draw the star:

            glBegin( GL_QUADS );

                glTexCoord2f(0,0); glVertex2i( positionX - STAR_RADIUS , positionY - STAR_RADIUS );
                glTexCoord2f(1,0); glVertex2i( positionX + STAR_RADIUS , positionY - STAR_RADIUS );
                glTexCoord2f(1,1); glVertex2i( positionX + STAR_RADIUS , positionY + STAR_RADIUS );
                glTexCoord2f(0,1); glVertex2i( positionX - STAR_RADIUS , positionY + STAR_RADIUS );

            glEnd();

            // Disable texturing and alpha blending:

            glDisable(GL_TEXTURE_2D);
            glDisable(GL_BLEND);

            //------------------------------------------------------------------
            // Star name drawing
            //------------------------------------------------------------------

            // Get the stars name:

            const char * name = s.getName();

            // Get the lenght of this name:

            unsigned nameLenght = strlen(name);

            // Draw the stars name centered under the star itself:

            font->drawString
            (
                name									,
                float( positionX - nameLenght * 4	)	,
                float( positionY + STAR_RADIUS		)	,
                8.0f	,
                1.0f	,
                1.0f	,
                1.0f	
            );
        }

    } // end of draw every star in the map
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GuiGalaxyMap::drawHyperspaceRange()
Purpose:  Draws the range of the players hyperspace engines as a gradiented circle
Params:   none
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GuiGalaxyMap::drawHyperspaceRange()
{
    //--------------------------------------------------------------------------
    // Get the range of the players ship:
    //--------------------------------------------------------------------------

    const GameObjectHook * shipHook = game->getPlayer()->getShipHook();

    // Get the players ship from the hook and assume it to be a ship object:

    const GameObject_Ship * ship = (GameObject_Ship*)(shipHook->getObject());

    // If the ship no longer exists then abort:

    if ( ship == 0 ) return;

    // Otherwise get the hyperspace range of the players ship:

    float range = ship->getHyperspaceRange() * Galaxy::SECTOR_SIZE;

    // Expand the range slightly for apperance reasons:

    range *= 1.35f;

    //--------------------------------------------------------------------------
    // OpenGL setup
    //--------------------------------------------------------------------------

    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);

    // Set blend function to additve:

    glBlendFunc(GL_ONE,GL_ONE);

    // Bind the gradient circle texture:

    GLTextureManager::getTexGradientCircle()->bind();

    //-------------------------------------------------------------------------
    // Get the players current system from the game:
    //--------------------------------------------------------------------------

    const StarSystem * currentSystem = game->getSystem();

    // Get the position of the system in the galaxy

    unsigned systemX = currentSystem->getSectorX() * Galaxy::SECTOR_SIZE + currentSystem->getSectorOffsetX();
    unsigned systemY = currentSystem->getSectorY() * Galaxy::SECTOR_SIZE + currentSystem->getSectorOffsetY();

    // Figure out where to draw the circle from this posiiton and the maps position in the galaxy:

    float circleX = float(systemX) - float(mapX);
    float circleY = float(systemY) - float(mapY);

    //--------------------------------------------------------------------------
    // Draw the circle representing the ships hyperspace range:
    //--------------------------------------------------------------------------

    // Draw green circle if player can jump, red otherwise:

    if ( ship->hasFuel() && travelEnabled )
    {
        glColor3f(0.35f,0.5f,0.35f);
    }
    else
    {
        glColor3f(0.5f,0.35f,0.35f);
    }

    glBegin(GL_QUADS);

        glTexCoord2f(0,0);  glVertex2f( this->position_x + circleX - range , this->position_y + circleY - range );
        glTexCoord2f(1,0);  glVertex2f( this->position_x + circleX + range , this->position_y + circleY - range );
        glTexCoord2f(1,1);  glVertex2f( this->position_x + circleX + range , this->position_y + circleY + range );
        glTexCoord2f(0,1);  glVertex2f( this->position_x + circleX - range , this->position_y + circleY + range );

    glEnd();
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GuiGalaxyMap::getDistanceToSelectedSystem()
Purpose:  Gets the distance from the players current system to the selected
          system in light years.
Params:   none
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

double GuiGalaxyMap::getDistanceToSelectedSystem()
{
    // If no system is selected the return 0 as the distance:

    if ( selectedSystem.isNullSystem() ) return 0;

    // Get the players current system from the game:

    const StarSystem * currentSystem = game->getSystem();

    // Get the positions of the current system and selected system in the galaxy:

    unsigned currentX   = currentSystem->getSectorX() * Galaxy::SECTOR_SIZE + currentSystem->getSectorOffsetX();
    unsigned currentY   = currentSystem->getSectorY() * Galaxy::SECTOR_SIZE + currentSystem->getSectorOffsetY();
    unsigned selectedX  = selectedSystem.getSectorX() * Galaxy::SECTOR_SIZE + selectedSystem.getSectorOffsetX();
    unsigned selectedY  = selectedSystem.getSectorY() * Galaxy::SECTOR_SIZE + selectedSystem.getSectorOffsetY();

    // Get a vector between these two positions:

    int vectorX = currentX - selectedX;
    int vectorY = currentY - selectedY;

    // Now make up a double componement vector of this:

    double vector[2] =
    {
        vectorX,
        vectorY
    };

    // Get the lenght of this vector:

    double lenght;

    lenght  = vector[0] * vector[0];
    lenght += vector[1] * vector[1];
    lenght  = sqrt(lenght);

    // Return the distance or lenght of this vector: but divide by sector size. Take each sector
    // as being one square light year in size:

    return lenght / Galaxy::SECTOR_SIZE;
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GuiGalaxyMap::mouseMoved()
Purpose:  Mouse moved event for this widget. Moves the view if neccessary.
Params:   mouse position in parent container coordinates
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GuiGalaxyMap::mouseMoved( int x , int y )
{
    //--------------------------------------------------------------------------
    // If dragging the view then move the view by the distance of the mouse from 
    // the center of the widget: otherwise see if the mouse is over the home
    // button:
    //--------------------------------------------------------------------------
    
    // Get the area of the map widget in screen coords:
    
    int widgetCenterScreenX = 0;
    int widgetCenterScreenY = 0;
    
    {
		int widgetHalfSizeX = 0;
		int widgetHalfSizeY = 0;
		
		getMouseDragBoxScreenCoords(widgetCenterScreenX, widgetCenterScreenY, widgetHalfSizeX, widgetHalfSizeY);
    }
    
    // Get the mouse position in screen coords:
    
    int mouseScreenX = GLWindow::getMouseScreenX();
    int mouseScreenY = GLWindow::getMouseScreenY();
    
    // See if dragging

    if ( dragging )
    {
        // Move view by how far the mouse is from the center of the 

        mapX += mouseScreenX - widgetCenterScreenX;
        mapY += mouseScreenY - widgetCenterScreenY;

        // Recenter mouse in the view: move the mouse by the amount it is away from the center of the view:

        GLWindow::setMousePosition
        (
            widgetCenterScreenX,
            widgetCenterScreenY
        );

        // Set the home button as not selected when dragging the view:

        homeButtonSelected = false;
    }
    else
    {
        // Not dragging: see if the mouse is over the home button:

        if (
                x >= this->position_x + this->size_x - 32
                &&
                x < this->position_x + this->size_x
                &&
                y > this->position_y
                &&
                y <= this->position_y + 32
            )
        {
            // If home button was not previously selected then play the button over sound:

            if ( homeButtonSelected == false )
            {
                SoundSystem::playSound( SoundManager::getSndButtonOver() );
            }

            // Mouse is over the home button: set as selected

            homeButtonSelected = true;
        }
        else
        {
            // Mouse not over the home button: set as not selected

            homeButtonSelected = false;
        }
    }

    //--------------------------------------------------------------------------
    // See what system the cursor is over:
    //--------------------------------------------------------------------------

    checkSelectedSystem(x,y);
}

// MS Visual C++: No unreferenced params warnings
#pragma warning(disable: 4100)

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GuiGalaxyMap::mouseReleased()
Purpose:  Mouse released event for the widget. Stops moving the view if view is
          being moved.
Params:   mouse position in parent container coordinates, button released
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GuiGalaxyMap::mouseReleased( int x , int y , GLWindow::MouseButton button )
{
    //--------------------------------------------------------------------------
    // If the right mouse button was released and view is being dragged then
    // return the cursor to its visible state:
    //--------------------------------------------------------------------------

    if ( button == GLWindow::MOUSE_BUTTON_RIGHT && dragging )
    {
        // Make cursor visible again:

        GLWindow::setCursor(GLWindow::CURSOR_ARROW);

        // Set the dragging flag to false:

        dragging = false;

        // Undo the previous restriction on mouse movement when RMB was pressed on widget:

        GLWindow::unRestrictMouse();

		// Move the mouse back to where it was before the view dragging started:

		GLWindow::setMousePosition
		(
			mouseBeforeDragX,
			mouseBeforeDragY
		);
    }
}

// MS Visual C++: No unreferenced params warnings
#pragma warning(default: 4100)

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GuiGalaxyMap::getMouseDragBoxScreenCoords()
Purpose:  Computes the coordinates of the screen space rectangle to clip mouse 
		  movement to for the map
Params:   Where to save the center (in screen space) and half width/height 
		  (again, screen space) of the box to restrict mouse movement to.
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GuiGalaxyMap::getMouseDragBoxScreenCoords( int & centerX, int & centerY, int & halfSizeX, int & halfSizeY )
{
	// Get current window position:
	
	POINT windowScreenPos = {0, 0};
	ClientToScreen(GLWindow::getWindowHandle(), &windowScreenPos);
	
	// Figure out the position of this widget, taking into account parent transforms 
	
	int unscaledPositionX = this->position_x;
	int unscaledPositionY = this->position_y;
	
	for (GuiWidget * p = getParent(); p; p = p->getParent())
	{
		unscaledPositionX += p->getPositionX();
		unscaledPositionY += p->getPositionY();
	}
	
	// Figure out the position and size of this widget in screen coords
	
	float scalingFactor = Game::getGuiScaleFactor();
	
	int positionX = (int)((float) unscaledPositionX * scalingFactor);
	int positionY = (int)((float) unscaledPositionY * scalingFactor);
	
	int sizeX = (int)((float) this->size_x * scalingFactor);
	int sizeY = (int)((float) this->size_y * scalingFactor);
	
	// Now compute the center:
	
	centerX = windowScreenPos.x + positionX + (sizeX / 2);
	centerY = windowScreenPos.y + positionY + (sizeY / 2);
	
	halfSizeX = sizeX / 2;
	halfSizeY = sizeY / 2;
}

// MS Visual C++: No unreferenced params warnings
#pragma warning(disable: 4100)

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GuiGalaxyMap::mousePressed()
Purpose:  Mouse pressed event for the widget. Starts moving the view if the right
          mouse button was pressed.
Params:   mouse position in parent container coordinates, button pressed
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GuiGalaxyMap::mousePressed( int x , int y , GLWindow::MouseButton button )
{
    //--------------------------------------------------------------------------
    // If the right mouse button was pressed then move the mouse to the center
    // of the map view and make invisible: but only if the home button is not
    // selected.
    //--------------------------------------------------------------------------

    if ( button == GLWindow::MOUSE_BUTTON_RIGHT && homeButtonSelected == false )
    {
        // Make the mouse invisible:

        GLWindow::setCursor(GLWindow::CURSOR_NONE);

        // Set the dragging flag to true:

        dragging = true;

        // Save the mouse position before the drag started:

		mouseBeforeDragX = GLWindow::getMouseScreenX();
		mouseBeforeDragY = GLWindow::getMouseScreenY();
        
        // Restrict the mouse movement to a bounding box of half the widget width and height which is centered on widget center:
        
		{
			int centerX		= 0;
			int centerY		= 0;
			int halfSizeX	= 0;
			int halfSizeY	= 0;
						
			getMouseDragBoxScreenCoords(centerX, centerY, halfSizeX, halfSizeY);
			
			// Move the mouse to the center of this area:
			
			GLWindow::setMousePosition(centerX, centerY);
			
			// Restrict the mouse to an area centered about the center of the area but half the size:
			
			GLWindow::restrictMouse
			(
				centerX - halfSizeX / 2,
				centerY - halfSizeY / 2,
				halfSizeX,
				halfSizeY
			);
		}
    }

    //--------------------------------------------------------------------------
    // If the LMB was pressed and home button is selected then center the map
    // view on the players current system:
    //--------------------------------------------------------------------------

    if ( button == GLWindow::MOUSE_BUTTON_LEFT && homeButtonSelected == true )
    {
        // Center the view over the players system:

        centerView();

        // Play the button clicked sound:

        SoundSystem::playSound( SoundManager::getSndButtonClick() );
    }

    //--------------------------------------------------------------------------
    // If the left mouse button was pressed and user is not dragging the view
    // then check to see if a system is currently selected: only do if the home
    // button is not selected though and travel is enabled
    //--------------------------------------------------------------------------

    if ( button == GLWindow::MOUSE_BUTTON_LEFT && dragging == false && homeButtonSelected == false )
    {
        // See if the user has selected a non-null star system:

        if ( selectedSystem.isNullSystem() == false )
        {
            // Play the button clicked sound:

            SoundSystem::playSound( SoundManager::getSndButtonClick() );

            // Get a hook to the players ship first:

            const GameObjectHook * hookShip = game->getPlayer()->getShipHook();

            // Get the ship object from the hook

            const GameObject_Ship * ship = (GameObject_Ship*)(hookShip->getObject());

            // If the ship exists then allow travel:

            if ( ship != 0 )
            {
                // If travel is not enabled then issue an error message:

                if ( travelEnabled )
                {

                    // Get the hyperspace range of the ship:

                    double range = ship->getHyperspaceRange();

                    // Get the distance to the selected star system:

                    double distance = getDistanceToSelectedSystem();

                    // If the star system is within range and not the current system then allow travel:

                    if ( distance == 0 )
                    {
                        GuiScreen::showMessageDialog
                        (
                            "Unable to travel",
                            "You are already at this system."
                        );
                    }
                    else if ( distance <= range )
                    {
                        // See if the player's ship has fuel to travel first:

                        if ( ship->hasFuel() )
                        {
                            // Valid system selected: request game to travel to it:

                            game->travelToSystem( selectedSystem.getSectorX() , selectedSystem.getSectorY() );

                            // Exit this gui screen:

                            guiScreen->exit();
                        }
                        else
                        {
                            // Player cannot travel because ship needs to refuel: issue warning message:

                            GuiScreen::showMessageDialog
                            (
                                "Unable to travel",
                                "You must refuel by docking at a spacestation before travelling again."
                            );
                        }
                    }
                    else
                    {
                        GuiScreen::showMessageDialog
                        (
                            "Unable to travel",
                            "System is beyond the range of your hyperspace engines."
                        );
                    }
                }
                else
                {
                    // Player not allowed travel: issue error message:

                    GuiScreen::showMessageDialog
                    (
                        "Unable to travel",
                        "You cannot travel while docked at a spacestation."
                    );

                }   // end else of it travel is allowed from this map

            }   // end if players ship exists

        }   // end if system is selected to travel to

    }   // end if conditions are right to attempt to travel
}

// MS Visual C++: No unreferenced params warnings
#pragma warning(default: 4100)

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     GuiGalaxyMap::lostFocus()
Purpose:  Lost focus event for the widget.
Params:   none
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void GuiGalaxyMap::lostFocus()
{
    // Set the home button as not selected:

    homeButtonSelected = false;

    // Set the currently selected system to the null system:

    selectedSystem = StarSystem();
}

