package oracle.forms.fd;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Point;
import oracle.forms.handler.IHandler;
import oracle.forms.ui.FormMouseGrabProvider;
import oracle.forms.ui.VBean;
import oracle.forms.properties.ID;
import oracle.forms.ui.CustomEvent;
import oracle.forms.engine.Main;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.StringTokenizer;

import oracle.forms.ui.VCheckbox;
import oracle.forms.ui.VComboBox;
import oracle.forms.ui.VPopList;
import oracle.forms.ui.VRadioButton;
import oracle.forms.ui.VRadioGroup;
import oracle.forms.ui.VTList;

/**
 * A Bean to handle the mouse events
 * use the Java reflexion to get the component
 * properties and methods
 * it etablish the matching between the java components
 * and the Forms module items
 *
 * @author Francois Degrelle
 * @version 1.4
 */
   
public class HandleMouseEvent2 extends VBean
{
  // variables
  private static final ID getInfos      = ID.registerProperty("GETINFOS");
  private static final ID setEvent      = ID.registerProperty("SETEVENT");
  private static final ID AllowEvent    = ID.registerProperty("ALLOWEVENT");  
  private static final ID TraceWidget   = ID.registerProperty("TRACEWIDGET");
  private static final ID SEND_MSG      = ID.registerProperty("SENDMSG");        
  private static final ID SEND_PROPS    = ID.registerProperty("SENDPROPS");  
  private static final ID SET_PROP      = ID.registerProperty("SETPROP");  
  private static final ID SET_LOG       = ID.registerProperty("SETLOG");    
  private static final ID SET_HIGLIGHT  = ID.registerProperty("SETHIGLIGHT");
  private static final ID MSGPROPS      = ID.registerProperty("MSGPROPS");     
  private static final ID MSGEVENT      = ID.registerProperty("MSGEVENT");       
  private static final ID MSGCOORD      = ID.registerProperty("MSGCOORD");         
  private static final ID MSGITEM       = ID.registerProperty("MSGITEM");
  private static final ID MSGTYPE = ID.registerProperty("MSGTYPE");  
  private static final ID MSGBTMOUSE    = ID.registerProperty("MSGBTMOUSE");           
  private IHandler     m_handler;  
  private Main         formsMain = null;
  private int          iMode = 0 ;
  private int          iInc = 20 ;
  private Color        oldColor   = null ;
  private Color        hightColor = null ;  
  private boolean      bMove  = false ;
  private boolean      bEnter = true ;  
  private boolean      bExit  = true ;  
  private boolean      bClick = true ;  
  private boolean      bPress = true ;
  private boolean      bRel   = true ;  
  private boolean      bGetEvents = true ;
  public boolean       bHighlight = false;
  private boolean      bLog   = false ;
  // objects to check
  private boolean      bAllWidgets = true ;
  private boolean      bButton = true ;
  private boolean      bCheckBox = true ;
  private boolean      bRadioButton = true ;  
  private boolean      bTextField = true ;
  private boolean      bTextArea = true ;
  private boolean      bPopList = true ;  
  private boolean      bTList = true ;
  private boolean      bComboBox = true ;
  private boolean      bCanvas = true ;  
  private boolean      bWindow = true ;
  private boolean      bMenu = true ;
  private boolean      bStatusBar = true ;      
  
  private String       sItem = "" ;
  private String       sType = "";     
  private String       sEvent = "" ;
  private String       sCoord = "" ;
  private String       sButton = "" ;
  private Point        point ;
  private Component[]  tComps = null ;
  private StringBuffer sbProperties = new StringBuffer() ;
  
  public void init(IHandler handler)
  {
    m_handler = handler;
    super.init(handler);
    // getting the Forms Main class
    //formsMain  =  (Main) handler.getApplet();
      // getting the Forms Main class
      try{
        Method method = 
           handler.getClass().getMethod("getApplet", new Class[0]);
        Object applet = method.invoke(handler, new Object[0]);
        if (applet instanceof Main) {
           formsMain     =  (Main)applet;
        }      
      }catch(Exception ex) {;}
      
    // add mouse listener to the Forms module
    _addMouseListeners(formsMain.getCursorGrabProvider());
  }  
  
    public void _addMouseListeners (FormMouseGrabProvider c)
    {
      c.addMouseMotionGrab(new MouseMotionListener(){

      public void mouseMoved(MouseEvent me)
      {
        if(bMove) handleComponent(me.getComponent(), me, "mouseMoved");       
      }
      public void mouseDragged(MouseEvent me)
      {
        // drag and drop is not supported in Forms9i and 10g. Therefore the
        // drag event is useless to capture
      }
    });

    c.addMouseGrab(new MouseListener(){

        public void mouseExited(MouseEvent me)
        {
          if(bExit) handleComponent(me.getComponent(), me, "mouseExited");          
        }
        public void mouseEntered(MouseEvent me)
        {
          if(bEnter) handleComponent(me.getComponent(), me, "mouseEntered");
        }
        public void mousePressed(MouseEvent me)
        {
          if(bPress) handleComponent(me.getComponent(), me, "mousePressed");          
        }
        public void mouseReleased(MouseEvent me)
        {
          if(bRel) handleComponent(me.getComponent(), me, "mouseReleased");          
        }
        public void mouseClicked(MouseEvent me)
        {
          if(bClick) handleComponent(me.getComponent(), me, "mouseClicked");          
        }
    });
  }  
  
  /*************************
   *  Set some properties  *
   ************************/
  public boolean setProperty(ID property, Object value)
  {
    /***************************
     *  enable/disable events  *
     ***************************/
    // enable/disable individual event
    if (property == setEvent)   
    {
      String s="", sEvent="", sFlag="" ;
      int    ipos=-1;
      boolean bFlag = false ;
      s = value.toString();
      ipos = s.indexOf("=") ;
      if(ipos > -1)
      {
        sEvent = s.substring(0,ipos);
        sFlag  = s.substring(ipos+1);
        if(sFlag.equalsIgnoreCase("true")) bFlag = true ;
        if(sEvent.equalsIgnoreCase("move"))  bMove = bFlag ;
        if(sEvent.equalsIgnoreCase("enter")) bEnter = bFlag ;
        if(sEvent.equalsIgnoreCase("exit"))  bExit = bFlag ;
        if(sEvent.equalsIgnoreCase("press")) bPress = bFlag ;
        if(sEvent.equalsIgnoreCase("click")) bClick = bFlag ;
      }
      return true ;
    }
    // enable/disable event capture
    else if (property == AllowEvent)   
    {
      String s= value.toString();
      if(s.equalsIgnoreCase("true")) bGetEvents = true ;
      else bGetEvents = false ;
      return true ;
    }
    // init the item list
    else if (property == getInfos)   
    {
      getItems();
      return true ;
    }
    //SET_HIGLIGHT
     else if (property == SET_HIGLIGHT) {  
         String s = value.toString();
         String sItem = "", sProp = "";
         int iR, iG, iB, ipos = -1;
         ipos = s.indexOf(",");
         if (ipos > -1) {
            System.out.println("SETHIGHLIGHT color:" + value.toString());
            StringTokenizer st = new StringTokenizer(s, ",");
            iR = Integer.parseInt(st.nextToken());
            iG = Integer.parseInt(st.nextToken());
            iB = Integer.parseInt(st.nextToken());
            hightColor = new Color(iR, iG, iB);
            iMode = 1;
            bHighlight = true ;
         } else {
            if(s.equalsIgnoreCase("true")) bHighlight = true ;
            else if(s.equalsIgnoreCase("false")) bHighlight = false ;
            else
            {
              System.out.println("SETHIGHLIGHT:" + value.toString());
              if (s.indexOf("-") > -1)
                iInc = Integer.parseInt(s.substring(1)) * -1;
              else
                iInc = Integer.parseInt(s.substring(1));
              iMode = 0;
              bHighlight = true ;
            }
         }
       return true ;
     }    
    // enable/disable event capture
    else if (property == SET_PROP)   
    {
      String s= value.toString();
      String sItem="", sProp="" ;
      int iPosX=0, iPosY=0 ;
      StringTokenizer st = new StringTokenizer(s,",");
      sProp = st.nextToken() ;
      iPosX = Integer.parseInt(st.nextToken()) ; 
      iPosY = Integer.parseInt(st.nextToken()) ; 
      point = new Point(iPosX, iPosY) ;
      log("SetProp "+sProp+" "+iPosX+" "+iPosY) ;
      for(int i=0; i<tComps.length; i++)
      {
         if(tComps[i].getLocation().getX() == iPosX &&
            tComps[i].getLocation().getY() == iPosY) 
         {
           tComps[i].setName(sProp);
           log("--> found "+tComps[i].getName()) ;
           return true ;
         }
      }
      return true ;
    }
    // log
    else if (property == SET_LOG)   
    {
      if(value.toString().equalsIgnoreCase("true")) bLog = true ;
      else if(value.toString().equalsIgnoreCase("false")) bLog = false ;
      return true ;
    }
    else
    {
     return super.setProperty(property, value);
    }
  }  

  /************************
   *  Get the properties  *
   ***********************/
   public Object getProperty(ID pId)
   {
     return super.getProperty(pId);
   } 

  /*
   * Etablish the correspondance between the Java component
   * and the Forms module item
   * display information about the mouse state, location
   * and the component that raised the event
   */
  private void handleComponent(Component cp, MouseEvent me, String sEventName)
  {
    if(!bGetEvents) return ;
    sType = cp.getClass().getName();      
    log("Component clicked:"+cp.getClass().getName());    
    Component cpp = null ;
    String sClass = cp.getClass().toString();
    Point  pt = me.getPoint() ;
    double iX = pt.getX() ;
    double iY = pt.getY() ;
    sCoord = ""+iX+","+iY ;
    sButton = "" + me.getButton() ;
    sEvent = sEventName ;
    sItem="" ;
    if (bEnter && bExit && bHighlight) {
         if (sEvent.equalsIgnoreCase("MouseEntered")) {
            oldColor = cp.getBackground();
            if (iMode == 0)
               cp.setBackground(getHighlight(cp.getBackground()));
            else
               cp.setBackground(hightColor);
         }
         if (sEvent.equalsIgnoreCase("MouseExited"))
            cp.setBackground(oldColor);
    }
    // get correspondance with the Forms items
    if( ! sClass.equalsIgnoreCase("class oracle.forms.ui.VButton"))
      cpp = (cp.getParent() != null ? cp.getParent() : cp );
    else
      cpp = cp ;
    int i = 0 ;
    while(i<tComps.length)
    {
      if(tComps[i].getLocation().getX() == cpp.getLocation().getX() &&
         tComps[i].getLocation().getY() == cpp.getLocation().getY()) 
       {
         sItem = tComps[i].getName() ;
         break ;
       }
       i++;
    }
    if(bAllWidgets)SendMessage() ;
    else
    {
      if(bButton && cp instanceof oracle.forms.ui.VButton) SendMessage() ;  
      else if(bCheckBox && cp instanceof oracle.forms.ui.VCheckbox) SendMessage() ;  
      else if(bComboBox && cp instanceof oracle.forms.ui.VComboBox) SendMessage() ;  
      else if(bPopList && cp instanceof oracle.forms.ui.VPopList) SendMessage() ;  
      else if(bRadioButton && cp instanceof oracle.forms.ui.VRadioButton) SendMessage() ;  
      else if(bTList && cp instanceof oracle.forms.ui.VTList) SendMessage() ;  
      else if(bTextField && cp instanceof oracle.forms.ui.VTextField) SendMessage() ;  
      else if(bTextArea && cp instanceof oracle.forms.ui.VTextArea) SendMessage() ;  
      else if(bCanvas && cp instanceof oracle.forms.ui.DrawnPanel) SendMessage() ;  
      else if(bWindow && cp instanceof oracle.forms.ui.ExtendedFrame) SendMessage() ;  
      else if(bMenu && sClass.startsWith("oracle.ewt.lwAWT.lwMenu")) SendMessage() ;  
      else if(bStatusBar && (cp instanceof oracle.forms.ui.FormStatusArea || cp instanceof oracle.ewt.statusBar.StatusBar)) SendMessage() ;      
      else return ;
    }

    // if right-click, send properties message to Forms
    if(sButton.endsWith("3"))
    {
      bGetEvents = false ;
      // get the component properties
      exploreField(cp);
      // get the component methods
      exploreMethods(cp);
      // send all to Forms
      SendProperties();
      bGetEvents = true ;
    }
  }

  // send message back to Forms
  private void SendMessage() 
  {
    try{
      CustomEvent ce = new CustomEvent(m_handler, SEND_MSG);
      m_handler.setProperty( MSGITEM, sItem );
      m_handler.setProperty(MSGTYPE, sType);
      m_handler.setProperty( MSGEVENT, sEvent );
      m_handler.setProperty( MSGCOORD, sCoord );
      m_handler.setProperty( MSGBTMOUSE, sButton );
      dispatchCustomEvent(ce);  
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }    
  }

  // send component properties back to Forms
  private void SendProperties() 
  {
    try{
      CustomEvent ce = new CustomEvent(m_handler, SEND_PROPS);
      m_handler.setProperty( MSGPROPS, sbProperties.toString() );
      dispatchCustomEvent(ce);  
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }    
  }

  /*
   *   Reflexion methods
   */
  public void exploreField(Object o)
   {
      Field[] f = null;
      Class c = null;
    
      c = o.getClass();
      f = c.getFields();
      consultField(f,o);
   }
  
   public void exploreMethods(Object o)
   {
      Method[] m = null;
      Class c = null;
    
      c = o.getClass();
      m= c.getMethods();
      consultMethods(m);
   }
  
   private void consultField(Field[] f, Object o)
   {
      sbProperties = new StringBuffer("  ** component properties **/n") ;
      for(int i=0;i<f.length;++i)
      {      
         sbProperties.append(Modifier.toString(f[i].getModifiers())) ;
         sbProperties.append(" ");
         sbProperties.append(f[i].getType().getName());
         sbProperties.append(" ");
         sbProperties.append(f[i].getName());
         sbProperties.append(" = ");
         try
         {
            sbProperties.append(f[i].get(o)+"/n");
         }
         catch (IllegalAccessException e)
         {
           sbProperties.append("Unable to get value/n");
         }
      }
   }
  
   private void consultMethods(Method[] m)
   {
      Class[] params = null;
     sbProperties.append("/n  ** component methods **/n");
      for(int i=0;i<m.length;++i) 
      {      
         sbProperties.append(Modifier.toString(m[i].getModifiers()));
         sbProperties.append(" ");
         sbProperties.append(m[i].getReturnType().getName());
         sbProperties.append(" ");
         sbProperties.append(m[i].getName());
         sbProperties.append("(");
         params = m[i].getParameterTypes();
         for(int j=0;j<params.length;++j)
         {
           sbProperties.append(params[j].getName());
         }
         sbProperties.append(")/n");
      } 
   }
   
   /*
    * get the list of components
    */
   private void getItems()
   {
     Container cont = this.getParent();
     tComps = cont.getComponents() ;
     Point pt = null ;
     for(int i=0; i<tComps.length; i++)
     {
       // output the layer hierarchy
       pt = tComps[i].getLocation();
       log("--> "+tComps[i].getName()+" ["+tComps[i].getClass()+"]"
            + pt.getX() + ","+pt.getY()) ;
     }
   }
   private Color getHighlight(Color c)  
   {
     log("inc="+iInc);
     int r,g,b ;
     int iMax = ( iInc < 0 ? 0 : 255 ) ;
     r = c.getRed() ;
     g = c.getGreen();
     b = c.getBlue() ;

     r = (r+iInc >= iMax ? r+iInc : iMax) ;
     g = (g+iInc >= iMax ? g+iInc : iMax) ;
     b = (b+iInc >= iMax ? b+iInc : iMax) ;

     return new Color(r,g,b);
   }

    
    // method to print a message on the console
    public void log( String sMessage )
    {
      if( bLog) System.out.println( "[" + this.getClass().getName() + "] " + sMessage ) ;
    }          
   
}
