/*
 *
 *  Copyright (C) 1999, Institute for MicroTherapy
 *
 *  This software and supporting documentation were developed by
 *
 *    University of Witten/Herdecke
 *    Department of Radiology and MicroTherapy
 *    Institute for MicroTherapy
 *    Medical computer science
 *    
 *    Universitaetsstrasse 142
 *    44799 Bochum, Germany
 *    
 *    http://www.microtherapy.de/go/cs
 *    mailto:computer.science@microtherapy.de
 *
 *  THIS SOFTWARE IS MADE AVAILABLE,  AS IS,  AND THE INSTITUTE MAKES  NO 
 *  WARRANTY REGARDING THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY
 *  OR FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES 
 *  OR ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY 
 *  AND PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
 *
 *  Author :      $Author: kleber $
 *  Last update : $Date: 2001/06/06 10:32:30 $
 *  Revision :    $Revision: 1.1.1.1 $
 *  State:        $State: Exp $
*/

package viewer.presentation;

import J2Ci.*;

import java.util.*;
import java.awt.*;
import java.awt.geom.*;

import main.*;

/**
 * This class manages the shutters of a presentation state. The data of the shutters are 
 * capsulated in a jDVPresentationState object. This class makes methods available for drawing the 
 * for handling shutters in a graphic context .       
 * 
 * @author Klaus Kleber
 * @since 30.04.1999
 */
public class ShutterList
{
    /**
     * Contains the current presentation state with the shutter data.
     * 
     * @since 30.04.1999
     */
    private jDVPresentationState ps;
    
    /**
     * Contains all active vector shutters.
     * 
     * @since 30.04.1999
     */
    private Area shutterArea;
    
    /**
     * Contains the index of every overlay which is suitable 
     * for use as a bitmap shutter.
     * 
     * @since 30.04.1999
     */ 
    private int overlayIsShutterIndexList[];
    
    /**
     * Contains the labels of every overlay which is suitable 
     * for use as a bitmap shutter. The index of the label is the 
     * same as the index in the overlayIsShutterIndexList.
     * 
     * @since 30.04.1999
     */
    public String overlayIsShutterLabelList[];
    
    /**
     * Contains the number of suitable bitmap shutters.
     * 
     * @since 30.04.1999
     */
    public int numberOfSuitableBitmapShutter = 0;
    
    /**
     * Specifies the index of the current active bitmap shutter in 
     * the overlayIsShutterIndexList.
     * If no bitmap shutter is active the value is -1.
     * 
     * @since 30.04.1999
     */
    public int activeBitmapShutterIndex;
    
    /**
     * Constructs the ShutterList form the specified jDVPresentationState object.
     * 
     * @param ps Contains the current jDVPresentationState object with the shutter data.
     * @since 30.04.1999
     */
    public ShutterList (jDVPresentationState ps)
    {
        this.ps = ps;
        
        //Builds the index an the label List for the bitmap shutter.
        
        overlayIsShutterIndexList = new int[16];
        overlayIsShutterLabelList = new String[16];
        activeBitmapShutterIndex = -1;
        numberOfSuitableBitmapShutter = 0;
        
        for (int i = 0; i<ps.getNumberOfOverlaysInPresentationState(); i++)
        {
            if (ps.overlayIsSuitableAsBitmapShutter(i))
            {
                overlayIsShutterIndexList[numberOfSuitableBitmapShutter] = i;
                overlayIsShutterLabelList[numberOfSuitableBitmapShutter] = ps.getOverlayInPresentationStateLabel(i);
                if (overlayIsShutterLabelList[numberOfSuitableBitmapShutter] == null) overlayIsShutterLabelList[numberOfSuitableBitmapShutter] = new String("Overlay " + i);
                if (ps.overlayIsBitmapShutter(i))activeBitmapShutterIndex = numberOfSuitableBitmapShutter;
                numberOfSuitableBitmapShutter++;
            }
        }
        
        //Constructs the shape of the vector shutter
        buildShape();
    }
    
    /**
    * Deactivates the current bitmap shutter if exist.
    *
    * @since 30.04.1999
    */
    private void decativateBitmapShutter()
    {
        
        
        activeBitmapShutterIndex = -1;
        shutterArea = new Area();
        ps.removeShutter(jDVPSShutterType.DVPSU_bitmap);
        
    }
    
    /**
     * Activates the bitmap shutter with the specified index in the overlayIsShutterIndexList.
     * 
     * @param index Specifies the index of the new bitmap shutter in the overlayIsShutterIndexList.
     * If index = -1 then the current shutter will be deactivate.
     * @since 30.04.1999
     */
    public void activateBitmapShutter(int index)
    {
        shutterArea = new Area();
        if (index != -1)ps.activateOverlayAsBitmapShutter(index);
        else decativateBitmapShutter();
        activeBitmapShutterIndex = index;
    }

    /**
     * Sets and activates a polygonal display shutter.
     * If a bitmap shutter is exists, it is deactivated     
     *
     * @param thePoints Contains the points of the polyline shutter. 
     * @param numberOfPoints Number of points of the polyline shutter
     * @since 30.04.1999
     */
    public void addPolygonalShutter(float[] thePoints,int numberOfPoints)
    {
        decativateBitmapShutter();
        
        if (numberOfPoints > 0) 
        {
          int status =   ps.setPolyShutterOrigin((int)thePoints[0],(int)thePoints[1]);
        }
        for (int i = 1; i < numberOfPoints;i++) 
        {
            int status =  ps.addPolyShutterVertex((int)thePoints[2*i],(int)thePoints[2*i+1]);
        }
        buildShape();
    }

    /**
     * Sets and activates rectangular display shutter.
     * If a bitmap shutter is exists, it is deactivated     
     *
     * @param lv the left vertical edge
     * @param rv the right vertical edge
     * @param uh the upper horizontal edge
     * @param lh the lower horizontal edge
     * @since 30.04.1999
     */
    public void addRectangularShutter(int lv, int rv, int uh, int lh)
    {
        decativateBitmapShutter();
       
        //
        ps.setRectShutter(lv, rv-2, uh, lh-2);
        buildShape();
        
    }

    /**
     * Sets and activates circular display shutter.
     * If a bitmap shutter is exists, it is deactivated 
     *
     * @param circX the X component of the shutter center
     * @param circY the Y component of the shutter center
     * @param radius the (horizontal) radius of the shutter
     * @since 30.04.1999
     */
    public void addCircularShutter(int circX, int circY, int radius)
    {
        decativateBitmapShutter();
        
        ps.setCircularShutter(circX, circY, radius-1);
        buildShape();
        
    }

    /**
     * Deletes a polygonal shutter if exist.
     *
     * @since 30.04.1999
     */
    public void deletePolygonal()
    {
        delete(jDVPSShutterType.DVPSU_polygonal);
    }

    /**
     * Deletes a circular shutter if exist.
     *
     * @since 30.04.1999
     */
    public void deleteCircular()
    {
        delete(jDVPSShutterType.DVPSU_circular);
    }

    /**
     * Deletes a rectangular shutter if exist.
     *
     * @since 30.04.1999
     */
    public void deleteRectangular()
    {
        delete(jDVPSShutterType.DVPSU_rectangular);
    }

    /** 
     * Deactivates display shutter of given type.
     *
     * @param shutterValue the shutter type (from jDVPSShutterType).
     * @since 30.04.1999
     */
    
    public void delete(int shutterValue)
    {
        if (ps.haveShutter(shutterValue)) 
        {
            ps.removeShutter(shutterValue);
        }
        
        buildShape();
    }

    /**
     * Checks if a rectangular shutter of given type is active.
     *
     * @return true if this type of shutter is currently active.
     * @since 30.04.1999
     */
    public boolean haveRectangularShutter()
    {
        return ps.haveShutter(jDVPSShutterType.DVPSU_rectangular);
    }

    /**
     * Checks if a circular shutter of given type is active.
     *
     * @return true if this type of shutter is currently active.
     * @since 30.04.1999
     */
    public boolean haveCircularShutter()
    {
        return ps.haveShutter(jDVPSShutterType.DVPSU_circular);
    }

    /**
     * Checks if a polygonal shutter of given type is active.
     *
     * @return true if this type of shutter is currently active.
     * @since 30.04.1999
     */
    public boolean havePolygonalShutter()
    {
        return ps.haveShutter(jDVPSShutterType.DVPSU_polygonal);
    }

    /**
     * Checks if a bitmapped shutter of given type is active.
     *
     * @return true if this type of shutter is currently active.
     * @since 30.04.1999
     */
    public boolean haveBitmapShutter()
    {
        return ps.haveShutter(jDVPSShutterType.DVPSU_bitmap);
    }

    public boolean haveGeomShutter()
    {
        if (haveCircularShutter()) return true;
        if (havePolygonalShutter()) return true;
        if (haveRectangularShutter()) return true;
        return false;
    }
    /**
     * Builds the shutterArea which is a combined Area of the vector shutters.
     *
     * @since 30.04.1999
     */
    public void  buildShape()
    {
        //Constructs an new Area
        shutterArea =new Area();
        
        if (haveRectangularShutter())
        {
            Rectangle2D.Double rect = new Rectangle2D.Double(   (ps.getRectShutterLV()),
                                                                (ps.getRectShutterUH()),
                                                                (ps.getRectShutterRV()-ps.getRectShutterLV()+1),
                                                                (ps.getRectShutterLH()-ps.getRectShutterUH()+1));
            if (shutterArea.isEmpty()) shutterArea.add(new Area(rect));
            else shutterArea.intersect(new Area(rect));  
        }
        
        //Circle shutter
        if ( haveCircularShutter())
        {
            Ellipse2D.Double ellipse = new Ellipse2D.Double(    (ps.getCenterOfCircularShutter_x()-ps.getRadiusOfCircularShutter()),
                                                                (ps.getCenterOfCircularShutter_y()-ps.getRadiusOfCircularShutter()),
                                                                2*(ps.getRadiusOfCircularShutter()),
                                                                2*(ps.getRadiusOfCircularShutter()));
          
          if (shutterArea.isEmpty()) shutterArea.add(new Area(ellipse));
          else 
          {
            shutterArea.intersect(new Area(ellipse));  
          }
        }
        //Polygonal shutter
        if (havePolygonalShutter())
        {
            
            GeneralPath generalPath = new GeneralPath();
            if (ps.getNumberOfPolyShutterVertices() > 1)
            {
                
                Point point = new Point();
                ps.getPolyShutterVertex(0, point);
                //System.out.println("Point: " + point.toString());
                generalPath.moveTo((float)(point.getX()), (float) (point.getY()));
                
                for (int i = 1; i<ps.getNumberOfPolyShutterVertices(); i++)
                {
                    ps.getPolyShutterVertex(i, point);
                    //System.out.println("Point: " + point.toString());
                    generalPath.lineTo((float)(point.getX()), (float) (point.getY()));
                    
                }
                if (shutterArea.isEmpty()) shutterArea.add(new Area(generalPath));
                else shutterArea.intersect(new Area(generalPath));  
                
            }
            
        }
    }
    
    /**
     * Clips the specified Graphics2D object with the shutterArea. The clipping area
     * will be transform with the specified AffineTransform object.
     * 
     * @param g2 Specifies the Graphics2D object which will be clipped.
     * @param aff Specifies the transformation which will be used.
     * @since 30.04.1999
     */
    public void setClip(Graphics2D g2, AffineTransform aff)
    {
        g2.setTransform(aff);
        //Rectangle shutter
        if (!shutterArea.isEmpty())
        {
            
            g2.clip(shutterArea);
        }
    
    }
    public void drawShutter(Graphics2D g2, AffineTransform aff, int width , int height, int bits)
    {
        if (haveGeomShutter())
        {
            g2.setColor( GrayColorIndex.get12Color(ps.convertPValueToDDL(ps.getShutterPresentationValue(),bits) ));
            Area clipArea = new Area(new Rectangle2D.Float(0,0,width ,height));
            Area transShutterArea = shutterArea.createTransformedArea(aff);
            clipArea.subtract(transShutterArea);
            g2.draw(clipArea);
            g2.fill(clipArea);
        }
        
    }
    /**
     * Returns a byte with the gray color value of the shutter. This 
     * value is transformed form the shutter presentation value.
     *
     * return The gray color value of the shutter.
     * @since 30.04.1999
     */
    
    public byte getGreyColorByte()
    {
       return (byte)ps.convertPValueToDDL(ps.getShutterPresentationValue(),8);
    }

    /**
    * Returns a String representing this object.
    *
    * @return A String representing this object
    * @since 30.04.1999
    */
    public String getInfo()
    {
        
        String returnString;
        
        //fill attributes
        returnString = new String(  "    Shutter List" +  "\n"+"\n" +
                                    "        Color: " + ps.getShutterPresentationValue());
        if ( haveRectangularShutter())
        {
            returnString = returnString.concat("      Rectangle Shutter: " + "\n" +
                                               "         RectShutterLV: " +  ps.getRectShutterLV()+ "\n"+
                                               "         RectShutterUH: " +  ps.getRectShutterUH()+ "\n" +
                                               "         RectShutterLH: " +  ps.getRectShutterLH() +"\n" +
                                               "         RectShutterRV: " +  ps.getRectShutterRV()+ "\n");
        }
        if ( haveCircularShutter())
        {
            returnString = returnString.concat("      Circle Shutter: " + "\n" +
                                               "         CenterOfCircularShutter: x = " +  ps.getCenterOfCircularShutter_x()+" y= "+ ps.getCenterOfCircularShutter_y() +"\n"+
                                               "         RadiusOfCircularShutte: " +  ps.getRadiusOfCircularShutter()+ "\n" );
        }
        
        if ( havePolygonalShutter())
        {
            returnString = returnString.concat("      Polygonal Shutter: " + "\n" );
        //fill points
            Point point = new Point();
            for (int i = 0; i < ps.getNumberOfPolyShutterVertices(); i++)
            {
                ps.getPolyShutterVertex(i, point);
                returnString = returnString.concat("        Point " + i  + ": X = " + point.x + ", Y = " + point.y);
            }                     
        
        }
        if (haveBitmapShutter())
        {
            returnString = returnString.concat("      Bitmapped Shutter: " + "\n" );
        
        }
        return returnString;
    }

    /**
     * Deletes all objects.
     *
     * @since 30.04.1999
     */
    public void deleteAll()
    {
        ps = null;
        shutterArea = null;
    }

    /**
     * Gets the shutter presentation value. If no shutter display
     * value exists, a default of 0 (black) is set.
     * @return The shutter presentation value.
     *
     * @since 30.04.1999
     */
    public int getShutterPresentationValue()
    {
        return ps.getShutterPresentationValue();
    }

    /**
     * Converts the shutter presentation value in a value between 0 by 1 and returns this value.
     *
     * @return A value between 0 by 1 which is the transformed shutter presentation value.
     * @since 30.04.1999
     */
    public float getShutterColorValue()
    {
        float floatValue =(float)getShutterPresentationValue()/(float)0xffff;
        float newValue = (float)  Math.round(floatValue*1000d);  
        return newValue/1000f;
    }

    /**
     * Sets the shutter presentation value. The input is a value between 0 by 1. This value
     * will convert in a value between 0 and 0xffff.
     *
     * @param colorValue Contains the new color.
     * @since 30.04.1999
     */
    public void setShutterColor (float colorValue)
    {
        ps.setShutterPresentationValue((int)(colorValue*0xffff));
    }
}




/*
 *  CVS Log
 *  $Log: ShutterList.java,v $
 *  Revision 1.1.1.1  2001/06/06 10:32:30  kleber
 *  Init commit for DICOMscope 3.5
 *  Create new CVS
 *
*/
