/*===========================================================================
 *
 * File:	MorrowMapOptions.JAVA
 * Author:	Dave Humphrey (uesp@m0use.net)
 * Created On:	Monday, August 27, 2001
 *
 * Holds the various options related to the map input/output.
 *
 *=========================================================================*/

	/* Import Packages */
import java.awt.*;
import java.io.*;
import java.net.*;
import MorrowMapLocTypes;
import MorrowMapRecord;



/*===========================================================================
 *
 * Begin Class MorrowMapOptions
 *
 *=========================================================================*/
public class MorrowMapOptions {

  /*---------- Begin Class Data Constants --------------------------*/
  //static final String MAP_PROV_URL  = "http://abode/~uesp/MorrowMap/mwprov1.gdb";
  //static final String MAP_MAIN_URL  = "http://abode/~uesp/MorrowMap/mwmain1.gdb";
  //static final String MAP_IMAGE_URL = "http://abode/webpub/images/bgimage.jpg";
  //static final String MAP_PROV_URL  = "http://www.m0use.net/~uesp/morrow/map/mwprov1.gdb";
  //static final String MAP_MAIN_URL  = "http://www.m0use.net/~uesp/morrow/map/mwmain1.gdb";
  //static final String MAP_IMAGE_URL = "http://www.m0use.net/~uesp/morrow/map/images/bgimage.jpg";
  static final String MAP_PROV_URL  = "mwprov1.gdb";
  static final String MAP_MAIN_URL  = "mwmain1.gdb";
  static final String MAP_IMAGE_URL = "bgimage.jpg";


  static final int MAX_MAP_WIDTH  = 300000;		/* Size of map in map coordinates */
  static final int MAX_MAP_HEIGHT = 350000;
  static final int MAX_MAP_X      = 175000;
  static final int MAX_MAP_Y      = 220000;
  static final int MIN_MAP_X      = -125000;
  static final int MIN_MAP_Y      = -130000;
  static final int MIN_MAP_WIDTH  = 100;		/* Minimum size for zoom levels */
  static final int MIN_MAP_HEIGHT = 120;

  static final float MAP_WH_RATIO = (float) 0.857;	/* Ratio of width/height */

  static final long TM_DISPLAY_PROVINCE = 1;		/* Display option values */
  static final long TM_DISPLAY_BORDER1  = 2;
  static final long TM_DISPLAY_BORDER2  = 4;
  static final long TM_DISPLAY_BORDER3  = 8;
  static final long TM_DISPLAY_RIVER    = 16;
  static final long TM_DISPLAY_ROAD1    = 32;
  static final long TM_DISPLAY_ROAD2    = 64;
  static final long TM_DISPLAY_ROAD3    = 128;
  static final long TM_DISPLAY_CITY1    = 256;
  static final long TM_DISPLAY_CITY2    = 512;
  static final long TM_DISPLAY_CITY3    = 1024;
  static final long TM_DISPLAY_RUIN1    = 2048;
  static final long TM_DISPLAY_RUIN2    = 4096;
  static final long TM_DISPLAY_RUIN3    = 8192;
  static final long TM_DISPLAY_MISC1    = 16384;
  static final long TM_DISPLAY_MISC2    = 32768;
  static final long TM_DISPLAY_MISC3    = 65536;
  static final long TM_DISPLAY_TRADE1   = 131072;
  static final long TM_DISPLAY_TRADE2   = 262144;
  static final long TM_DISPLAY_FREE1    = 524288;
  static final long TM_DISPLAY_FREE2    = 1048576;

  static final long TM_DISPLAY_BORDERS  = 14;		/* Display option groups */
  static final long TM_DISPLAY_ROADS    = 224;
  static final long TM_DISPLAY_CITIES   = 1792;
  static final long TM_DISPLAY_RUINS    = 14336;
  static final long TM_DISPLAY_MISC     = 114688;
  static final long TM_DISPLAY_TRADES   = 393216;
  static final long TM_DISPLAY_LARGE    = (TM_DISPLAY_PROVINCE | TM_DISPLAY_BORDER1);
  static final long TM_DISPLAY_MEDIUM   = (TM_DISPLAY_LARGE | TM_DISPLAY_BORDER2 | TM_DISPLAY_RIVER | TM_DISPLAY_ROAD1 | 
				TM_DISPLAY_CITY1 | TM_DISPLAY_RUIN1 | TM_DISPLAY_MISC1 | TM_DISPLAY_TRADE1 | 
				TM_DISPLAY_FREE1);
  static final long TM_DISPLAY_SMALL    = (TM_DISPLAY_MEDIUM | TM_DISPLAY_BORDER3 | TM_DISPLAY_ROAD2 | TM_DISPLAY_CITY2 | 
				TM_DISPLAY_RUIN2 | TM_DISPLAY_MISC2 | TM_DISPLAY_TRADE2 | TM_DISPLAY_FREE2);
  static final long TM_DISPLAY_ALL      = 0xffffffff;

  static final int TG_DISPLAY_ALWAYS = 0;		/* Display levels */
  static final int TG_DISPLAY_FULL   = 1;
  static final int TG_DISPLAY_LARGE  = 2;
  static final int TG_DISPLAY_MEDIUM = 3;
  static final int TG_DISPLAY_SMALL  = 4;
  static final int TG_DISPLAY_ALL    = 5;

  /*---------- End of Class Data Constants -------------------------*/

  
  /*---------- Begin Class Data Members --------------------------*/
  
  int           m_PixelWidth;		/* Size of the desired map image in pixels*/
  int		m_PixelHeight;

  int		m_DisplayLevel;		/* Sets the appropiate level for displaying objects */
  long		m_DisplayOptions;	/* Sets which items are displayed */

  Rectangle	m_MapBox;		/* Extents of the map in map coordinates */

  boolean       m_DoSearch;		/* Search options */
  String        m_SearchString;

  boolean	m_DrawText;
  boolean       m_ShowPosition;		/* Display the XY location */
  boolean	m_ShowAll;		/* Show all locations */

  int		m_ForceDisplayLevel;	/* Force display of this level and higher levels */
  
  Font		m_DefaultFont;		/* Font objects */
  Font		m_HeavyFont;
  Font		m_SmallFont;

  float		m_MapToPixelXA;		/* Map to pixel coordinate conversion factors */
  float		m_MapToPixelXB;
  float		m_MapToPixelYA;
  float		m_MapToPixelYB;

  /*---------- End of Class Data Members -------------------------*/


/*===========================================================================
 *
 * Constructor - public MorrowMapOptions ();
 *
 *=========================================================================*/
public MorrowMapOptions () {
  m_PixelWidth  = 428;
  m_PixelHeight = 500;

  m_DisplayLevel = 0;
  m_DisplayOptions = TM_DISPLAY_ALL;

  m_MapToPixelXA = (float) 1.0;
  m_MapToPixelXB = (float) 0.0;
  m_MapToPixelYA = (float) 1.0;
  m_MapToPixelYB = (float) 0.0;

  m_MapBox = new Rectangle(MIN_MAP_X, MIN_MAP_Y, MAX_MAP_WIDTH, MAX_MAP_HEIGHT);
  m_SearchString = new String("");
  m_DoSearch	 = false;
  m_DrawText	 = true;
  m_ShowPosition = false;
  m_ShowAll	 = false;
  m_ForceDisplayLevel = 0;

	/* Create the default font objects */
  m_HeavyFont   = new Font("SansSerif", Font.BOLD, 12);
  m_DefaultFont = new Font("SansSerif", Font.PLAIN, 11);
  m_SmallFont   = new Font("SansSerif", Font.PLAIN, 10);

  ComputeConversion();
 }
/*===========================================================================
 *		End of Constructor MorrowMapOptions()
 *=========================================================================*/


/*===========================================================================
 *
 * Method - public void ClearSearch ();
 *
 * Resets the search options.
 *
 *=========================================================================*/
public void ClearSearch () {
  m_DoSearch = false;
  m_SearchString = "";
 }
/*===========================================================================
 *		End of Method ClearSearch()
 *=========================================================================*/


/*===========================================================================
 *
 * Method - void ComputeConversion ();
 *
 * Computes the various conversion factors for coorinate transformations.
 *
 *=========================================================================*/
public void ComputeConversion () {

	/* Old conversions */
//  m_MapToPixelXA = (float)m_PixelWidth  / (float)m_MapBox.width;
//  m_MapToPixelXB = -(float)m_MapBox.x * (float)m_PixelWidth / (float)m_MapBox.width;
//  m_MapToPixelYA = (float)m_PixelHeight / (float)m_MapBox.height;
//  m_MapToPixelYB = -(float)m_MapBox.y * (float)m_PixelHeight / (float)m_MapBox.height;

  m_MapToPixelXA = (float)m_PixelWidth  / (float)m_MapBox.width;
  m_MapToPixelXB = -(float)m_MapBox.x * (float)m_PixelWidth / (float)m_MapBox.width;

  m_MapToPixelYA = -(float)m_PixelHeight / (float)m_MapBox.height;
  m_MapToPixelYB = (float)(m_MapBox.y + m_MapBox.height) * (float)m_PixelHeight / (float)m_MapBox.height;

  //System.out.println (" XA = " + m_MapToPixelXA);
  //System.out.println (" XB = " + m_MapToPixelXB);
  //System.out.println (" YA = " + m_MapToPixelYA);
  //System.out.println (" YB = " + m_MapToPixelYB);
 }
/*===========================================================================
 *		End of Method ComputeConversion()
 *=========================================================================*/


/*===========================================================================
 *
 * Method - String ConvertSearchString (String SearchString);
 *
 * Converts the input string to a valid search string which is returned.
 *
 *=========================================================================*/
public String ConvertSearchString (String SearchString) {
  String ParsedString = SearchString.trim().toLowerCase();
  String TempString;
  char   HexChar;
  int    CharIndex;
  int    StartIndex = 0;

  System.out.println("InitialString= '" + ParsedString + "'");

	/* Remove any %XX hex codes from the string */
  while ((CharIndex = ParsedString.indexOf('%', StartIndex)) != -1) {
    if (CharIndex+3 >= ParsedString.length()) break;
    TempString = ParsedString.substring(StartIndex, CharIndex);
    HexChar = (char) (HexCharToInt(ParsedString.charAt(CharIndex+1)) * 16 + HexCharToInt(ParsedString.charAt(CharIndex+2)));
    TempString += String.valueOf(HexChar);
    TempString += ParsedString.substring(CharIndex + 3);
    
    ParsedString = TempString;
    StartIndex = CharIndex + 1;
   }

  System.out.println("ParsedString = '" + ParsedString + "'");
  return (ParsedString);
 }
/*===========================================================================
 *		End of Method ConvertSearchString()
 *=========================================================================*/


/*===========================================================================
 *
 * Method - public int HexCharToInt (char HexChar);
 *
 * Returns an integer value based on the input hex character.  Returns 0
 * if the character is not valid.
 *
 *=========================================================================*/
public int HexCharToInt (char HexChar) {

  if (HexChar >= '0' && HexChar <= '9') 
    return ((int)HexChar - (int)'0'); 
  else if (HexChar >= 'A' && HexChar <= 'F') 
    return ((int)HexChar - (int)'A' + 10); 
  else if (HexChar >= 'a' && HexChar <= 'f') 
    return ((int)HexChar - (int)'a' + 10); 

  return (0); 
 }
/*===========================================================================
 *		End of Method HexCharToInt()
 *=========================================================================*/



/*===========================================================================
 *
 * Begin Conversion Methods
 *
 *=========================================================================*/
public int MapToPixelX (int MapX) {
  int Value = (int)(((float)MapX) * m_MapToPixelXA + m_MapToPixelXB);
  //System.out.println ("MapX = " + MapX + ",  Value = " + Value);
  return (Value);
 }

public int MapToPixelY (int MapY) {
  return (int)(((float)MapY) * m_MapToPixelYA + m_MapToPixelYB);
 }
/*===========================================================================
 *		End of Conversion Methods
 *=========================================================================*/


/*===========================================================================
 *
 * Method - int Pan (DX, DY);
 *
 * Attempts to pan the viewable map area by the given amounts.  Returns 0
 * on success or -1 on any error.  The DX/DY values are in amounts relative
 * to the map width/height.
 *	0.5 = Pan half map width/height
 *	1.0 = Pan exactly map width/height
 *	2.0 = Pan twice map width/height
 *
 *=========================================================================*/
public int Pan (float DX, float DY) {
  int NewX;
  int NewY;

	/* Compute the new position */
  NewX = m_MapBox.x + (int)(DX*(float)m_MapBox.width);
  NewY = m_MapBox.y - (int)(DY*(float)m_MapBox.height);

  	/* Ensure a valid new X position */
  if (NewX < MIN_MAP_X) 
    NewX = MIN_MAP_X;
  else if (NewX + m_MapBox.width/2 > MAX_MAP_X)
    NewX = MAX_MAP_X - m_MapBox.width/2;

	/* Ensure a valid new Y position */
  if (NewY < MIN_MAP_Y) 
    NewY = MIN_MAP_Y;
  else if (NewY + m_MapBox.height > MAX_MAP_Y)
    NewY = MAX_MAP_Y - m_MapBox.height;

	/* Has the position changed? */
  if (NewX == m_MapBox.x && NewY == m_MapBox.y) return (-1);

	/* Change the bounds location */
  m_MapBox.setLocation(NewX, NewY);
  ComputeConversion();

  System.out.println ("X = " + NewX + " ( " + m_MapBox.width + " ) ");
  System.out.println ("Y = " + NewY + " ( " + m_MapBox.height + " ) ");
  return (0);
 }
/*===========================================================================
 *		End of Method Pan()
 *=========================================================================*/


/*===========================================================================
 *
 * Method -  void SetDisplayLevel ();
 *
 * Updates the display level from the current map width.
 *
 *=========================================================================*/
public void SetDisplayLevel () {

  if (m_MapBox.width > MAX_MAP_WIDTH/2) {
    m_DisplayOptions = TM_DISPLAY_LARGE;
    m_DisplayLevel = TG_DISPLAY_FULL;
   }
  else if (m_MapBox.width > MAX_MAP_WIDTH/4) {
    m_DisplayOptions = TM_DISPLAY_MEDIUM;
    m_DisplayLevel = TG_DISPLAY_LARGE;
   }
  else if (m_MapBox.width > MAX_MAP_WIDTH/8) {
    m_DisplayOptions = TM_DISPLAY_SMALL;
    m_DisplayLevel = TG_DISPLAY_MEDIUM;
   }
  else if (m_MapBox.width > MAX_MAP_WIDTH/16) {
    m_DisplayOptions = TM_DISPLAY_ALL;
    m_DisplayLevel = TG_DISPLAY_SMALL;
   }
  else {
    m_DisplayOptions = TM_DISPLAY_ALL;
    m_DisplayLevel = TG_DISPLAY_ALL;
   }

 }
/*===========================================================================
 *		End of Method SetDisplayLevel()
 *=========================================================================*/


/*===========================================================================
 *
 * Method - public void SetDrawText (ValueString);
 *
 * Sets the draw text option depending on the given string input.
 *
 *=========================================================================*/
public void SetDrawText (String ValueString) {
  int Value;


	/* Check for special case of empty or NULL string */
  if (ValueString.equals(null) || ValueString.equals("")) return;

  Value = Integer.valueOf(ValueString).intValue();

  if (Value == 0)
    m_DrawText = false;  
  else
    m_DrawText = true;
     
 }
/*===========================================================================
 *		End of Function void SetDrawText()
 *=========================================================================*/


/*===========================================================================
 *
 * Method - public void SetShowPosition (ValueString);
 *
 * Sets the show position option depending on the given string input.
 *
 *=========================================================================*/
public void SetShowPosition (String ValueString) {
  int Value;


	/* Check for special case of empty or NULL string */
  if (ValueString.equals(null) || ValueString.equals("")) return;

  Value = Integer.valueOf(ValueString).intValue();

  if (Value == 0)
    m_ShowPosition = false;  
  else
    m_ShowPosition = true;
     
 }
/*===========================================================================
 *		End of Function void SetShowPosition()
 *=========================================================================*/


/*===========================================================================
 *
 * Method - public void SetShowAll (ValueString);
 *
 * Sets the show all option depending on the given string input.
 *
 *=========================================================================*/
public void SetShowAll (String ValueString) {
  int Value;

	/* Check for special case of empty or NULL string */
  if (ValueString.equals(null) || ValueString.equals("")) return;

  Value = Integer.valueOf(ValueString).intValue();

  if (Value == 0)
    m_ShowAll = false;  
  else
    m_ShowAll = true;

 }
/*===========================================================================
 *		End of Function void SetShowAll()
 *=========================================================================*/


/*===========================================================================
 *
 * Method - public void SetForceDisplayLevel (ValueString);
 *
 * Sets the display level option depending on the given string input.
 *
 *=========================================================================*/
public void SetForceDisplayLevel (String ValueString) {
  int Value;

	/* Check for special case of empty or NULL string */
  if (ValueString.equals(null) || ValueString.equals("")) return;

  Value = Integer.valueOf(ValueString).intValue();

  m_ForceDisplayLevel = Value;
 }
/*===========================================================================
 *		End of Function void SetForceDisplayLevel()
 *=========================================================================*/


/*===========================================================================
 *
 * Method - public void SetSearchString (Name);
 *
 * Sets the search string to the given value and updates the appropiate 
 * search options.  Clears the search options in the name string is empty.
 * Properly converts strings with %XX hexadecimal codes.
 *
 *=========================================================================*/
public void SetSearchString (String Name) {
  String TempString;

  try {	
	/* Check for special case of empty or NULL string */
    if (Name.equals(null) || Name.equals("")) {
      m_DoSearch = false;
      return;
     }

	/* Perform the required conversions */
    TempString = Name.trim();
    m_SearchString = ConvertSearchString(Name);
    m_DoSearch = !m_SearchString.equals("");
   }
	/* Catch an NULL string */
  catch (NullPointerException except) {
    m_DoSearch = false;
    m_SearchString = "";
   }
 }
/*===========================================================================
 *		End of Function void SetSearchString()
 *=========================================================================*/


/*===========================================================================
 *
 * Method - int Zoom (Amount);
 *
 * Attempts to zoom into/out of the current view point of the map.  Amount
 * is a number representing the amount of zoom.  
 *	0.5 = Zoom in to half size
 *	1.0 = No change
 *	2.0 = Zoom out to double size
 * Returns 0 on success or -1 on any error.
 *
 *=========================================================================*/
public int Zoom (float Amount) {
  int NewWidth;
  int NewHeight;
  int NewX;
  int NewY;
  
	/* Ensure valid input */
  if (Amount <= 0 || Amount > 10) return (-1);

	/* Compute the new zoom area width */
  NewWidth  = (int) ((float)m_MapBox.width * Amount);
  
	/* Ensure a valid width */
  if (NewWidth < MIN_MAP_WIDTH) 
    NewWidth = MIN_MAP_WIDTH;
  else if (NewWidth > MAX_MAP_WIDTH) 
    NewWidth = MAX_MAP_WIDTH;

	/* Compute the height to match the map ratio */
  NewHeight = (int) ((float)NewWidth / MAP_WH_RATIO);

	/* Has the width/height changed? */
  if (NewWidth == m_MapBox.width && NewHeight == m_MapBox.height) return (-1);

	/* Adjust the x/y position to center zoom */
  NewX = m_MapBox.x + (m_MapBox.width - NewWidth)/2;
  NewY = m_MapBox.y + (m_MapBox.height - NewHeight)/2;

	/* Ensure a valid new X position */
  if (NewX < MIN_MAP_X) 
    NewX = MIN_MAP_X;
  else if (NewX + NewWidth > MAX_MAP_WIDTH)
    NewX = MAX_MAP_WIDTH - NewWidth;

	/* Ensure a valid new Y position */
  if (NewY < MIN_MAP_Y) 
    NewY = MIN_MAP_Y;
  else if (NewY + NewHeight > MAX_MAP_HEIGHT)
    NewY = MAX_MAP_HEIGHT - NewHeight;

	/* Change the map bounds */
  m_MapBox.setBounds(NewX, NewY, NewWidth, NewHeight);
  SetDisplayLevel();
  ComputeConversion();

  //System.out.println (" Width = " + NewWidth);
  //System.out.println ("Height = " + NewHeight);
  //System.out.println ("X = " + NewX);
  //System.out.println ("Y = " + NewY);
  
  return (0);
 }
/*===========================================================================
 *		End of Method Zoom()
 *=========================================================================*/


/*===========================================================================
 *
 * Method - int ZoomFullMap ();
 *
 * Resets the zoom level to show the entire map area.  Returns 0 on success
 * or -1 on error or if nothing changed.
 *
 *=========================================================================*/
public int ZoomFullMap () {
  int NewWidth;
  int NewHeight;
  int NewX;
  int NewY;

	/* Set the new map bounds */
  NewWidth  = MAX_MAP_WIDTH;
  NewHeight = MAX_MAP_HEIGHT;
  NewX = MIN_MAP_X;
  NewY = MIN_MAP_Y;

  	/* Has the width/height/location changed? */
  if (NewWidth == m_MapBox.width && NewHeight == m_MapBox.height &&
      NewX == m_MapBox.x && NewY == m_MapBox.y) return (-1);

	/* Change the map bounds */
  m_MapBox.setBounds(NewX, NewY, NewWidth, NewHeight);
  ComputeConversion();
  SetDisplayLevel();
  return (0);
 }
/*===========================================================================
 *		End of Method ZoomFullMap()
 *=========================================================================*/


 }
/*===========================================================================
 *		End of Class MorrowMapOptions
 *=========================================================================*/


/*===========================================================================
 *		End of File MorrowMapOptions.JAVA
 *=========================================================================*/