/*
   Tamot --- Task Modelling Editor
   Copyright (C) 2000 Commonwealth Scientific and Industrial Research Organisation
   (CSIRO), Australia. All rights reserved. 

   The Software, owned by CSIRO Australia, has been developed by the CSIRO 
   Intelligent Interactive Technology group. 
   For more information, please see http://www.cmis.csiro.au/iit/.

   The Software is a beta-test version for internal research and evaluation purposes 
   by the Licensee. The Software is still at a development stage. 
   It has not undergone complete testing and may have inherent errors,
   bugs or deficiencies that can affect the operation of the Software. 

   We encourage your feedback and suggestions. Any bugs / suggestions found please email to
   Shijian.Lu@cmis.csiro.au and Thomas.Lo@cmis.csiro.au. 

   After you have signed the Beta-Test Software License Agreement with the CSIRO,
   CSIRO grants you a non-exclusive, non-transferable license to use it only for your 
   personal, non-commercial and lawful end use. Implied licenses are negated. 

   Warranty Disclaimer : 

   CSIRO supplies the Software on an "as is" basis and makes no warranties that use of
   the Software by the Licensee will not infringe any third party’s 
   Intellectual Property Rights nor that the Software will be of merchantable quality,
   or suitable for a particular purpose. CSIRO excludes all terms, conditions and
   warranties implied by custom, the general law or statute in relation to the
   Software.
*/

package taskModellingTool;

import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.geom.*;
import java.awt.font.*;
import java.io.*;
import java.lang.reflect.*;

public class BooleanConnector extends LinkableComponent{
    private static final Color BACKGROUND_COLOR=new Color(250,210,160);
    protected static final Color BACKGROUND_SELECTED_COLOR=new Color(250,200,200);
    private static final Color BACKGROUND_ICON_COLOR=new Color(200,200,200);
    private static final Color BORDER_COLOR=new Color(100,100,150);
    private static final Color FOREGROUND_COLOR=new Color(0,0,0);
        
    protected static final double w0=1.2;  //in u
    protected static final double h0=0.7; // in u
    protected double w=w0;
    protected double h=h0;


    private static final float STROKE_SIZE=0.5f;
    
    private static final int ROOF_RATIO=4;
    private static final int FLOOR_RATIO=5;
    private static final int TEXT_MARGIN_RATIO=6;
    private static final int FIRST_LOCATION_X=50;
    private static final int FIRST_LOCATION_Y=50;
    protected final static String REF_STRING="bc";
        
    protected static Object [][] attributesToDisplay={{"name"},{"type"}};
    
    protected static boolean [] userAttributes=         {true,    true};
    
    protected static Object [] dialogsFields={"name","type"};
    
    private static Object [] cloneFields={"type"};
    
    //attributes to display
    public String type;
    
    /**
     * Create the Boolean Connector (name, bounds, shape).
     * Default position
     **/
    ///  
    public BooleanConnector(String type){
    	super(REF_STRING);
    	this.type=type;
    	setBounds(FIRST_LOCATION_X,FIRST_LOCATION_Y,r(w*u)+1,r(h*u)+1);    		    	
    	backupX=FIRST_LOCATION_X;
    	backupY=FIRST_LOCATION_Y;
    	setArea(w*u,h*u);   		    	
    }
    
    /**
     * Create the Boolean Connector (name, bounds, shape).
     **/
    ///  
    public BooleanConnector(String type,int posx,int posy){
    	super(REF_STRING);
    	this.type=type;
    	setBounds(posx,posy,r(w*u)+1,r(h*u)+1);    		    	
    	backupX=posx;
    	backupY=posy;
    	setArea(w*u,h*u);   		    	
    }
    
    /**
     * Copy constructor.
     **/
    ///  
    public BooleanConnector(BooleanConnector lc) {
    	super(REF_STRING);
    	setBounds(lc.getBounds());    		    	
    	backupX=getX();
    	backupY=getY();    	
    	name=lc.name;
    	Class cl=lc.getClass();
    	Field field;
    	String type;

        for (int i=0;i<cloneFields.length;i++) {
    	   try {
    	       field=(cl.getField((String)cloneFields[i]));
    	       type=field.getType().getName();
    	       if (type.equals("java.lang.String"))
    	           field.set(this,field.get(lc));
    	       else if (type.equals("int"))
    	           field.setInt(this,field.getInt(lc));
    	       else if (type.equals("boolean")) {
    	           field.setBoolean(this,field.getBoolean(lc));
    	           System.out.println("Fields: original: "+field.getBoolean(lc)+"   new: "+field.getBoolean(this));
               }
   	       }
           catch (Exception except){System.err.println(except.toString());}
        }
        setArea(w*u,h*u);   		    	
        
        ID = lc.ID;
    }

    //--------------------------- IO ------------------------------/
    /**
     * Do not use (its only for externalization purposes)
     */
    ///   
    public BooleanConnector() {
    	super();
    }
    
    ///
    public void writeExternal(ObjectOutput out) throws IOException{
    	super.writeExternal(out);
    	out.writeObject(type);
    }
    
    ///
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
    	super.readExternal(in);
    	type=(String)in.readObject();  	
    	setArea(getWidth(),getHeight()); 	
    }

    public void writeXML(PrintStream o,int tabLevel) {
        o.print(getTABs(tabLevel)+"<Boolean_Connector ");
        o.print("Name=\""+name+"\" ");
        o.print("id=\"_"+ID+"\" ");
        o.print("Type=\""+type+"\">");
        o.println("</Boolean_Connector>");
    }
    
    /**
     * Importation format
     */
    ///
    public void writeASCII(PrintStream o){
    	o.println(FileManager.BOOLEAN_CONNECTOR);
    	o.println(name);
    	o.println(type);
    	o.println();
    }
    
    /**
     * Importation format
     */
    ///
    public void readASCII(BufferedReader i) {
    	/*String s;
    	try {
    	    backupX=FIRST_LOCATION_X;
    	    backupY=FIRST_LOCATION_Y;
    	    s=i.readLine();
    	    if (!s.equals("")) backupX=Double.parseDouble(s);
    	    s=i.readLine();
    	    if (!s.equals("")) backupY=Double.parseDouble(s);
    	    setLocation(r(backupX),r(backupY));
        } catch (Exception excep){}//(NumberFormatException excep){},catch (IOException excep){}
    	*/
    	try {
    	    name=i.readLine();
        } catch (Exception excep){}
    	try {
    	    type=i.readLine();
        } catch (Exception excep){}
    	setSize(r(w*u)+1,r(h*u)+1);
    	setArea(r(w*u),r(h*u));
    }    

    public void setSizeArea() {
        setSize(r(w*u)+1,r(h*u)+1);
        setArea(r(w*u),r(h*u));
    }
    
    ///
    public Object [][] getAttributesToDisplay(){
    	return attributesToDisplay;
    }
    
    ///
    public void setAttributesToDisplay(Object [][] o){
    	attributesToDisplay=o;
    }
    
    ///
    public boolean [] getUserAttributes(){
    	return userAttributes;
    }
    
    ///
    public void setUserAttributes(boolean[] o){
    	userAttributes=o;
    }
    
    ///
    public Object [] getDialogsFields(){
    	return dialogsFields;
    }
    
    ///
    public void setDialogsFields(Object [] o){
    	dialogsFields=o;
    }
    
    ///
    public Object [] getCloneFields(){
    	return cloneFields;
    }
    
    ///
    public void setCloneFields(Object [] o){
    	cloneFields=o;
    }

    private void setArea(double w,double h){
    	double hr=h/ROOF_RATIO;
    	double hf=h-h/FLOOR_RATIO;
        double [] xpoints={0,w/2,w,w,w/2,0};
        double [] ypoints={hr,0,hr,hf,h,hf};
	area = new Area(new Polygon(round(xpoints),round(ypoints),6));    	
    }
    
    ///   
    protected void drawComponent(Graphics2D g2){
    	setArea(w*u,h*u);
    	double hr=h/ROOF_RATIO;
    	double hf=h-h/FLOOR_RATIO;
        
        setSize(r(w*u)+1,r(h*u)+1);
        
 	    g2.setStroke(new BasicStroke(STROKE_SIZE));
        
        if (isShiftSelected()) g2.setColor(BottomUp.BACKGROUND_SHIFT_SELECTED_COLOR);
        else if (isSelected()) g2.setColor(BACKGROUND_SELECTED_COLOR);
        else g2.setColor(BACKGROUND_COLOR);
        
        g2.fill(area);
        g2.setColor(BORDER_COLOR);
        g2.draw(area);
        g2.setColor(FOREGROUND_COLOR);
        
        if (!type.equals("")){
            double wl=w-2*(w/TEXT_MARGIN_RATIO);
            double hl=hf-hr;
            hl-=2*(hl/TEXT_MARGIN_RATIO);
    	    TextLayout layout = new TextLayout(type,new Font("Helvetica", Font.PLAIN, 96),new FontRenderContext(null, false, false));
            Rectangle2D r=layout.getBounds();
            AffineTransform textAt = new AffineTransform();
            textAt.translate(w*u/TEXT_MARGIN_RATIO,hf*u-(hf-hr)*u/TEXT_MARGIN_RATIO);
            textAt.scale(wl*u/r.getWidth(),hl*u/r.getHeight());
            Shape text=layout.getOutline(textAt);
            g2.fill(text);
        }
    }
    
    /**
     * The icon is darker iff b=false
     */
    ///
    public static ImageIcon getReductedIcon(int w,int h,double f,String type,boolean b){
    	BufferedImage image=new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
    	Graphics2D g2=image.createGraphics();
    	//AlphaComposite ac=AlphaComposite.getInstance(AlphaComposite.SRC_OVER,0.5f);
    	//g2.setComposite(ac);
    	drawIcon(g2,(int)Math.round(w*(1-f)),(int)Math.round(h*(1-f)),type,b);
    	return new ImageIcon(image);  	
    }
    
    /**
     * The icon is darker iff b=false
     */
    ///
    public static ImageIcon getIcon(int w,int h,String type,boolean b){
    	BufferedImage image=new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
    	Graphics2D g2=image.createGraphics();
    	//AlphaComposite ac=AlphaComposite.getInstance(AlphaComposite.SRC_OVER,0.5f);
    	//g2.setComposite(ac);
    	drawIcon(g2,w,h,type,b);
    	return new ImageIcon(image);  	
    }
    
    ///
    protected static void drawIcon(Graphics2D g2,int w,int h,String type,boolean b){
    	g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
    	//g2.setColor((b)?BACKGROUND_ICON_COLOR:(BACKGROUND_ICON_COLOR).darker());
    	//Rectangle rr=new Rectangle(0,0,w,h);
    	//g2.fill(rr);
    	int marge=1;
    	int w2=w-2*marge;
    	int h2=h-2*marge;
    	int hr=h2/ROOF_RATIO;
    	int hf=h2-h2/FLOOR_RATIO;
        int [] xpoints={1,w2/2,w2,w2,w2/2,1};
        int [] ypoints={hr,1,hr,hf,h2,hf};
	Shape s = new Polygon(xpoints,ypoints,6);
    	g2.setColor((b)?BACKGROUND_COLOR:(BACKGROUND_COLOR).darker());
    	g2.fill(s);
    	g2.setColor((b)?BORDER_COLOR:(BORDER_COLOR).darker());
    	g2.draw(s);
    	
        if (!type.equals("")){
            int wl=w2-2*(w2/TEXT_MARGIN_RATIO);
            int hl=hf-hr;
            hl-=2*(hl/TEXT_MARGIN_RATIO);
    	    TextLayout layout = new TextLayout(type,new Font("Helvetica", 1, 96),new FontRenderContext(null, false, false));
            Rectangle2D r=layout.getBounds();
            AffineTransform textAt = new AffineTransform();
            textAt.translate(w2/TEXT_MARGIN_RATIO+marge,hf-(hf-hr)/TEXT_MARGIN_RATIO+marge);
            textAt.scale(wl/r.getWidth(),hl/r.getHeight());
            Shape text=layout.getOutline(textAt);
            g2.fill(text);
        }
  	
    }
    
    ///
    public static Image getComponentCursor(int wi,int hi) {
    	//BufferedImage image = new BufferedImage(wi,hi,BufferedImage.TYPE_INT_ARGB);
        // add 1 pixel to both width & height after upgrading from JDK v.1.22 to v.1.31
        BufferedImage image = new BufferedImage(wi+1,hi+1,BufferedImage.TYPE_INT_ARGB);

        Graphics2D g2 = image.createGraphics();
    	
        AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,0.5f);
    	g2.setComposite(ac);
    	
        drawCursor(g2,wi,hi);
        
    	return image;  	
    }
    
    protected static void drawCursor(Graphics2D g2,int cursorWidth,int cursorHeight) {
    	g2.setColor(Color.black);

        double ww = cursorWidth;
        double hh = cursorHeight;

        double RATIO_FOR_ARROW_LINE = 0.3;
        
        // (xc,yc) = top left-hand corner of hexagon
        double xcenter = ww * RATIO_FOR_ARROW_LINE;
        double ycenter = hh * RATIO_FOR_ARROW_LINE;
        int xc = (int)Math.round(xcenter);
        int yc = (int)Math.round(ycenter);

        // slope of cursor
        double slope = Math.atan(hh/ww);

        double RATIO_FOR_ARROW_HEAD = 0.4;
        double DANGLE = Math.PI/6;     // 30 degree
        
        double xarrowHead = xcenter * RATIO_FOR_ARROW_HEAD;
        double yarrowHead = ycenter * RATIO_FOR_ARROW_HEAD;
        
        double xoffset = yarrowHead*Math.tan(DANGLE);
        double yoffset = xarrowHead*Math.tan(DANGLE);

        double xs[] = {0,xarrowHead-xoffset,xarrowHead+xoffset};
        double ys[] = {0,yarrowHead+yoffset,yarrowHead-yoffset};

        // draw the arrow line
        g2.drawLine(0,0,xc,yc);

        // draw the arrow head
        Polygon p = new Polygon(round(xs),round(ys),3);
    	g2.fill(p);
    	
        // width & height of hexagon
    	int www = cursorWidth - xc;
    	int hhh = cursorHeight - yc;
        
    	int hr = hhh/ROOF_RATIO;
    	int hf = hhh-hhh/FLOOR_RATIO;
        
        int [] xpoints = {xc,   xc+www/2,xc+www,xc+www,xc+www/2,xc};
        int [] ypoints = {yc+hr,yc,      yc+hr, yc+hf, yc+hhh,  yc+hf};
        
        // draw the hexagon
	    p = new Polygon(xpoints,ypoints,6);    	
    	g2.draw(p);
    }
    
    private static int[] round(double [] t){
    	int [] result=new int[t.length];
    	for (int i=0;i<t.length;i++){
    	    result[i]=(int)Math.round(t[i]);
    	}
    	return result;
    }
    private static int r(double d){
    	return (int)Math.round(d);
    }
    
    public double giveWidth(){
    	return w0;
    }
    
}