package oracle.forms.fd;

import java.applet.*;
import java.awt.*;
import java.awt.BasicStroke;
import java.awt.event.*;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.net.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import oracle.forms.handler.IHandler;
import oracle.forms.properties.ID;
import oracle.forms.ui.CustomEvent;
import oracle.forms.ui.VBean;

  /**
   * A Bean to have a html map behaviour
   *
   * @author Francois Degrelle
   * @version 1.0
   */
   
public class MapComponent extends VBean {
  public final static ID SETPOLYGON    = ID.registerProperty("SETPOLYGON"); 
  public final static ID SETRECT       = ID.registerProperty("SETRECT");   
  public final static ID SETIMAGE      = ID.registerProperty("SETIMAGE");  
  public final static ID SETFONTCOLOR  = ID.registerProperty("SETFONTCOLOR");   
  public final static ID ZONECLICKED   = ID.registerProperty("ZONECLICKED");     
  public final static ID NAME          = ID.registerProperty("NAME");       
  Graphics2D g2 ;
  JPanel jp = new JPanel();
  zone[] tz = new zone[100] ;
  public IHandler  m_handler;  
  final static float dash1[] = {1.3f};
  final static BasicStroke dashed = new BasicStroke(1.0f, 
                                                      BasicStroke.CAP_BUTT, 
                                                      BasicStroke.JOIN_MITER, 
                                                      10.0f, dash1, 0.0f);
  private Color cFontColor = Color.black; 
  private JLabel bigLabel = new JLabel();
  private int iMaxZones=0, iSelectedZone = -1 ;
  private int iCurrent=-1, iOld=-1 ;
  private int iPosX=0, iPosY=0; 
  private boolean bLog = true ;
  private URL m_codeBase;  
  private ImageIcon image = null ; 

 public MapComponent() 
  {
    super();
  }
  
 public void init(IHandler handler)
 {
    m_handler = handler;
    super.init(handler);
    boolean bCont=true;
    int index = 1;
    jp.setLayout(null);
    jp.setVisible(true);    
    add(jp);

  }
 
  /****************************
   *  Set the map properties  *
   ***************************/
  public boolean setProperty(ID property, Object value)
  {
    if (property == SETPOLYGON) // set a polygonal zone
    {
      String text="";
      String sUrl = "";
      String s = value.toString();
      Polygon p = new Polygon();
      try {
       StringTokenizer tokenizer = new StringTokenizer(s, ",");
       text = tokenizer.nextToken() ;
       sUrl = tokenizer.nextToken() ;
       while (tokenizer.hasMoreTokens()) {
         String str = tokenizer.nextToken().trim();
         int x = Integer.parseInt(str);
         str = tokenizer.nextToken().trim();
         int y = Integer.parseInt(str);
         p.addPoint(x, y);
         }
     }
     catch (Exception ex) { }
     tz[iMaxZones++] = new zone(p, text, sUrl, new Rectangle(p.getBounds()));
     PolygonButton btn = new PolygonButton(p,text, sUrl, jp);
     repaint();
     return true;
    }
    else if (property == SETRECT) // set a rectangular zone
    {
      String text="";
      String sUrl = "";
      String s = value.toString();
      int x=0, y=0, w=0, h=0;
      Polygon p = new Polygon();
      StringTokenizer tokenizer = new StringTokenizer(s, ",");
      text = tokenizer.nextToken() ;
      sUrl = tokenizer.nextToken() ;
      x = Integer.parseInt(tokenizer.nextToken().trim()); // X pos
      y = Integer.parseInt(tokenizer.nextToken().trim()); // Y pos
      w = Integer.parseInt(tokenizer.nextToken().trim()); // Width
      h = Integer.parseInt(tokenizer.nextToken().trim()); // Height
      p.addPoint(x,y);
      p.addPoint(x+w,y);
      p.addPoint(x+w,y+h);
      p.addPoint(x,y+h);
      tz[iMaxZones++] = new zone(p, text, sUrl, new Rectangle(p.getBounds()));
      PolygonButton btn = new PolygonButton(p,text, sUrl, jp);      
      repaint();
     return true;
    }    
    else if (property == SETIMAGE) // set the background image
    {
      String sImageName = value.toString() ;
      Image img = loadImage(sImageName);
      if(img != null) image = new ImageIcon(img);
      return true ;
    }
    else if (property == SETFONTCOLOR) // set the area color
    {
      cFontColor = getColor(value.toString()) ;
      return true ;
    }     
    else
    {
     return super.setProperty(property, value);
    }
  }    

    /************************
     *  Get the properties  *
     ***********************/
    public Object getProperty(ID pId) // Get the current area name
    {
      
      if (pId == NAME && iCurrent >=0)
      {
        return "" + tz[iCurrent].name;
      }
      else
      {
        return super.getProperty(pId);
      }
    } 
    
 public void paint(Graphics g) {
  g2 = (Graphics2D) g ;
  g2.setColor(cFontColor);
  g2.setStroke(dashed);
  image.paintIcon(null,g2,0,0);
  for( int i=0 ; i<iMaxZones; i++)
  {
    g2.drawPolygon(tz[i].p);
  }
 } 

 /*************************************
  *  Show/Hide the selected map part  *
  ************************************/
 void display(int iNum, boolean b) {
  g2 = (Graphics2D) this.getGraphics();
  String sName="" ;
  if(g2 != null && iNum >= 0)
  {
    g2.setColor(Color.white);
    g2.clearRect((int)jp.getX(),(int)jp.getY(),(int)jp.getWidth(),(int)jp.getHeight());
    image.paintIcon(null,g2,0,0);
    if(b)
    {
      g2.setColor(cFontColor);
      g2.setStroke(dashed);
      g2.drawPolygon(tz[iNum].p);
      g2.setColor(Color.black);
      sName = tz[iNum].name ;
      
      Font font = new Font("Arial",Font.BOLD,14);
      FontRenderContext frc = g2.getFontRenderContext();
      TextLayout layout = new TextLayout(tz[iNum].name, font, frc);
      Rectangle2D bounds = layout.getBounds();
      g2.setColor(Color.white);
      g2.fillRect((int)((tz[iNum].r.getX()+(tz[iNum].r.getWidth()/2))-2),
                  (int)((tz[iNum].r.getY()+(tz[iNum].r.getHeight()/2))-(int)bounds.getHeight()),
                  (int)(bounds.getWidth()+4),
                  (int)(bounds.getHeight()+4));
      g2.setColor(cFontColor);      
      g2.setFont(font);
      g2.drawString(tz[iNum].name,(int)(tz[iNum].r.getX()+(tz[iNum].r.getWidth()/2)),(int)(tz[iNum].r.getY()+(tz[iNum].r.getHeight()/2)));
    }
  }
 } 
 
class PolygonButton extends JComponent implements MouseListener, MouseMotionListener
{
  int iPos = iMaxZones ;
  public PolygonButton(Polygon p,String name, String sUrl, JPanel jp)
  {
    //m_polygon = p;
    setBounds(p.getBounds());
    setName(name);
    jp.addMouseListener(this);     
    jp.addMouseMotionListener(this); 
  }

  /*********************************
   *  Show the corresponding area  *
   ********************************/
  public void mouseMoved(MouseEvent e) {
  iSelectedZone = iPos ;
  boolean bFound=false ;
  int x = e.getX();
  int y = e.getY();
  iPosX = x; iPosY = y ;
  for( int i=0; i<iMaxZones;i++)
  {
    if( tz[i].p.contains(x, y) ) 
    {
      bFound=true ;
      if(i != iCurrent)
      {
        iCurrent= i ;        
        if(iOld != iCurrent)
         {
           display( iOld, false );
         }        
        display( iCurrent, true );   
        iOld = iCurrent ;
      }      
      break ;
    }
  }
  if( (!bFound) && (iOld >= 0) && (iOld != iCurrent))
  {
    display( iOld, false ) ;
    display( iCurrent, false ) ;
    iCurrent = -1 ;
  }
  } 
  public void mouseDragged(MouseEvent e) {}
  
  /*****************************************
   *  Inform that a zone has been clicked  *
   ****************************************/
  public void mouseClicked(MouseEvent e) {
  if(iCurrent >=0 && (this.getName().equals(tz[iCurrent].name)))
  {
    System.out.println("Zone selected="+tz[iCurrent].name);
    CustomEvent ce = new CustomEvent(m_handler, ZONECLICKED);
    dispatchCustomEvent(ce);    
  }
 }
 public void mousePressed(MouseEvent e) {}
 public void mouseReleased(MouseEvent e) {}
 public void mouseExited(MouseEvent e) { mouseMoved(e); }
 public void mouseEntered(MouseEvent e) { mouseMoved(e); }
}

  public Color getColor(String colourValue) 
  {    
   try{      
    int r,g,b;      
    int rPos, gPos;      
    rPos = colourValue.indexOf(",");      
    gPos = colourValue.indexOf(",", rPos + 1);      
    if (rPos < 1 || gPos < 1 || gPos + 1 == colourValue.length()) {        
        throw new Exception("Invalid colour");
    }      
    r = Integer.parseInt(colourValue.substring(0, rPos));      
    g = Integer.parseInt(colourValue.substring(rPos + 1, gPos));      
    b = Integer.parseInt(colourValue.substring(gPos + 1));        
    if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) {        
       throw new Exception("Invalid colour");
    } 

    return new Color(r,g,b);
   } 
   catch(Exception e) {      
    return new Color(0,0,0);
   }  
  } 


  /*****************************************************************
   *  Load an image from JAR file, Client machine or Internet URL  *
   ****************************************************************/
  private Image loadImage(String imageName)
  {
    URL imageURL = null;
    boolean loadSuccess = false;
    Image img = null ;
    
    //JAR
    log("Searching JAR for " + imageName);
    imageURL = getClass().getResource(imageName);
    if (imageURL != null)
    {
      log("URL: " + imageURL.toString());
      try
      {
        img = Toolkit.getDefaultToolkit().getImage(imageURL);
        loadSuccess = true;
        log("Image found: " + imageURL.toString());
        return img ;
      }
      catch (Exception ilex)
      {
        log("Error loading image from JAR: " + ilex.toString());
      }
    }
    else
    {
      log("Unable to find " + imageName + " in JAR");
    }

    //DOCBASE
    if (loadSuccess == false)
    {
      log("Searching docbase for " + imageName);
      try
      {
        if (imageName.toLowerCase().startsWith("http://")||imageName.toLowerCase().startsWith("https://"))
        {
          imageURL = new URL(imageName);
        }
        else if(imageName.toLowerCase().startsWith("file:"))
        {
          imageURL = new URL(imageName);
        }
        else
        {
          imageURL = new URL(m_codeBase.getProtocol() + "://" + m_codeBase.getHost() + ":" + m_codeBase.getPort() + imageName);
        }
        log("Constructed URL: " + imageURL.toString());
        try
        {
          img = createImage((java.awt.image.ImageProducer) imageURL.getContent());
          loadSuccess = true;
          log("Image found: " + imageURL.toString());
          return img ;
        }
        catch (Exception ilex)
        {
          log("Error reading image - " + ilex.toString());
        }
      }
      catch (java.net.MalformedURLException urlex)
      {
        log("Error creating URL - " + urlex.toString());
      }
    }

    //CODEBASE
    if (loadSuccess == false)
    {
      log("Searching codebase for " + imageName);
      try
      {
        imageURL = new URL(m_codeBase, imageName);
        log("Constructed URL: " + imageURL.toString());
        try
        {
          img = createImage((java.awt.image.ImageProducer) imageURL.getContent());
          loadSuccess = true;
          log("Image found: " + imageURL.toString());
          return img ;
        }
        catch (Exception ilex)
        {
                log("Error reading image - " + ilex.toString());
        }
      }
      catch (java.net.MalformedURLException urlex)
      {
        log("Error creating URL - " + urlex.toString());
      }
    }

    if (loadSuccess == false)
    {
      log("Error image " + imageName + " could not be located");
    }
    return img ;
  }
  
  void log( String sMessage )
  {
    if( bLog) System.out.println( sMessage ) ;
  }
}
