/*
   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.lang.reflect.*;
import domainModel.*;

import java.io.*;

public class Task extends CompositeComponent{
    private static final Color BACKGROUND_COLOR = new Color(220,220,255);
    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);
    private static final Color CURSOR_COLOR=new Color(0,0,0);
    
    protected static final double w0=3;  //in u
    protected static final double h0=1; // in u
    protected double w=w0;
    protected double h=h0;
    
    
    //pre and post conditions
    protected static double CONDITION_WIDTH_RATIO=1;
    protected static double CONDITION_HEIGHT_RATIO=0.5;
    private static final double CONDITION_MARGIN_X_RATIO=0.2;
    private static final double CONDITION_MARGIN_Y_RATIO=0.05;
    private static final double CONDITION_SIZE_RATIO=0.30;
    protected static double CONDITION_NAME_OFFSET=-0.08;
    protected static double OFFSET_PRECONDITION=-0.3; //>-(length positive side)
    protected static double OFFSET_POSTCONDITION=OFFSET_PRECONDITION;//w0-CONDITION_WIDTH_RATIO+0.5;
    protected static double GAP_PRECONDITION=0.1;
    protected static double GAP_POSTCONDITION=0.1;
    protected static int MAX_LENGTH=25;
    
    private static final double COMPOSITE_WIDTH_RATIO=0.03;
    private static final double COMPOSITE_HEIGHT_RATIO=COMPOSITE_WIDTH_RATIO;
    private static final double ARC_WIDTH_RATIO=0.4;
    private static final double ARC_HEIGHT_RATIO=ARC_WIDTH_RATIO;
    private static final char INFINITE=236;

    private static final double NAME_MARGIN_RATIO=0.5;
    private static final double NAME_SIZE_RATIO=0.5;
    private static final double INTERVAL_SIZE_RATIO=0.30;
    private static final double INTERVAL_MARGIN_RATIO_X=0.4;
    private static final double INTERVAL_MARGIN_RATIO_Y=0.25;
               
    private static final int FIRST_LOCATION_X=50;
    private static final int FIRST_LOCATION_Y=50;
    
    private static final float STROKE_SIZE=0.25f;
    public static final String [] STYLE_VALUE={"Interactive", "Automatic","Manual"};
    
    protected static double offpt=OFFSET_POSTCONDITION;
    protected static double offpr=OFFSET_PRECONDITION;
    protected static double gappt=GAP_POSTCONDITION;
    protected static double gappr=GAP_PRECONDITION;
    
    //size and position for terminal event
    protected static double TERM_X0=0.75;
    protected static double TERM_Y0=1.3;
    protected static double TERM_SIZE=0.75;
    protected static double TERM_ARROW=0.2;     	
    	
    protected transient Shape compositeShape;
    
    //Attributes that can be displayed in the attributes panel
    //protected static Object [][] attributesToDisplay={{"name"},{"semantics"},{"composite",bF},{"mandatory"},{"interactive"},{"minCard"},{"maxCard"},{"precondition"},{"postcondition"},{"feedback"},{"terminal"},{"dirty"}/*,{"action"},{"object"}*/};
    protected static Object [][] attributesToDisplay={{"name"},{"semantics"},{"composite",bF},{"mandatory"},{"style"},{"minCard"},{"maxCard"},{"precondition"},{"feedback"},{"terminal"},{"dirty"},{"_preconDM"},{"_feedbackDM"}, {"warning"},{"actor"},{"other"}};   //do not display postcondition
    
    //Initial attributes to display in the attribute panel
    protected static boolean [] userAttributes=         {true,    false,          true,          true,         true,    true,        true,      true,           true,		true,        true	,      false,       false,        true,        true,  	true	};
    
    //Attributes in the edition dialog
    //protected static Object [] dialogsFields={"name","dirty","semantics","mandatory","interactive","minCard","maxCard","precondition","postcondition","feedback","terminal"}; //don't put action and object here
    protected static Object [] dialogsFields={"name","mandatory","style","minCard","maxCard","precondition","feedback","terminal", "actor","other","dirty"}; //don't display postcondition
    
    //cloneable attributes
    private static Object [] cloneFields={"semantics","composite","mandatory","style","minCard","maxCard","precondition","postcondition","feedback","terminal","warning","actor","other","dirty","_preconDM","_feedbackDM" /*,"action","object"*/};
        
    //Task's attributes    

    public boolean mandatory=true;
//    public boolean interactive=true;
    public String style=STYLE_VALUE[0];
    public int minCard=0;
    public int maxCard=-1;
    public String precondition="";
    public String postcondition="";
    public String feedback=""; 
    public boolean dirty=true;
    public String semantics="";
    public boolean terminal=false;
 
    //shijian 2001-3-21
    // for storing action-instance ID for precondition and feedbacks
    public String _preconDM="";
    public String _feedbackDM="";
    
    //shijian 2001-3-21
    // new attributes for language genenration
    public String warning="";
    public String other=""; 
    public String actor="";

    public boolean background=false;    // for HTML Report Settings
    public boolean comment=false;    // for HTML Report Settings
    public boolean tip=false;    // for HTML Report Settings
    //public boolean warning=false;    // for HTML Report Settings
    public boolean annotation=false;    // for HTML Report Settings
    /*public String action="";
    public String object="";*/

    public Task(String name) {
    	super(name);
    	//semantics=getName(); shijian 2001-1-10
    	setLocation(FIRST_LOCATION_X,FIRST_LOCATION_Y);
    	backupX=FIRST_LOCATION_X;
    	backupY=FIRST_LOCATION_Y;
    	setSize(r(w*u)+1,r(h*u)+1);
    	setArea(r(w*u),r(h*u));   		    	
    }
    
    public Task(String name,int posx,int posy){
    	super(name);
    	//semantics=getName();shijian 2001-1-10

    	setLocation(posx,posy);
    	backupX=posx;
    	backupY=posy;
    	setSize(r(w*u)+1,r(h*u)+1);    		    	
    	setArea(r(w*u),r(h*u));   		    	
    }
    
    //copy constructor
    public Task(Task lc){
    	super();
    	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));
    		}
    		catch (Exception except) { 
    			System.err.println(except.toString());
    		}
    	}
    	setArea(r(w*u),r(h*u));   		    	
    	
	    //Thomas ?V5
    	ID = lc.ID;
    }

    //--------------------------- IO ------------------------------/
    //for externalization purposes    
    public Task() {
    	super();
    }
    
    public void writeExternal(ObjectOutput out) throws IOException{
    	super.writeExternal(out);
    	out.writeBoolean(mandatory);
//    	out.writeBoolean(style);
    	out.writeObject(style);
    	out.writeInt(minCard);
    	out.writeInt(maxCard);
    	out.writeObject(precondition);
    	out.writeObject(postcondition);
    	out.writeObject(feedback);
    	out.writeObject(semantics);
    	out.writeBoolean(terminal);
    	out.writeBoolean(dirty);

    }
    
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
    	super.readExternal(in);
    	mandatory=in.readBoolean();  	
//    	style=in.readBoolean();
    	style=(String)in.readObject();
    	minCard=in.readInt();
    	maxCard=in.readInt();
    	precondition=(String)in.readObject();
    	postcondition=(String)in.readObject();
    	feedback=(String)in.readObject();
    	semantics=(String)in.readObject();
    	terminal=in.readBoolean();
    	dirty=in.readBoolean();
    	setArea(getWidth(),getHeight()); 	
    }
    
    public void writeASCII(PrintStream o){
    	o.println(FileManager.TASK);
    	o.println(name);
    	//shijian 2001-8-2
    	// don't ouput semantics in IMP format
     	//o.println(semantics);
	   	o.println("");	//write nothing for semantics
    	//o.println(dirty);
    	
    	o.println(feedback);
    	o.println(minCard);
    	o.println(maxCard);
    	o.println(precondition);
    	o.println(postcondition);
    	o.println((mandatory)?"Mandatory":"Optional");
//    	o.println((style)?"Interactive":"Automatic");
    	o.println(style);
    	o.println((composite)?"Composite":"Elementary");
    	o.println((terminal)?"Yes":"No");
    	
    	//shijian 2001-3-22 
    	o.println();
    	if (_preconDM !=null && !(_preconDM.equals(""))){
    	    o.println(FileManager.BEGIN_PRECONDM);
    		o.println(_preconDM);
    	    o.println(FileManager.END_PRECONDM);
       		o.println();
   		}
    	if (_feedbackDM !=null && !(_feedbackDM.equals(""))){
    	    o.println(FileManager.BEGIN_FEEDBACKDM);
    		o.println(_feedbackDM);
    	    o.println(FileManager.END_FEEDBACKDM);
      		o.println();
    	}
    	if (warning !=null && !(warning.equals(""))){
    	    o.println(FileManager.BEGIN_WARNING);
    		o.println(warning);
    	    o.println(FileManager.END_WARNING);
       		o.println();
   		}
    	if (actor !=null && !(actor.equals(""))){
    	    o.println(FileManager.BEGIN_ACTOR);
    		o.println(actor);
    	    o.println(FileManager.END_ACTOR);
      		o.println();
    	}
    	if (other !=null && !(other.equals(""))){
    	    o.println(FileManager.BEGIN_OTHER);
    		o.println(other);
    	    o.println(FileManager.END_OTHER);
      		o.println();
  		}

    	o.println();
    }

    public void readASCII(BufferedReader i) {
    	String s;
    	try {
    	    name = i.readLine();
        }
        catch (Exception excep) {
        }
    	try {
    	    semantics = i.readLine();
       	    semantics = ""; //discard sematics infor from IMP files
 	    
        }
        catch (Exception excep) {
        }
 /*     try {
    	    dirty = false;
    	    s = i.readLine();
    	    if (s.equals("true")) dirty = true;
        }
        catch (Exception excep) {
        }
 */
    	try {
    	    feedback = i.readLine();
        }
        catch (Exception excep) {
        }
    	try {
    	    minCard = 0;
    	    s = i.readLine();
    	    if (!s.equals("")) minCard = Integer.parseInt(s);
        }
        catch (Exception excep) {
        }
    	try {
    	    maxCard = -1;
    	    s = i.readLine();
    	    if (!s.equals("")) maxCard = Integer.parseInt(s);
        }
        catch (Exception excep) {
        }
    	try {
    	    precondition = i.readLine();
        }
        catch (Exception excep) {
        }
    	try {
            postcondition = i.readLine();
        }
        catch (Exception excep) {
        }
    	try {
    	    mandatory = true;
    	    s = i.readLine();
    	    if (s.equals("Optional")) mandatory = false;
        }
        catch (Exception excep) {
        }
    	try {
/*    	    style=true;
    	    s=i.readLine();
    	    if (s.equals("Automatic")) style=false;
  */
  	        style=i.readLine();
/*    	    if (s.equals("Interactive")) 
    		style="Interactive";
    	    else if (s.equals("Automatic")) 
    		style="Automatic";
    	    else //if (style.equals("Mannual"))
    		style="Mannual"; 
*/
        }
        catch (Exception excep) {
        }
    	try {
    	    composite = false;
    	    s = i.readLine();
    	    if (s.equals("Composite")) composite = true;
        }
        catch (Exception excep) {
        }
    	try {
    	    terminal = false;
    	    s = i.readLine();
    	    if (s.equals("Yes")) terminal = true;
        }
        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 xt,double w,double h,double xpr,double gappr,double prw,double prh,double xpt,double gappt,double ptw,double pth){
    	Shape s;
  /*  	if (style) s=new RoundRectangle2D.Double(xt,prh+gappr,w,h,ARC_WIDTH_RATIO*u,ARC_HEIGHT_RATIO*u);
    	else s=new Rectangle2D.Double(xt,prh+gappr,w,h);
  */
      	if (style.equals(STYLE_VALUE[0])) 
    		s=new RoundRectangle2D.Double(xt,prh+gappr,w,h,ARC_WIDTH_RATIO*u,ARC_HEIGHT_RATIO*u);
    	else if (style.equals(STYLE_VALUE[1])) 
    		s=new Rectangle2D.Double(xt,prh+gappr,w,h);
    	else //if (style.equals("Mannual"))
    		s=new Ellipse2D.Double(xt,prh+gappr,w,h); 

    	Area a=new Area(s);
    	a.add(new Area(new Rectangle2D.Double(xpr,0,prw,prh)));
    	a.add(new Area(new Rectangle2D.Double(xpt,prh+h+gappr+gappt,ptw,pth)));
    	if (terminal) 
    		a.add(new Area(new Arc2D.Double(TERM_X0*w,prh+pth+gappr+gappt+TERM_Y0*h,TERM_SIZE*h,TERM_SIZE*h,0,360, Arc2D.OPEN)));
 
    	area=a;
    }

    private void setArea(double xt,double w,double h,double xp,double gap,double pw,double ph,boolean precond){
    	Shape s;
  /*  	
    	if (style) s=new RoundRectangle2D.Double(xt,(precond)?(gap+ph):0,w,h,ARC_WIDTH_RATIO*u,ARC_HEIGHT_RATIO*u);
    	else s=new Rectangle2D.Double(xt,(precond)?(gap+ph):0,w,h);
   */
    	if (style.equals(STYLE_VALUE[0])) 
    		s=new RoundRectangle2D.Double(xt,(precond)?(gap+ph):0,w,h,ARC_WIDTH_RATIO*u,ARC_HEIGHT_RATIO*u);
    	else if (style.equals(STYLE_VALUE[1])) 
    		s=new Rectangle2D.Double(xt,(precond)?(gap+ph):0,w,h);
    	else //if (style.equals("Mannual"))
    		s=new Ellipse2D.Double(xt,(precond)?(gap+ph):0,w,h);
   
   
    	Area a=new Area(s);
    	a.add(new Area(new Rectangle2D.Double(xp,(precond)?0:(gap+h),pw,ph)));
    	if (terminal) 
    		a.add(new Area(new Arc2D.Double(TERM_X0*w,gap+ph+TERM_Y0*h,TERM_SIZE*h,TERM_SIZE*h,0,360, Arc2D.OPEN)));
 
    	area=a;
    }

    private void setArea(double w,double h){
    	Shape s;
    	if (style.equals(STYLE_VALUE[0])) 
    		s=new RoundRectangle2D.Double(0,0,w,h,ARC_WIDTH_RATIO*u,ARC_HEIGHT_RATIO*u);
    	else if (style.equals(STYLE_VALUE[1])) 
    		s=new Rectangle2D.Double(0,0,w,h);
    	else //if (style.equals("Mannual"))
    		s=new Ellipse2D.Double(0,0,w,h);
   
 /*   	if (style) s= new RoundRectangle2D.Double(0,0,w,h,ARC_WIDTH_RATIO*u,ARC_HEIGHT_RATIO*u);
    	else s= new Rectangle2D.Double(0,0,w,h);
  */
    	Area a = new Area(s);
    	if (terminal) 
    	{
    		//a.add(new Area(new Line2D.Double(0,h+10,w/2,h/2)));
    		a.add(new Area(new Arc2D.Double(TERM_X0*w,TERM_Y0*h,TERM_SIZE*h,TERM_SIZE*h,0,360, Arc2D.OPEN)));
    		//a.add(new Area(new Rectangle2D.Double(0,h+10,w/2,h/2)));
                //System.out.println("draw terminal event");  Line2D.Double
         }
         area=a;
    }
    
       
    protected void drawComponent(Graphics2D g2) {        
    	//Thomas - html report
    	//System.out.println("before task drawComponent : width = "+w);

    	TextLayout layout = new TextLayout(name,new Font("Helvetica",Font.PLAIN,r(NAME_SIZE_RATIO*u)),new FontRenderContext(null,true,false)); //transform, antialiased, fractional metrics
    	double wl=layout.getBounds().getWidth()/u+2*NAME_MARGIN_RATIO;
    	if (wl>w0) w=wl;
    	else w=w0;
    	
    	//Thomas - html report
    	//System.out.println("after task drawComponent : width = "+w);

    	double wpr,wpt,hpr,hpt,xpr,xpt,xt,yt,ypr,ypt,temp;
    	TextLayout layoutPr=null;
    	TextLayout layoutPt=null;
    	
    	wpr=0;
    	wpt=0;
    	hpr=0;
    	hpt=0;
    	
    	
    	double wtotal=w;
    	double htotal=h;    
    	
     	double terminalY=h;    // for positioning terminal event
   		
    	
    	xt=0;
    	xpr=offpr;
    	xpt=offpt;
    	yt=0;
    	ypr=0;
    	ypt=h+gappt;
    	
    	boolean pre=!(precondition.equals(""));
    	//boolean post=!(postcondition.equals(""));
    	boolean feedB=!(feedback.equals(""));	//draw feedback instead of postcondition
    	
    	if (pre){
            layoutPr = new TextLayout((precondition.length()>MAX_LENGTH)?((new String(precondition)).substring(0,MAX_LENGTH)):(precondition),new Font("Helvetica",Font.PLAIN,r(CONDITION_SIZE_RATIO*u)),new FontRenderContext(null,true,false)); //transform, antialiased, fractional metrics
    	    wpr=layoutPr.getBounds().getWidth()/u+2*CONDITION_MARGIN_X_RATIO;
    	    hpr=layoutPr.getBounds().getHeight()/u+2*CONDITION_MARGIN_Y_RATIO;
    	    if (wpr<CONDITION_WIDTH_RATIO) wpr=CONDITION_WIDTH_RATIO;
    	    if (hpr<CONDITION_HEIGHT_RATIO) hpr=CONDITION_HEIGHT_RATIO;
    	    if (!feedB) {
    	        if (offpr<0) {
    	    	    //change the origin
    	            xpr=0;
    	            xt-=offpr;
    	        }    	        
    	        wtotal=Math.max(xt+w,xpr+wpr);
    	    }
    	    else {
    	        ypt+=hpr+gappr;    	    	
    	    }
    	    yt+=hpr+gappr;
    	    htotal+=hpr+gappr;
    	    
    	    terminalY = terminalY+hpr+gappr;
    	}
  /*  	
    	if (post){
            layoutPt = new TextLayout((postcondition.length()>MAX_LENGTH)?((new String(postcondition)).substring(0,MAX_LENGTH)):(postcondition),new Font("Helvetica",Font.PLAIN,r(CONDITION_SIZE_RATIO*u)),new FontRenderContext(null,true,false)); //transform, antialiased, fractional metrics
    	    wpt=layoutPt.getBounds().getWidth()/u+2*CONDITION_MARGIN_X_RATIO;
    	    hpt=layoutPt.getBounds().getHeight()/u+2*CONDITION_MARGIN_Y_RATIO;
    	    if (wpt<CONDITION_WIDTH_RATIO) wpt=CONDITION_WIDTH_RATIO;
    	    if (hpt<CONDITION_HEIGHT_RATIO) hpt=CONDITION_HEIGHT_RATIO;
    	    if (!pre){
    	    	if (offpt<0){
    	            xpt=0;
    	            xt-=offpt;
    	        }
    	        wtotal=Math.max(xt+w,xpt+wpt);
    	    }
            else {
    	        if ((offpt<offpr)&&(offpt<0)){
    	            xpt=0;
    	            xt-=offpt;
    	            xpr-=offpt;
    	        } else if ((offpr<=offpt)&&(offpr<0)){
    	            xpr=0;
    	            xt-=offpr;
    	            xpt-=offpr;
    	        }
    	        wtotal=Math.max(xt+w,Math.max(xpr+wpr,xpt+wpt));
    	    }
    	    htotal+=hpt+gappt;
    	}
    	
    	setSize(r(wtotal*u)+1,r(htotal*u)+1);
    	

    	if ((!pre)&&(!post)) setArea(w*u,h*u);
    	else if (pre&&(!post)) setArea(xt*u,w*u,h*u,xpr*u,gappr*u,wpr*u,hpr*u,true);
    	else if (post&&(!pre)) setArea(xt*u,w*u,h*u,xpt*u,gappt*u,wpt*u,hpt*u,false);
    	else if (pre&&post) setArea(xt*u,w*u,h*u,xpr*u,gappr*u,wpr*u,hpr*u,xpt*u,gappt*u,wpt*u,hpt*u);
    	    	
   */
   
        //draw feedback instead of postcondition
    	if (feedB) {
            layoutPt = new TextLayout((feedback.length()>MAX_LENGTH)?((new String(feedback)).substring(0,MAX_LENGTH)):(feedback),new Font("Helvetica",Font.PLAIN,r(CONDITION_SIZE_RATIO*u)),new FontRenderContext(null,true,false)); //transform, antialiased, fractional metrics
    	    wpt=layoutPt.getBounds().getWidth()/u+2*CONDITION_MARGIN_X_RATIO;
    	    hpt=layoutPt.getBounds().getHeight()/u+2*CONDITION_MARGIN_Y_RATIO;
    	    if (wpt<CONDITION_WIDTH_RATIO) wpt=CONDITION_WIDTH_RATIO;
    	    if (hpt<CONDITION_HEIGHT_RATIO) hpt=CONDITION_HEIGHT_RATIO;
    	    if (!pre) {
    	    	if (offpt<0) {
    	            xpt=0;
    	            xt-=offpt;
    	        }
    	        wtotal=Math.max(xt+w,xpt+wpt);
    	    }
            else {
    	        if ((offpt<offpr)&&(offpt<0)) {
    	            xpt=0;
    	            xt-=offpt;
    	            xpr-=offpt;
    	        } else if ((offpr<=offpt)&&(offpr<0)) {
    	            xpr=0;
    	            xt-=offpr;
    	            xpt-=offpr;
    	        }
    	        wtotal=Math.max(xt+w,Math.max(xpr+wpr,xpt+wpt));
    	    }
    	    htotal+=hpt+gappt;
    //	    System.out.println("feed=hpt " + hpt);
    //	    System.out.println("feed=gappt" + gappt);
    
    	    terminalY = terminalY+hpt+gappt;
    	}
    	
    	if (terminal) htotal=htotal+1.25;//10;
   
    	setSize(r(wtotal*u)+1,r(htotal*u)+1);
    	
    	if ((!pre)&&(!feedB)) setArea(w*u,h*u);
    	else if (pre&&(!feedB)) setArea(xt*u,w*u,h*u,xpr*u,gappr*u,wpr*u,hpr*u,true);
    	else if (feedB&&(!pre)) setArea(xt*u,w*u,h*u,xpt*u,gappt*u,wpt*u,hpt*u,false);
    	else if (pre&&feedB) setArea(xt*u,w*u,h*u,xpr*u,gappr*u,wpr*u,hpr*u,xpt*u,gappt*u,wpt*u,hpt*u);
    	
    	double wc=w-w0*COMPOSITE_WIDTH_RATIO;
    	double hc=h-w0*COMPOSITE_HEIGHT_RATIO; 

    	if (style.equals(STYLE_VALUE[0])) 
    		compositeShape=new RoundRectangle2D.Double(xt*u,yt*u,wc*u,hc*u,ARC_WIDTH_RATIO*u,ARC_HEIGHT_RATIO*u);
    	else if (style.equals(STYLE_VALUE[1])) 
    		compositeShape=new Rectangle2D.Double(xt*u,yt*u,wc*u,hc*u);
    	else
    		compositeShape=new Ellipse2D.Double(xt*u,yt*u,wc*u,hc*u);

        //System.out.println("  Task = "+name+" ID = "+ID+" isSelected = "+isSelected());

        // display selected or unselected colour
        if (isShiftSelected()) g2.setColor(BottomUp.BACKGROUND_SHIFT_SELECTED_COLOR);
        else if (isSelected()) g2.setColor(BACKGROUND_SELECTED_COLOR);
        else g2.setColor(BACKGROUND_COLOR);
        
 	    if (mandatory) g2.setStroke(new BasicStroke(STROKE_SIZE,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER, 2.0f));
 	    else {
 	        float dash[] = {5.0f,5.0f};
            BasicStroke bs = new BasicStroke(STROKE_SIZE,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER, 2.0f, dash, 0.0f);
            g2.setStroke(bs);
        }
        
        //  terminal
        //  draw the attached line between the task and the circle
    	if (terminal) {
    		//g2.setStroke(new BasicStroke(STROKE_SIZE,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER, 2.0f));
    	    Double xD1 = new Double(w/2*u);
    	    Double yD1 = new Double(terminalY/2*u);
    	    Double xD2 = new Double((TERM_X0*w+TERM_SIZE*h/2)*u);
    	    Double yD2 = new Double((terminalY+(TERM_Y0-1)*h+TERM_SIZE/2*h)*u);
    	    int x1 = xD1.intValue();
    	    int y1 = yD1.intValue();
    	    int x2 = xD2.intValue();
    	    int y2 = yD2.intValue();
            g2.drawLine(x1, y1,x2,y2);
        }
        
        g2.fill(area);
        g2.setColor(BORDER_COLOR);
        g2.draw(area);
        if (isComposite()) {
            g2.draw(compositeShape);
        }
        
        //Name of the task
        g2.setColor(FOREGROUND_COLOR);
        AffineTransform textAt = new AffineTransform();
        textAt.translate(xt*u+(w*u-layout.getBounds().getWidth())/2,(yt+NAME_MARGIN_RATIO)*u);
        Shape text=layout.getOutline(textAt);
        g2.fill(text);
        
        //precondition
    	if (pre) {
            textAt = new AffineTransform();
            textAt.translate((xpr+wpr/2)*u-layoutPr.getBounds().getWidth()/2,(ypr+hpr/2+CONDITION_NAME_OFFSET)*u+layoutPr.getAscent()/2);
            text=layoutPr.getOutline(textAt);
            g2.fill(text);
        }
   /*     
        //postcondition
    	if (post){
            textAt = new AffineTransform();
            textAt.translate((xpt+wpt/2)*u-layoutPt.getBounds().getWidth()/2,(ypt+hpt/2+CONDITION_NAME_OFFSET)*u+layoutPt.getAscent()/2);
            text=layoutPt.getOutline(textAt);
            g2.fill(text);
        }
 */       
        // feedbacks  terminal
    	if (feedB) {
    		textAt = new AffineTransform();
            textAt.translate((xpt+wpt/2)*u-layoutPt.getBounds().getWidth()/2,(ypt+hpt/2+CONDITION_NAME_OFFSET)*u+layoutPt.getAscent()/2);
            text=layoutPt.getOutline(textAt);
            g2.fill(text);
        }
                   
        //  terminal
        //  draw a arrow inside the circle
    	if (terminal) {
    		//g2.setStroke(new BasicStroke(STROKE_SIZE,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER, 2.0f));
    	    double deltaX= TERM_SIZE/2*h*Math.cos(2* Math.PI*45/360);
    	    double deltaY= TERM_SIZE/2*h*Math.sin(2* Math.PI*45/360);
    	    Double xD1 = new Double((TERM_X0*w+TERM_SIZE/2*h -deltaX )*u);
    	    Double yD1 = new Double((terminalY+(TERM_Y0-1)*h+TERM_SIZE/2*h+deltaY )*u);
    	    Double xD2 = new Double((TERM_X0*w+TERM_SIZE/2*h +deltaX)*u);
    	    Double yD2 = new Double((terminalY+(TERM_Y0-1)*h+TERM_SIZE/2*h - deltaY)*u);

    	    int x1 = xD1.intValue();
    	    int y1 = yD1.intValue();
    	    int x2 = xD2.intValue();
    	    int y2 = yD2.intValue();
            g2.drawLine(x1, y1,x2,y2);
            
            Double arrowLengthD = new Double(TERM_ARROW*h*u);
            int arrowLength = arrowLengthD.intValue();          
            int [] xpoints={x2-arrowLength,x2,x2};
            int [] ypoints={y2,y2,y2+arrowLength};
    	    Polygon p=new Polygon(xpoints,ypoints,3);
    	    g2.fill(p);
        }

        //Interval
        String s=getIntervalString();
        if (s!=null) {
            layout = new TextLayout(s,new Font("Helvetica",Font.PLAIN,r(INTERVAL_SIZE_RATIO*u)),new FontRenderContext(null,true,false)); //transform, antialiased, fractional metrics
            textAt = new AffineTransform();
            textAt.translate((xt+w-2*(w-wc))*u-layout.getBounds().getWidth(),(yt+h-2*(h-hc))*u);
            text=layout.getOutline(textAt);
            g2.fill(text);
        }
    }
        
    private String getIntervalString(){
    	String result=null;
    	int minC=(minCard>=0)?minCard:0;
    	if (maxCard>=minC)
    	    result=minC+"-"+maxCard;
    	else if ((maxCard<0)&&(minC>0))
    	    result=minC+"-";//+INFINITE;
    	return result;
    }

    public static ImageIcon getReductedIcon(int w,int h,double f,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,r(w*(1-f)),r(h*(1-f)),b);
    	return new ImageIcon(image);  	
    }
    
    public static ImageIcon getIcon(int w,int h,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,b);
    	return new ImageIcon(image);  	
    }
    protected static void drawIcon(Graphics2D g2,int w,int h,boolean b){
    	g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
    	//g2.setColor((b)?BACKGROUND_ICON_COLOR:(BACKGROUND_ICON_COLOR).darker());
    	//Rectangle r=new Rectangle(0,0,w,h);
    	//g2.fill(r);
    	Rectangle r=new Rectangle(w/8,h/4,w-2*(w/8),h-2*(h/4));
    	g2.setColor((b)?BACKGROUND_COLOR:(BACKGROUND_COLOR).darker());
    	g2.fill(r);
    	g2.setColor((b)?BORDER_COLOR:(BORDER_COLOR).darker());
    	g2.draw(r);
    }
    
    public static Image getComponentCursor(int wi,int hi) {
        // buffer to store image data for cursor
    	//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 used to draw into this image buffer
    	Graphics2D g2 = image.createGraphics();
        
        // specify how new pixels are to be combined with the existing pixels : opaque
    	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 rectangle
    	double xcenter = ww * RATIO_FOR_ARROW_LINE;
    	double ycenter = hh * RATIO_FOR_ARROW_LINE;
    	int xc = r(xcenter);
    	int yc = r(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);
        
        // draw the rectangle for task shape
    	Rectangle r = new Rectangle(xc,yc,cursorWidth-xc,cursorHeight-yc);
    	g2.draw(r);
    }
    
    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(){
    	TextLayout layout = new TextLayout(name,new Font("Helvetica",Font.PLAIN,r(NAME_SIZE_RATIO*u)),new FontRenderContext(null,true,false)); //transform, antialiased, fractional metrics
    	double wl=layout.getBounds().getWidth()/u+2*NAME_MARGIN_RATIO;
    	if (wl>w0) return wl;
    	else return w0;
    }
    
 
	 //shijian 7-2-2001
	 //set text for semantics
	 public void setSemantics(String str){
	      semantics =str;	 	
	      setDirty(true);
	 }
	 //shijian 13-2-2001
	 //fet text for semantics
	 public String getSemantics(){
	      return semantics;
	 }
 
	 //shijian 13-2-2001
	 //set dirty
	 public void setDirty(boolean b){
	      	dirty =b;	 	
	 }
 
	 //shijian 13-2-2001
	 //get dirty
	 public boolean isDirty(){
	      	return dirty;	 	
	 }
  
	 //shijian 21-3-2001
	 //set ID for precondition
	 public void setPreconDM(String str){
	      _preconDM =str;	 	
	      if (!str.equals(""))
		  setDirty(true);
	 }
	 //shijian 13-2-2001
	 //fet ID for precondition
	 public String getPreconDM(){
	      return _preconDM;
	 } 
 
	 //shijian 21-3-2001
	 //set action instance ID for feedbacks
	 public void setFeedbackDM(String str){
	      _feedbackDM =str;	 	
	      if (!str.equals(""))
		  setDirty(true);
	 }
	 //shijian 21-3-2001
	 //get action instance ID for feedbacks
	 public String getFeedbackDM(){
	      return _feedbackDM;
	 }
 
	 //shijian 21-3-2001
	 //set action instance ID for feedbacks
	 public void setWarning(String str) {
	      warning = str;
	      if (!str.equals(""))
		  setDirty(true);
          
          //TMUtility.display("warning: " + warning);
	 }
	 //shijian 21-3-2001
	 //get action instance ID for feedbacks
	 public String getWarning(){
	      return warning;
	 }
 
	 //shijian 21-3-2001
	 //set text for label
	 public void setOther(String str){
	      other =str;	 	
          //TMUtility.display("other: " + other);
	 }
	 //shijian 21-3-2001
	 //get text for label
	 public String getOther(){
	      return other;
	 }
 
	 //shijian 21-3-2001
	 //set text for actor
	public void setActor(String str){
		actor =str;
		setSemantics("");

	}
	 //shijian 21-3-2001
	 //get text for actor
	 public String getActor(){
	      return actor;
	 }
 
	 //shijian 13-2-2001
	 //construct semantics from task name
	 public String getDefaultSemantics(){
	 	 String seman= "";
	 	 
	 	 //shijian 	30-10-2001
	 	 //if there is "actor" in the begining of task name
	 	 //then don't add "actor" again
	 	 String actorTemp="";
		 if (style.equals("Automatic"))
			actorTemp = EntityInstance.getDefaultSystemInstance().getName();
		 else
			actorTemp = EntityInstance.getDefaultUserInstance().getName();
			
 	 	 if (actor != null ){
	 	 	String st = actor.trim();
	 	 	if (st.length() > 0){
		 	 	actorTemp = st;
	 	 	}
	 	 }
	 	 //check task name
	 	 String taskName=getName().trim();
	 	 if (taskName.startsWith(actorTemp))
		 	 	seman = taskName;
	 	 else
		 	 	seman = actorTemp + " " + taskName;
	 	 
	 	 /*
	 	 if (actor != null ){
	 	 	String st = actor.trim();
	 	 	if (st.length() > 0){
		 	 	seman = actor + " " + getName();
		 	 	return seman;
	 	 	}
	 	 }
		 // grab task name and add actor based on task type
	    // and pass that to the parser
		
		//brasser 2001-6-21
		//commented out section that adds "user" or "system" to the front of the semantics.
		//added seman = getName()
		if (style.equals("Automatic"))
			seman = EntityInstance.getDefaultSystemInstance().getName()
				+" "+getName();
		else
			seman = EntityInstance.getDefaultUserInstance().getName()+
				" "+getName();
		
		*/
	
		
	    return seman;
	 }
	 
	 //shijian 26-3-2001
	 //get precondition
	 public String getPrecon(){
	      return precondition;
	 } 
	 
	 //shijian 26-3-2001
	 //get feedback
	 public String getFeedback(){
	      return feedback;
	 }
	 
	 //shijian 26-3-2001
	 //get precondition
	 public void setPrecon(String st){
	    precondition = st;  
	    setPreconDM("");
	 	return ;
	 } 
	 
	 //shijian 26-3-2001
	 //get feedback
	 public void setFeedback(String st){
	 	feedback= st;
		setFeedbackDM("");
    	return ;
	 }
	 
	 //shijian 9-5-2001
	 //set style
	 public void setStyle(String st){
	 	style= st;
    	return ;
	 }
 
	 //shijian 22-11-2001
	 public boolean isAutomatic(){
     	return (style.equals(STYLE_VALUE[1]))? true: false;
	 }
}
