// Yura Mamyrin

package risk.ui.SwingGUI;

import risk.engine.*;
import risk.engine.core.*;

import java.io.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.border.*;
import javax.swing.colorchooser.*;
import javax.swing.filechooser.*;

import java.util.List;
import java.util.Arrays;
import java.awt.image.BufferedImage;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.awt.Rectangle;

/**
 * @author Yura Mamyrin
 */

public class MapEditorPanel extends JPanel implements MouseInputListener {

	private List countries; // every item in this list also has its position+1 stored as the "color" value of it
	private List continents;
	private BufferedImage pic;
	private BufferedImage map;
	private Country selected;
	private Rectangle box;

	public MapEditorPanel() {

        	addMouseMotionListener(this);
		addMouseListener(this);

		ToolTipManager.sharedInstance().setDismissDelay(10000);

	}

	public BufferedImage getImageMap() {

		return map;

	}


	public BufferedImage getImagePic() {

		return pic;

	}

	public void setImagePic(BufferedImage a) {

		Dimension size = new Dimension(a.getWidth(), a.getHeight());

		if (size.width!=PicturePanel.PP_X || size.height!=PicturePanel.PP_Y) {

			JOptionPane.showMessageDialog(this,"non standard image size!");
		}

		pic = a;

		setPreferredSize(size);
		setMinimumSize(size);
		setMaximumSize(size);

		box = new Rectangle(size);

	}

	public void setImageMap(BufferedImage a) {

		if (a.getWidth() != pic.getWidth() || a.getHeight() != pic.getHeight() ) {

			JOptionPane.showMessageDialog(this,"ImageMap does not match ImagePic size!");

		}

		map = a;

	}



	public void setMap(RiskGame myMap) {

		countries = Arrays.asList( myMap.getCountries() );
		continents = Arrays.asList( myMap.getContinents() );

	}

	public void saveMap(File file) throws Exception {

	    String n = System.getProperty("line.separator");

	    StringBuffer buffer = new StringBuffer();


	    buffer.append("; map made with the map maker");
	    buffer.append(n);

	    buffer.append(n);
	    buffer.append("[files]");
	    buffer.append(n);

	    buffer.append("pic ");
	    buffer.append("@TODO:");
	    buffer.append(n);
	    buffer.append("map ");
	    buffer.append("@TODO:");
	    buffer.append(n);
	    buffer.append("crd ");
	    buffer.append("@TODO:");
	    buffer.append(n);

	    buffer.append(n);
	    buffer.append("[continents]");
	    buffer.append(n);

            for (int i = 0; i < continents.size(); i++) {

                Continent c = (Continent)continents.get(i);

		buffer.append(c.getIdString());
		buffer.append(" ");
		buffer.append(c.getArmyValue());
		buffer.append(" #");
		buffer.append(  Integer.toHexString((  c.getColor() .getRGB() & 0xffffff) | 0x1000000).substring(1) );
		buffer.append(n);

	    }

	    buffer.append(n);
	    buffer.append("[countries]");
	    buffer.append(n);


            for (int i = 0; i < countries.size(); i++) {

                Country c = (Country)countries.get(i);

		buffer.append(String.valueOf(i+1));
		buffer.append(" ");
		buffer.append(c.getIdString());
		buffer.append(" ");
		buffer.append( String.valueOf( continents.indexOf(c.getContinent()) +1) );
		buffer.append(" ");
		buffer.append( c.getX() );
		buffer.append(" ");
		buffer.append( c.getY() );
		buffer.append(n);

	    }


	    buffer.append(n);
	    buffer.append("[borders]");
	    buffer.append(n);


            for (int i = 0; i < countries.size(); i++) {

                Country c = (Country)countries.get(i);

		buffer.append(String.valueOf(i+1));


                List ney = c.getNeighbours();
                for (int j = 0; j < ney.size(); j++) {

                    Country n1 = (Country)ney.get(j);

		    buffer.append(" ");
		    buffer.append(String.valueOf( n1.getColor() ) );
		}

		buffer.append(n);

	    }


	    Writer output = null;
	    try {

		output = new BufferedWriter( new FileWriter(file) );
		output.write( buffer.toString() );
	    }
	    finally {

		if (output != null) output.close();
	    }


	}


    public void paintComponent(Graphics g) {

	//Graphics2D h = (Graphics2D)g;
	//super.paintComponent(g);


	if (countries!=null) {

	    int r=10;

            g.drawImage(pic,0,0,this);

	    int width = pic.getWidth();

            for (int i = 0; i < countries.size(); i++) {

                Country n = (Country)countries.get(i);
                int x = n.getX();
                int y = n.getY();

		g.setColor( n.getContinent().getColor() );
		g.fillOval( x-r , y-r, (r*2), (r*2) );

                List ney = n.getNeighbours();
                for (int j = 0; j < ney.size(); j++) {

                    Country n1 = (Country)ney.get(j);
                    int x1 = n1.getX();
                    int y1 = n1.getY();


                    if (n1.getNeighbours().contains(n)) {
                        g.setColor(Color.BLUE);
		    }
                    else {
                        g.setColor(Color.GREEN);
		    }



			if ( Math.abs( x - x1 ) > ( width  / 2) ) {


				if ( x > (width / 2) ) { // ie "n" is on the right
					g.drawLine( x, y, x1+width, y1);
					g.drawLine( x-width, y, x1, y1);

				}
				else { // the attacker is on the left
					g.drawLine( x, y, x1-width, y1);
					g.drawLine( x+width, y, x1, y1);
				}

			}
			else {

                    		g.drawLine(x,y,x1,y1);

			}

		}





                if (selected == n) {
                    g.setColor(Color.RED);
		}
		else {
                    g.setColor(Color.BLUE);
		}
                g.drawRect(x-2,y-2,4,4);



                g.setColor(Color.BLACK);

		g.drawString(n.getIdString(), x,y);
		g.drawString(String.valueOf(i+1), x,y+10);

            }

	}

    }




    public boolean contains(int x, int y) {

	if (countries!=null) {

            Country mynode = null;
            for (int i = 0; i < countries.size(); i++) {

                Country n = (Country)countries.get(i);
                int x1 = n.getX();
                int y1 = n.getY();
                if (x1 >= x - 2 && y1 >= y -2 && x1 <= x + 2 && y1 <= y +2) {
                    mynode = n;
                    break;
                }
            }

	    if (mynode!=null) {

		String show="<html><b>"+mynode.getIdString()+" ("+mynode.getColor()+")</b><br>Location: (x="+mynode.getX()+",y="+mynode.getY()+")<br>" +

		"Continent: " + mynode.getContinent().getIdString() +" ("+ (continents.indexOf(mynode.getContinent()) +1) +")";

                List ney = mynode.getNeighbours();
                for (int j = 0; j < ney.size(); j++) {

                    Country n1 = (Country)ney.get(j);

		    show = show + "<br>Neighbour: " + n1.getIdString() +" ("+n1.getColor()+")";
		}

		show = show + "</html>";

 		setToolTipText(show);

	    }
	    else {

		setToolTipText(null);

	    }

	    return true; // this is needed so the mouse listoner can use it

	}
	else {

	    return false;

	}
    }




	// #############################################################
	// ###################### mouse ###########################
	// ##################################################




        public void mouseClicked(MouseEvent e) {
	if (countries!=null) {

            // search all countries, find a valid one
            int x = e.getX();
            int y = e.getY();


            Country mynode = null;
            for (int i = 0; i < countries.size(); i++) {

                Country n = (Country)countries.get(i);
                int x1 = n.getX();
                int y1 = n.getY();
                if (x1 >= x - 2 && y1 >= y -2 && x1 <= x + 2 && y1 <= y +2) {
                    mynode = n;
                    break;
                }
            }


/*
	  if ( e.getModifiers() == java.awt.event.InputEvent.BUTTON1_MASK ) {

            if (MODE == ADDRESS || MODE == START) {


	      if (mynode==null && myaddr==null) {

                // dialog box for address node
                Object[] r = mylist.getSelectedValues();
                if (r.length > 1 || r.length==0)
                    return;

 		// Messages 
		Object[] message = new Object[6];

		message[0] = "number:";
		message[1] = new JTextField("num");
		message[2] = "postcode:";
		message[3] = new JTextField("e1");
		message[4] = "road:";
		message[5] = (Road)r[0];

		// Options 
		String[] options = { 
			"OK",
			"Cancel"
		}; 
		int result = JOptionPane.showOptionDialog( 
			myframe,			// the parent that the dialog blocks 
			message,				// the dialog message array 
			"Add new Address",			// the title of the dialog window 
			JOptionPane.OK_CANCEL_OPTION,		// option type 
			JOptionPane.QUESTION_MESSAGE,		// message type 
			null,					// optional icon, use null to use the default icon 
			options,				// options string array, will be made into buttons 
			options[0]				// option that should be made into a default button 
			);

		if (result==0) {
                                
			Address a = new Address(((JTextField)message[1]).getText(),x,y,(Road)r[0],((JTextField)message[3]).getText());
                               
			if (MODE != START) {

				addresses.add(a);
			}
			else {

				start = a; startlocation.setText( start+"" );
			}

			// YURA:?
			addlist.setListData(addresses);

			addlist.revalidate();
			addlist.repaint();
               
		}

	      }

            }
	    else if (MODE == DEL) {

		if (mynode != null) {

		    removeNode(mynode);

		}
		else if (myaddr !=null && myaddr!=start) {

		    addresses.remove(myaddr);

		    addlist.clearSelection();

		    addlist.revalidate();
		    addlist.repaint();

		}

	    }
	    else if (mynode != null && mynode == selected) {
                selected = null;

            }
            else if (mynode != null && (MODE == PLACE || selected == null)) {

                selected = mynode;
            }
            else if (mynode == null && MODE == PLACE && myaddr==null) {

                // roads
                Object[] roads = mylist.getSelectedValues();
                if (roads.length == 0)
                    return;
                mynode = new Country(x,y,roads);  
                countries.add(mynode);

		if (selected!=null) {

		    boolean done=false;

		    for (int i = 0; i < mynode.getRoads().size(); i++) {

			Road roada = (Road)(mynode.getRoads().elementAt(i));

			for (int j = 0; j < selected.getRoads().size(); j++) {

			    Road roadb = (Road)(selected.getRoads().elementAt(j));

			    if (roada==roadb) { done=true; break; }
			}

         	    }

		    if (done) {

			selected.addNeighbour(mynode);
			mynode.addNeighbour(selected);

		    }

		}
		selected = mynode;

            }
            else if (mynode != null && MODE == JOIN && mynode != selected) {

		    boolean done=false;

		    for (int i = 0; i < mynode.getRoads().size(); i++) {

			Road roada = (Road)(mynode.getRoads().elementAt(i));

			for (int j = 0; j < selected.getRoads().size(); j++) {

			    Road roadb = (Road)(selected.getRoads().elementAt(j));

			    if (roada==roadb) { done=true; break; }
			}

         	    }

		    if (done) {

			if (!selected.getNeighbours().contains(mynode))
			    selected.addNeighbour(mynode);

			if (!mynode.getNeighbours().contains(selected))
			    mynode.addNeighbour(selected);

		    }

		    selected = mynode;

            }
            else if (mynode != null && MODE == UNJOIN && mynode != selected) {

                if (selected.getNeighbours().contains(mynode))
                    selected.getNeighbours().remove(mynode);

                if (mynode.getNeighbours().contains(selected))
                    mynode.getNeighbours().remove(selected);

                selected = mynode;
            }

	  }
	  else if (e.getModifiers() == java.awt.event.InputEvent.BUTTON3_MASK) {

		if (mynode!=null) {

		    JList r = new JList( roads );

		    Vector z = mynode.getRoads();

		    int[] zz = new int[ z.size() ];

		    for (int i = 0; i < z.size(); i++) {
			zz[i] = roads.indexOf(z.elementAt(i));
		    }

		    r.setSelectedIndices(zz);

 		    // Messages 
		    Object[] message = new Object[2];

		    message[0] = "roads:";
		    message[1] = new JScrollPane(r);

		    // Options 
		    String[] options = { 
			"OK",
			"Cancel"
		    }; 
		    int result = JOptionPane.showOptionDialog( 
			myframe,			// the parent that the dialog blocks 
			message,				// the dialog message array 
			"Edit Country",			// the title of the dialog window 
			JOptionPane.OK_CANCEL_OPTION,		// option type 
			JOptionPane.QUESTION_MESSAGE,		// message type 
			null,					// optional icon, use null to use the default icon 
			options,				// options string array, will be made into buttons 
			options[0]				// option that should be made into a default button 
			);

		    if (result==0 && r.getSelectedIndex() != -1) {

	    		mynode.setRoads( r.getSelectedValues() );

			// checks that there r no joins between countries that have no raod in comman
			for (int k = 0; k < mynode.getNeighbours().size(); k++) {

			    Country sel = (Country)(mynode.getNeighbours().elementAt(k));

			    boolean done=false;

			    for (int i = 0; i < mynode.getRoads().size(); i++) {

				Road roada = (Road)(mynode.getRoads().elementAt(i));

				for (int j = 0; j < sel.getRoads().size(); j++) {

				    Road roadb = (Road)(sel.getRoads().elementAt(j));

				    if (roada==roadb) { done=true; break; }
				}

	         	    }

			    if (!done) {

		                if (sel.getNeighbours().contains(mynode))
		                    sel.getNeighbours().remove(mynode);

		                if (mynode.getNeighbours().contains(sel))
		                    { mynode.getNeighbours().remove(sel); k--; }

			    }

			}

		    }

		}
		else if (myaddr!=null) {

		    JComboBox r = new JComboBox( roads );
		    r.setSelectedIndex( roads.indexOf(myaddr.getRoad()) );

 		    // Messages 
		    Object[] message = new Object[6];

		    message[0] = "number:";
		    message[1] = new JTextField( myaddr.getNumber() );
		    message[2] = "postcode:";
		    message[3] = new JTextField( myaddr.getCode() );
		    message[4] = "road:";
		    message[5] = r;

		    // Options 
		    String[] options = { 
			"OK",
			"Cancel"
		    }; 
		    int result = JOptionPane.showOptionDialog( 
			myframe,			// the parent that the dialog blocks 
			message,				// the dialog message array 
			"Edit Address" + ((myaddr==start)?(" (start)"):("")),			// the title of the dialog window 
			JOptionPane.OK_CANCEL_OPTION,		// option type 
			JOptionPane.QUESTION_MESSAGE,		// message type 
			null,					// optional icon, use null to use the default icon 
			options,				// options string array, will be made into buttons 
			options[0]				// option that should be made into a default button 
			);

		    if (result==0) {

			myaddr.setNumber(((JTextField)message[1]).getText());
			myaddr.setCode(((JTextField)message[3]).getText());
			myaddr.setRoad((Road)r.getSelectedItem());

			if (myaddr==start) { startlocation.setText( start+"" ); }

		    }

		}

	  }
*/

          repaint();
	}
	}

	private Country dragpoint=null;

        public void mousePressed(MouseEvent e) {
	if (countries!=null) {

            int x = e.getX();
            int y = e.getY();

            Country mynode = null;
            for (int i = 0; i < countries.size(); i++) {

                Country n = (Country)countries.get(i);
                int x1 = n.getX();
                int y1 = n.getY();
                if (x1 >= x - 2 && y1 >= y -2 && x1 <= x + 2 && y1 <= y +2) {
                    mynode = n;
                    break;
                }
            }




	    if (mynode!=null) {

		dragpoint=mynode;

	    }

	}
	}

        public void mouseReleased(MouseEvent e) {

		dragpoint=null;

	}

        public void mouseDragged(MouseEvent e) {

            int x = e.getX();
            int y = e.getY();

	    if (dragpoint!=null && box!=null && box.contains(x,y)) {

		dragpoint.setX(x);
		dragpoint.setY(y);

		repaint();
	    }

	}

        public void mouseEntered(MouseEvent e) {}
        public void mouseExited(MouseEvent e) {}
	public void mouseMoved(MouseEvent e) {}




}
