package uk.co.patrickhaston.mars;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import javax.swing.JButton;

public class MarsView extends MPanel 
{
  /**
  * Contents of this class
  */
  private MarsFrame theFrame;
  private int waypoint = 0;
  private int settlement = 0;
  
  private int orientation = 0;
  public static int NORTH = 0;
  public static int EAST = 1;
  public static int SOUTH = 2;
  public static int WEST = 3;
  
  protected int scale = 0;
  public static int LARGE_SCALE = 0;
  public static int MEDIUM_SCALE = 1;
  public static int SMALL_SCALE = 2;
  public static int TINY_SCALE = 3;
  
  private MarsViewImage ground;

  // the start x and y dimensions
  protected int sX;
  protected int sY;
  // the finish x and y dimensions
  protected int fX;
  protected int fY;
  // the centre positions
  protected int midX = 0;
  protected int midY = 0;
  
  protected int tileSize = 64;
  
  protected Point currentTile = null;

  int constructions[] = null;
  
  // add a way of closing this view
  private JButton closeButton = null;

  /**
  * Constructor - requires frame and the waypoint Id
  */
  public MarsView(MarsFrame frame, int waypointId)
  {
    super();
    try  
    {
      theFrame = frame;
      waypoint = waypointId;
      jbInit();
    }
    catch (Exception e) 
    {
      e.printStackTrace();
    }
  }

  /**
   * Initializes the state of this instance.
   */
  private void jbInit() throws Exception 
  {
    settlement = theFrame.mars.Settlements.getSettlementAt(waypoint);
    Toolkit toolkit = Toolkit.getDefaultToolkit();
    Image image = toolkit.getImage("C:\\Mars\\images\\10mGround.gif");
//  MediaTracker mediaTracker = new MediaTracker(this);
//    mediaTracker.addImage();
    ground = new MarsViewImage(image, theFrame, theFrame);
    
    // add a button to close the view
    closeButton = new JButton("close");
    closeButton.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent e)
      {
       closeButton_ActionPerformed(e);
      }
    });

    this.add(closeButton);
    addMouseListener();
  }

  private void addMouseListener()
  {
    // Add mouse listener for the map
    MouseListener mapMouseListener = new MouseAdapter() 
    {
      public void mouseClicked(MouseEvent e) 
      {
//        if (e.getClickCount() == 1) 
//        {
//          LatLong loc = theMap.viewToWorld(e.getPoint());
//          if (loc != null)
//          {
            //theFrame.mars.systemMessage("Mouse click at (" + loc.east + ", " + loc.north + ")");
            //theFrame.mapPanel.remove(theFrame.map);
            //remove(theFrame.map);
//            theFrame.showWaypoint(theFrame.selectedWayPoint);
            /*
            theFrame.settlementView = new MarsView(theFrame, theFrame.selectedWayPoint);
            theFrame.settlementView.setPreferredSize(new Dimension(400, 400));

            add(theFrame.settlementView);
            theFrame.currentView = theFrame.SETTLEMENT_VIEW;
            theFrame.settlementView.validate();
            //validate();
            theFrame.validate();
            theFrame.repaint();

            //JOptionPane.showMessageDialog(theFrame, new MarsView(theFrame, theFrame.selectedWayPoint), "View", JOptionPane.PLAIN_MESSAGE);
            */
//          }
//        }
      }
    };
    addMouseListener(mapMouseListener);
    
    // Add mouse motion listener for the view
    MouseMotionListener mouseMotion = new MouseMotionAdapter()
    {
      public void mouseMoved(MouseEvent e)
      {
        Point p = e.getPoint();
        currentTile = screenToTile(p);
//        theFrame.mars.systemMessage("CurrentTile=" + currentTile);
        theFrame.repaint();
      }
    };
    addMouseMotionListener(mouseMotion);
  }
  
  public void paintComponent(Graphics g)
  {
    recalcDimensions();
    //g.drawString("Waypoint " + theFrame.mars.Waypoints.getName(waypoint),0,15);
    //g.drawString("Settlement " + theFrame.mars.Settlements.getName(settlement),0,30);
    int w = (this.getWidth() / 2);// + midX*tileSize/2 + midY*tileSize/2;
    int h = (this.getHeight() / 2);// + midX*tileSize/4 - midY*tileSize/4;
    
    if (waypoint > 0)
    {
      constructions = theFrame.mars.Waypoints.getConstructions(waypoint);
    }

    //ground.paintAt(g,0,0);
    for( int x=sX; x<=fX; x++)
    {
      for (int y=fY; y>=sY; y--)
      {
        // draw the ground first
        //ground.paintAt(g, w + x*tileSize/2 + y*tileSize/2, h - y*tileSize/4 + x*tileSize/4, 0, this, MarsConstruction.IN_USE, 10);
        int b = theFrame.mars.Regions.getBiotope(theFrame.mars.Waypoints.getLocation(waypoint));
        if(b > 0)
        {
          theFrame.mars.Biotopes.paintAt(b, g, w + x*tileSize/2 + y*tileSize/2, h - y*tileSize/4 + x*tileSize/4, 0, MarsConstruction.IN_USE, this);
        }
      }
    }

    int localX, localY;
    for( int x=sX; x<=fX; x++)
    {
      for (int y=fY; y>=sY; y--)
      {
        if (constructions != null)
        {
          for (int i=0; i<constructions.length; i++)
          {
            if(theFrame.mars.Constructions.isAt(constructions[i], (x+midX)*10, (y+midY)*10))
            {
              // draw the construction at this location
              int t = theFrame.mars.Constructions.getConstructionType(constructions[i]);
              int o = theFrame.mars.Constructions.getOrientation(constructions[i]);
              int c = theFrame.mars.Constructions.getStatus(constructions[i]);
              theFrame.mars.ConstructionTypes.paintAt(t, g, w + x*tileSize/2 + y*tileSize/2, h - y*tileSize/4 + x*tileSize/4, o, c, this);
            }
          }
        }
      }
    }
    
  if( currentTile != null)
  {
    g.setColor(Color.black);
    int x = w + currentTile.x*tileSize/2 + currentTile.y*tileSize/2;
    int y = h - currentTile.y*tileSize/4 + currentTile.x*tileSize/4 + tileSize;
    g.drawLine(x, y - tileSize/4, x + tileSize/2, y - tileSize/2);
    g.drawLine(x + tileSize/2, y - tileSize/2, x + tileSize, y - tileSize/4);
    g.drawLine(x + tileSize, y - tileSize/4, x + tileSize/2, y);
    g.drawLine(x + tileSize/2, y, x, y - tileSize/4);
  }
    
  }
  
  public int getConstructionAt(Point p)
  {
    //constructions = theFrame.mars.Waypoints.getConstructions(waypoint);
    
    if (constructions != null)
    {
      for (int i=0; i<constructions.length; i++)
      {
        if(theFrame.mars.Constructions.isAt(constructions[i], p.x * 10, p.y * 10))
        {
          // return the construction at this location
          return (constructions[i]);
        }
      }
    }
    return 0;
  }
  
  public static String getOrientationName(int o)
  {
    String retval = "";
    switch (o)
    {
      case 0: // north
        retval = "North"; break;
      case 1: // north
        retval = "East"; break;
      case 2: // north
        retval = "South"; break;
      case 3: // north
        retval = "West"; break;
    }
    return retval;
  }
  
    void closeButton_ActionPerformed(ActionEvent e)
  {
      theFrame.hideWaypoint();
  }
  
  public void pan_North()
  {
    midX--;
    midY++;
  }

  public void pan_NorthEast()
  {
    midY++;
  }

  public void pan_South()
  {
    midX++;
    midY--;
  }
  
  public void pan_SouthWest()
  {
    midY--;
  }

  public void pan_East()
  {
    midY++;
    midX++;
  }
  
  public void pan_SouthEast()
  {
    midX++;
  }

  public void pan_West()
  {
    midY--;
    midX--;
  }
  
  public void pan_NorthWest()
  {
    midX--;
  }

  public void zoomIn()
  {
    scale--;
    if (scale < LARGE_SCALE) scale = LARGE_SCALE;
    recalcDimensions();
  }

  public void zoomOut()
  {
    scale++;
    if (scale > TINY_SCALE) scale = TINY_SCALE;
    recalcDimensions();
  }
  
  public void recalcDimensions()
  {
    switch (scale)
    {
      case 0: tileSize = 128; break;
      case 1: tileSize = 64; break;
      case 2: tileSize = 32; break;
      case 3: tileSize = 16; break;
    }
    // get the size of the screen in terms of tiles
    int w = this.getWidth() / (tileSize/2);
    int h = this.getHeight() / (tileSize/2);  // should this be divided by 4?
    // midX and midY mark the tile at the centre of the screen
    int cX = midX; //(fX + sX) / 2;
    int cY = midY; //(fY + sY) / 2;
    sX = - w;
    fX = w;
    sY = - h;
    fY = h;
  }
  
  public Point getTile(Point p)
  {
    // find the offset from the mid point
    int dx = p.x - (tileSize + getWidth() / 2);
    int dy = p.y - (tileSize*3/4 + getHeight() / 2);
    // find the distance
    Point tile = new Point();
    // dx = tx*tileSize/2 + ty*tileSize/2
    // dy = tx*tileSize/4 - ty*tileSize/4
    // 2*dx = tx*tileSize + ty*tileSize
    // 4*dy = tx*tileSize - ty*tileSize
    // dx*2/tileSize = tx + ty
    // dy*4/tileSize = tx - ty
    // tx = dy*4/tileSize + ty
    // dx*2/tileSize = ty + dy*4/tileSize + ty
    // 2 * ty = dx*2/tileSize - dy*4/tileSize
    // ty = dx/tileSize - dy*2/tileSize
    //tile.y = (int) Math.round((float) dx/tileSize - (float) dy*2/tileSize - 0.5);
    // tx = dy*4/tileSize + ty
    //tile.x = (int) Math.round(dy*4/tileSize + tile.y + 0.5);
    
    // use formula y = c + grad * x
    // dy = y + 0.5 * dx
    // dy - 0.5*dx = y
    tile.x = (int) Math.round( (dx + 2 * dy) / (tileSize));
    // dy = c - 0.5 * dx
    // 0 = c - 0.5 * x
    // c = dy + 0.5 * dx
    // x = 2c
    // x = 2 * (dy + 0.5 * dx)
    // x = 2y + dx
    tile.y = (int) Math.round( ( dx - 2 * dy ) / (tileSize));
    return tile;
  }
  
  public Point getCurrentTile()
  {
    return currentTile;
  }
  
  public Point getActualTile()
  {
    if(currentTile!=null)
    {
      Point p = new Point(currentTile);
      p.x += midX;
      p.y += midY;
      return p;
    }
    return null;
  }
  
  public Point screenToTile(Point s)
  {
    Point t = new Point();
    // establish the mid point of the view
    int h = getHeight() / 2;
    int w = getWidth() / 2;
    // find the screen position relative to the midpoint
    s.x -= w;
    s.y -= h;
    // find the point at which a line from s running North/South crosses the y axis
    int c1 = s.y - s.x / 2;
    // find the point at which a line from s running East/West crosses the y axis
    int c2 = s.y + s.x / 2;
    // offset c1 and c2 to take into account the size of the image tile
    c1 -= tileSize / 2;
    c2 -= tileSize;
    
    t.x = Math.round(c2 * 2 / tileSize);
    t.y = -Math.round(c1 * 2 / tileSize);
    t.x = c2*2/tileSize;
    t.y = - c1*2/tileSize;
    return t;
  }
  
  public int getSettlementId()
  {
    return settlement;
  }
}
