import java.util.*;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import java.util.Vector;


public class BlockSpringConfiguration  {
   private LabPanel labPanel;
   protected float samplingt;
   protected LabMenuBar Menu;
   private float t=0;
   private int Selected=-1;
   private float time=0;
   private grafico grafico1; 
   protected JMenu menu3;
   protected JRadioButtonMenuItem rbMenuItem;
   protected Vector <PhysicsElement> phyElements; // Vector is a Container
   protected float gravity;
   
   public BlockSpringConfiguration (JPanel fondo,double timeWindowSize ){
      this.grafico1=new grafico("GRAFICO",fondo,timeWindowSize);
	  gravity=0;
      phyElements = new Vector <PhysicsElement>();
      //add(new GBlock(1f,new Vector2D(200,75),new Vector2D(),40f,40f));  //Para probar mas rapido y no
      //add(new GBlock(1f,new Vector2D(300,75),new Vector2D(),40f,40f));  // hacer a cada rato las configuraciones
      //add(new GBlock(1f,new Vector2D(400,75),new Vector2D(),40f,40f));
      //add(new GSpring(200f,10f));
      //add(new GRubberBand(150f,70f));
      menu3 = new JMenu("Select");
      menu3.setToolTipText("Select mass to be plotted.");
      menuSelect();   
   }
   
   public void setLabPanel(LabPanel lp){
      labPanel = lp;
   }
    
   /**
    * Crea y modifica el menu Select en el Menu
    */
   public void menuSelect(){
	   	  int j=1;
	      menu3.removeAll();  
	      int i;
	     for (i=0; i<this.phyElements.size(); i++){
	       if(this.phyElements.get(i) instanceof GBlock &&
	    		   !(this.phyElements.get(i) instanceof GFixer)	) {
	            rbMenuItem = new JRadioButtonMenuItem("Mass"+j);
	            ActionListener sel=new ActionListener(){
	            	public void actionPerformed(ActionEvent event){
	            		JMenuItem menuItem = (JMenuItem)(event.getSource());
	            		selected(menuItem.getText());
	            	}
	            };
	            rbMenuItem.addActionListener(sel);
	            if(i==Selected)rbMenuItem.setSelected(true);
	            j++;
	     	    menu3.add(rbMenuItem);
	     	} 
	      }   
   }
   
   /**
    * Determina la masa seleccionada en el menu Select
    * @param t Nombre de la Masa Seleccionada
    */
   public void selected(String t){
	   int x=Integer.parseInt(t.substring(4));
	   int i,j=1;
	   for (i=0; i<this.phyElements.size(); i++){
	       if(this.phyElements.get(i) instanceof GBlock &&
	    		   !(this.phyElements.get(i) instanceof GFixer)	   ) {
	    	if(j==x){
	        Selected=i;
	    	break;}
	    	else {Selected=-1;}
	    	j++;
	       }
	   }
	   for (i=0; i<this.phyElements.size(); i++){
	       if(this.phyElements.get(i) instanceof GBlock &&
	    		   !(this.phyElements.get(i) instanceof GFixer)	   ) {  
	    	   if(i==Selected)
	    	   ((GBlock)this.phyElements.get(i)).plot(true);
	    	   else
	    		   ((GBlock)this.phyElements.get(i)).plot(false);
	       }
	       }
	   labPanel.repaint();
   }
   
   public void computeNextState(float delta_t) {
      int i;
	   for (i=0; i<phyElements.size(); i++){
         phyElements.get(i).computeNextState(delta_t);    
      }
   }
   /**
    * Actualiza el tiempo para graficar
    * @param t tiempo de Sampling del Simulador
    */
   public void time(float t ){
	time =time+t;
	samplingt=t;
   }
   
   /**
    * Envia datos de posicion y tiempo de Masa seleccionada al grafico
    */
   public void updateState() {
	      for (int i=0; i<phyElements.size(); i++)
	         phyElements.get(i).updateState();
	      int i;
		  Vector2D datos;
	      Block selected;
			      if(t!=time && Selected>=0){
			    	  t=time;
			    	  selected=((Block)phyElements.get(Selected));
			    	   datos=selected.getPosition();
			      		grafico1.add(datos.getX(),datos.getY(),time,samplingt);
			      		}
	      
	      if (labPanel != null)
	         labPanel.repaint();
	   }
   
   /**
    * Metodo para agregar gravedad al sistema.
    * @param g Gravedad. (En la tierra 9,8[m/s*s])
    */
   public void gravity(float g){
   gravity=g;
   for (int i=0; i<phyElements.size(); i++)
   phyElements.get(i).gravity=g;
   labPanel.repaint();
   }
   public void add(PhysicsElement e) {
      e.gravity=gravity;
      phyElements.add(e);
      if (labPanel != null)
         labPanel.repaint();
   }
   public void remove(PhysicsElement e) {
	      phyElements.remove(e);
	      menuSelect();
	      if (labPanel != null)
	         labPanel.repaint();
   }
   /**
    * Reset: sirve para resetar la configuracion realizada sin tener que cerrar
    * y abrir de nuevo el programa.
    */
   public void reset(){
	   for (int i=phyElements.size()-1; i>=0; i--)
	       remove(phyElements.get(i));
	   menuSelect();
	   Selected=-1;
   }
   /**
    * Borrar el ultimo elemento fisico agregado a la configuracion. Esta accion es
    * permitida si el sistema esta pausado.
    */
   public void resetLast(){
	   if((phyElements.size()-1)==Selected);Selected=-1;
   remove(phyElements.get(phyElements.size()-1));
   menuSelect();
   }
   /**
    * Se modifico este metodo para agregar una flecha y una g cuando se simule
    * con gravedad, el resto se dejo igual.
    */
   public void paintComponent(Graphics2D g2d){
    if(gravity!=0){
    Font nombre=new Font ("SERIF",Font.BOLD,30);
    g2d.setFont(nombre);
    g2d.drawLine(20,20,20,70);//flecha
    g2d.drawLine(10,50,20,70);//flecha
    g2d.drawLine(30,50,20,70);//flecha
    g2d.drawString("g",30,35);
       }
       for (int i=0; i<phyElements.size(); i++)
         if (phyElements.get(i) instanceof Drawable)
            ((Drawable) phyElements.get(i)).draw(g2d);
   }
   public Draggable find(int x, int y) {
      for (int i=0; i<phyElements.size(); i++)
         if (phyElements.get(i) instanceof Draggable) {
            Draggable element =(Draggable) (phyElements.get(i));
            if (element.contains(x,y)) return element;
         }
      return null;
   }  
   public GBlock findBlock(double x, double y) {
      for (int i=0; i<phyElements.size(); i++){
         if (phyElements.get(i) instanceof GBlock) {
            GBlock block =(GBlock)(phyElements.get(i));
            if (block.contains(x,y)) return block;
         }
         if (phyElements.get(i) instanceof GFixer) {
            GFixer fixer =(GFixer)(phyElements.get(i));
            if (fixer.contains(x,y)) return (GBlock)fixer;
         }}
      return null;
   }
              
}
