//==================================================================================================
// S i m u l a t i o n                                                                         Java
// V i s u a l C o m p o n e n t
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
// the GNU Library General Public License for more details (http://www.gnu.org).

/*DESCRIPTION*/
/* This module provides a class to represent visual components in a simulation. */

// Package //---------------------------------------------------------------------------------------
package bpp.simulation;

// Importation //-----------------------------------------------------------------------------------
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.JPanel;

// V i s u a l C o m p o n e n t  Class //----------------------------------------------------------
/*CLASS VisualComponent */
/* Represents the visual aspect of a simulation object. It provides an outside and/or an inside
   representation. The outside view belongs to the <CODE>java.awt.Component</CODE> class. The
   inside view is composed of layers where visual components can be placed. */
public class VisualComponent implements MouseListener {
 //---------------------------------------------------------------------------------------Attributes
 protected boolean atCentered;
 protected int     atHeight;
 protected int     atLayer;
 protected Point   atLocation;
 protected String  atName;
 protected String  atNativePointer;
 protected String  atProperties;
 protected int     atWidth;

 protected SimulatorFrame  atFrame;
 protected JPanel          atInside;
 protected Component       atOutside;
 protected VisualComponent atParent;
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD VisualComponent */ /* Builds a visual component inside a given simulator frame. */
 public VisualComponent(SimulatorFrame agFrame) {
  atCentered=true;
  atHeight=0;
  atLayer=0;
  atLocation=new Point(0,0);
  atName="Unknown Component";
  atNativePointer="nil";
  atProperties="";
  atWidth=0;

  atFrame=agFrame;
  atInside=null;
  atOutside=null;
  atParent=null;
 }
 //-----------------------------------------------------------------------------------------Location
 /*METHOD VisualComponent */ /* Returns the coordinates of the component on the layout. */
 public Point location() { return (atLocation); }
 //--------------------------------------------------------------------------------------------Layer
 /*METHOD VisualComponent */
 /* Returns the layer where the component is located on the layout. */
 public int layer() { return (atLayer); }
 //-----------------------------------------------------------------------------------------Centered
 /*METHOD VisualComponent */
 /* Indicates if the outside representation is centered on the coordinates of the component. */
 public boolean centered() { return (atCentered); }
 //---------------------------------------------------------------------------------------------Name
 /*METHOD VisualComponent */ /* Returns the name of the component. */
 public String name() { return (atName); }
 //------------------------------------------------------------------------------------NativePointer
 /*METHOD VisualComponent */
 /* Returns the C++ pointer of the simulation object represented by the visual component. */
 public String nativePointer() { return (atNativePointer); }
 //---------------------------------------------------------------------------------------Properties
 /*METHOD VisualComponent */ /* Returns the list of properties of the component. */
 public String properties() {
  return ("name = "+atName
          +"\nnative pointer = "+atNativePointer
          +"\nparent = "+(atParent==null ? "nil" : atParent.name())
          +"\nlayer = "+atLayer
          +"\ninside = "+(atInside==null ? "no" : "yes")
          +"\nposition = "+atLocation.x+";"+atLocation.y+(atCentered ? " (center)" : " (top left)")
          +(atProperties==null ? "" : "\n\n"+atProperties));
 }
 //--------------------------------------------------------------------------------------------Frame
 /*METHOD VisualComponent */ /* Returns the simulator frame that manages the visual component. */
 public SimulatorFrame frame() { return (atFrame); }
 //-------------------------------------------------------------------------------------------Inside
 /*METHOD VisualComponent */ /* Returns the inside representation of the component. */
 public Component inside() { return (atInside); }
 //------------------------------------------------------------------------------------------Outside
 /*METHOD VisualComponent */ /* Returns the outside representation of the component. */
 public Component outside() { return (atOutside); }
 //-------------------------------------------------------------------------------------------Parent
 /*METHOD VisualComponent */
 /* Returns the component where the actual component is located. */
 public VisualComponent parent() { return (atParent); }
 //--------------------------------------------------------------------------------------SetLocation
 /*METHOD VisualComponent */ /* Sets the coordinates of the component on the layout. */
 public void setLocation(int atPositionX,int atPositionY) {
  atLocation.x=atPositionX;
  atLocation.y=atPositionY;
  setOutsideLocation();
 }
 //-------------------------------------------------------------------------------SetOutsideLocation
 protected void setOutsideLocation() {
  Dimension lcSize;

  if (atOutside!=null) {
   if (atCentered) {
    lcSize=atOutside.getSize();
    atOutside.setLocation(atLocation.x-lcSize.width/2,atLocation.y-lcSize.height/2);
   }
   else atOutside.setLocation(atLocation.x,atLocation.y);
  }
 }
 //-----------------------------------------------------------------------------------------SetLayer
 /*METHOD VisualComponent */ /* Sets the layer where the component is located on the layout. */
 public void setLayer(int agLayer) {
  if (atParent!=null) atParent.changeLayer(this.outside(),atLayer,agLayer);
  atLayer=agLayer;
 }
 //--------------------------------------------------------------------------------------ChangeLayer
 protected void changeLayer(Component agComponent,int agOldLayer,int agNewLayer) {
  removeInside(agComponent,agOldLayer);
  addInside(agComponent,agNewLayer,true);
  agComponent.addMouseListener(this);
 }
 //--------------------------------------------------------------------------------------SetCentered
 /*METHOD VisualComponent */
 /* Sets whether the outside representation is centered on the coordinates of the component. */
 public void setCentered(boolean agCentered) {
  atCentered=agCentered;
  setOutsideLocation();
 }
 //------------------------------------------------------------------------------------------SetName
 /*METHOD VisualComponent */ /* Sets the name of the component. */
 public void setName(String agName) {
  atName=agName;
  if (atFrame.inspectedComponent()==this) atFrame.updateInspector();
 }
 //---------------------------------------------------------------------------------SetNativePointer
 /*METHOD VisualComponent */
 /* Sets the C++ pointer of the simulation object represented by the visual component. */
 public void setNativePointer(String agPointer) {
  atNativePointer=agPointer;
  if (atFrame.inspectedComponent()==this) atFrame.updateInspector();
 }
 //--------------------------------------------------------------------------------------AddProperty
 /*METHOD VisualComponent */ /* Adds a property to the list of the component. */
 public void addProperty(String agProperty) {
  if (atProperties=="") atProperties=agProperty;
  else atProperties+="\n"+agProperty;
  if (atFrame.inspectedComponent()==this) atFrame.updateInspector();
 }
 //------------------------------------------------------------------------------------SetProperties
 /*METHOD VisualComponent */ /* Sets the list of properties of the component. */
 public void setProperties(String agProperties) {
  atProperties=agProperties;
  if (atFrame.inspectedComponent()==this) atFrame.updateInspector();
 }
 //----------------------------------------------------------------------------------------AddInside
 /*METHOD VisualComponent */
 /* Adds a component to the inside representation of the component. The component will be located
    on the layer provided as argument. */
 public void addInside(Component agComponent,int agLayer) {
  addInside(agComponent,agLayer,true);
  agComponent.setVisible(true);
  agComponent.addMouseListener(this);
 }
 //----------------------------------------------------------------------------------------AddInside
 /*METHOD VisualComponent */
 /* Adds a visual component to the inside representation of the component. The component will be
    located on the layer provided by its own attribute. */
 public void addInside(VisualComponent agComponent) {
  addInside(agComponent.outside(),agComponent.layer(),false);
  agComponent.atParent=this;
 }
 //----------------------------------------------------------------------------------------AddInside
 protected void addInside(Component agComponent,int agLayer,boolean agDummy) {
  Component lcComponentS[];
  int       lcCounter;
  Container lcLayer;

  Point     lcLocation = agComponent.getLocation();
  Dimension lcSize     = agComponent.getSize();

  if (atInside==null) {
   atInside=new JPanel(null) {
    public void paint(Graphics agGraphic) {
     Dimension lcSize = atFrame.selectedComponent().inside().getSize();

     agGraphic.setColor(Color.white);
     agGraphic.fillRect(0,0,lcSize.width-1,lcSize.height-1);
     agGraphic.setColor(Color.black);
     agGraphic.drawRect(0,0,lcSize.width-1,lcSize.height-1);

     super.paint(agGraphic);
    }
   };

   atInside.addMouseListener(this);
  }

  while (atInside.getComponentCount()<=agLayer) {
   lcLayer=new Container();
   atInside.add(lcLayer,0);
  }

  lcLayer=(Container)atInside.getComponent(atInside.getComponentCount()-(agLayer+1));
  lcLayer.add(agComponent);

  atWidth=Math.max(lcLocation.x+lcSize.width,atWidth);
  atHeight=Math.max(lcLocation.y+lcSize.height,atHeight);

  atInside.setSize(atWidth,atHeight);
  lcCounter=0;
  lcComponentS=atInside.getComponents();

  while (lcCounter<lcComponentS.length) {
   ((Container)lcComponentS[lcCounter]).setSize(atWidth,atHeight);
   ++lcCounter;
  }
 }
 //-------------------------------------------------------------------------------------RemoveInside
 /*METHOD VisualComponent */
 /* Removes a component from the inside representation of the component. The layer where the
    component is located must be provided. */
 public void removeInside(Component agComponent,int agLayer) {
  removeInside(agComponent,agLayer,true);
  agComponent.removeMouseListener(this);
 }
 //-------------------------------------------------------------------------------------RemoveInside
 /*METHOD VisualComponent */
 /* Removes a visual component from the inside representation of the component. */
 public void removeInside(VisualComponent agComponent) {
  removeInside(agComponent.outside(),agComponent.layer(),false);
  agComponent.atParent=null;
 }
 //-------------------------------------------------------------------------------------RemoveInside
 protected void removeInside(Component agComponent,int agLayer,boolean agDummy) {
  Container lcLayer = (Container)atInside.getComponent(atInside.getComponentCount()-(agLayer+1));
  lcLayer.remove(agComponent);
 }
 //---------------------------------------------------------------------------------------SetOutside
 /*METHOD VisualComponent */
 /* Sets the outside representation of the component (<CODE>null</CODE> means there is no
    outside view). */
 public void setOutside(Component agComponent) {
  if (atOutside!=null) atOutside.removeMouseListener(this);
  atOutside=agComponent;

  if (atOutside!=null) {
   atOutside.addMouseListener(this);
   atOutside.setVisible(false);
  }

  if (!atCentered) atLocation=agComponent.getLocation();
  setOutsideLocation();
 }
 //---------------------------------------------------------------------------------------------Hide
 /*METHOD VisualComponent */ /* Makes the component invisible. */
 public void hide() { if (atOutside!=null) atOutside.setVisible(false); }
 //---------------------------------------------------------------------------------------------Show
 /*METHOD VisualComponent */ /* Makes the component visible. */
 public void show() { if (atOutside!=null) atOutside.setVisible(true); }
 //-------------------------------------------------------------------------------------MouseClicked
 /*METHOD VisualComponent */
 /* Is invoked when a mouse button has been clicked (pressed and released) on the component. */
 public void mouseClicked(MouseEvent agEvent) {
  if (agEvent.getClickCount()==1) atFrame.setInspectedComponent(this);
  else if (agEvent.getClickCount()==2) {
   if (atInside==null) atFrame.console().append("\n[!] No Inside For '"+atName+"'.\n");
   else {
    if (atFrame.selectedComponent()==this) {
     if (atParent==null) atFrame.console().append("\n[!] No Parent For '"+atName+"'.\n");
     else {
      atFrame.console().append("\n[>] Moving Up To '"+atParent.name()+"'...\n");
      atFrame.setSelectedComponent(atParent);
     }
    }
    else {
     atFrame.console().append("\n[>] Moving Down To '"+atName+"'...\n");
     atFrame.setSelectedComponent(this);
    }
   }
  }
 }
 //-------------------------------------------------------------------------------------MouseEntered
 /*METHOD VisualComponent */ /* Is invoked when the mouse enters the component. */
 public void mouseEntered(MouseEvent agEvent) {}
 //--------------------------------------------------------------------------------------MouseExited
  /*METHOD VisualComponent */ /* Is invoked when the mouse exits the component. */
 public void mouseExited(MouseEvent agEvent) {}
 //-------------------------------------------------------------------------------------MousePressed
  /*METHOD VisualComponent */
  /* Is invoked when a mouse button has been pressed on the component. */
 public void mousePressed(MouseEvent agEvent) {}
 //------------------------------------------------------------------------------------MouseReleased
 /*METHOD VisualComponent */
 /* Is invoked when a mouse button has been released on the component. */
 public void mouseReleased(MouseEvent agEvent) {}
}

// End //-------------------------------------------------------------------------------------------