import lotus.domino.*;
import java.io.*;
import javax.swing.*;
import javax.imageio.ImageIO;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;

public class JavaAgent extends AgentBase {

	public void NotesMain() {

		// ======================================================================
		//
		// Important note ... the image resize function in this sample code was
	    	// taken from this page:
		// http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html
		// and then modified a bit to make it simply care about the width of the
		// image and not the height.
		//		
		// ======================================================================
		
		// ======================================================================
		//
		// Author: 			Marc Champoux
		// Web Site:		http://www.thenewdominoadmin.com
		// Creation Date:	April 18th 2010
		// 
		// Description:		This java agent allows an employee to select a jpg
		//					file from his computer (or a network share) and the
		//					code below will resize the picture and then import
		//					it into the "jpegPhoto" of the person document
		//					in the Domino Directory.
		//
		// Sample Usage:	(a) Employee opens the Domino Directory.
		//					(b) Employee finds and select his open person doc.
		//					(c) Employee clicks on "Actions -> Import Picture".
		//					(d) Employee select "Me.jpg" from his C:\ drive.
		//					(e) Code creates a "Me-resized.jpg" on the C:\ drive.
		//					(f) Code reads and import the "Me-resized.jpg" into
		//					    the "jpegPhoto" field of the person doc.
		//					(g) Others will then be able to see the picture of
		//					    the employee within the next few minutes or
		//					    hours in their Sametime Business Card.
		//
		// ======================================================================
		
		
		try {
          Session session = getSession();							// The session.
          AgentContext agentContext = session.getAgentContext();	// The agentContent object to get the documents.
          String docFormUsed;										// The form of the document selected.
          final JFileChooser fc = new JFileChooser();				// A file chooser prompt.
          int fcReturnVal;											// The return value of the file chooser prompt.
          String fileNameSelected;									// The name of the file selected.
          String fileNameResized;									// The name of the file once we have resized it.

          // Start by getting a hold on the list of selected documents.
          DocumentCollection dc = agentContext.getUnprocessedDocuments();
          
          // Check if we have at least 1 document selected ...
          if ( dc.getCount() == 1 ) {

        	  // Get the 1st document ...
        	  Document doc = dc.getFirstDocument();
        	  
        	  // Get the value of the form used ...
        	  docFormUsed = doc.getItemValueString( "Form" );
        	  
        	  // Make sure it's a person document form ...
        	  if ( docFormUsed.toLowerCase().equals( "person") ) {
        		  
        		  // Prompt for the jpg file ...
        		  fc.setDialogTitle("Select a *JPG* file to open"); 
                  fcReturnVal = fc.showOpenDialog(null);

                  // Check if the employee clicked on "OK".
                  if (fcReturnVal == JFileChooser.APPROVE_OPTION) {
                	  
                	  // Get the file that was selected ...
                      File file = fc.getSelectedFile();
                      fileNameSelected = file.getAbsolutePath();
                      
                      // Make sure it's a jpg ...
                      if ( fileNameSelected.toLowerCase().lastIndexOf(".jpg") >0 ){
                    	  
                    	  // Let me or us know what is the selected file ...
                    	  System.out.println( "Selected file is called: " + fileNameSelected );
                    	  
                    	  // Set the file name of the resized image ...
                    	  fileNameResized = fileNameSelected.substring(0, fileNameSelected.toLowerCase().lastIndexOf(".jpg")) + "-resized.jpg";

                    	  // Let me or us know what is the renamed file ...
                    	  System.out.println( "Renamed file will be called: " + fileNameResized );

                    	  // The fun begings so let's put a try-catch block ...
                    	  try {
                    		  
                    		  	// Start by reading the image and put it in a Buffered Image
                  				BufferedImage image = ImageIO.read(new File(fileNameSelected));
                  				
                  				// Now call the getScaledInstance method that we plundered and tweaked from the Java.net site
                  				BufferedImage resizedImage = getScaledInstance(image,100,RenderingHints.VALUE_INTERPOLATION_BILINEAR,true);
                  				
                  				// Finally write the image on the hard drive (hopefully, it's a hard-drive and not a network 
                  				// share that the person only had read access to.
                  				if ( ImageIO.write(resizedImage, "jpg", new File (fileNameResized)) ) {
                  					
                  					// Create a new inputStream to read the new image file
                  					File newImageFile = new File (fileNameResized);
                  					InputStream newImage = new FileInputStream(newImageFile);
                  					
                  					// Get the size of the newly resized image
                  			        long newImageLength = newImageFile.length();
                  					
                  			        // Make sure that the file is smaller than 20k ...
                  			        if ( newImageLength <= 20000 ) {
                  			        	
                  			        	//Create the byte array to hold the data from the image ...
                  			        	byte[] newImageBytesArray = new byte[(int)newImageLength];
                  			      
                  			        	// Read in the bytes into 1 large array.
                  			        	int offset = 0; 
                  			        	int numRead = 0; 
                  			        	while (offset < newImageBytesArray.length && (numRead=newImage.read(newImageBytesArray, offset, newImageBytesArray.length-offset)) >= 0) {
                  			        		offset += numRead;
                  			        	} 
                  			        	
                  			        	// Ensure all the bytes have been read in 
                  			        	if (offset < newImageBytesArray.length) {
                  			        		
                  			        		// Oups something went really wrong somewhere ...
                  			        		JOptionPane.showMessageDialog(null,"Sorry but an unexpected error occured when reading the resized picture. Please contact your system administrator. A detail of the error can be found in the Java Console.","An Unexpected Error Occured",JOptionPane.ERROR_MESSAGE);
                  			        		throw new IOException("Error - Could not completely read file " + newImageFile.getName());
                  			        		
                  			        	} else {
                  			        		
                  			        		// Ok, here we go ... the moment of truth ... time to call that special replaceitemvalue
                  			        		// method that I had never used before ... until I needed pictures in Sametime Business
                  			        		// cards ...
                  			        		doc.replaceItemValueCustomDataBytes ( "jpegPhoto", "jpegPhoto", newImageBytesArray);
                  			        		
                  			        		// Save the document ...
                  			        		doc.save();
                  			        		
                  			        		// Print something ...
                  			        		JOptionPane.showMessageDialog(null,"Your picture has been resized and uploaded successfully. Your Sametime Business Card picture should appear within a few minutes.","Success!",JOptionPane.INFORMATION_MESSAGE);
                  			        		System.out.println ("Image resized and imported succesfully");
                  			        	}
                  			        	
                  			        } else {
                  			        	
                      					// Oups, the file is too large ...
                  			        	JOptionPane.showMessageDialog(null,"The resized file is larger than 20 000 bytes. Please re-try with a different JPG file or resize it prior to using this tool.","Error - Resized Image is Too Large",JOptionPane.ERROR_MESSAGE);
                      					System.out.println("The resized file is larger than 20 000 bytes. Please investigate why this happened." );
                      					
                  			        }
                  			        
                  			        // Close the file we've just read ...  
                  			        newImage.close();
                  			        
                  				} else {
                  					// Oups, something went wrong and we can't write ...
                  					JOptionPane.showMessageDialog(null,"You did not select a file with a \"JPG\" file extension.","Error - Wrong File Extension",JOptionPane.ERROR_MESSAGE);
                  					System.out.println("The agent is unable to write the re-sized image to the hdd." );
                  				}
                  				
                  				// Now, re-open the resized file.Check the file size 
                                        
                    	  } catch (IOException e) {
                    		  JOptionPane.showMessageDialog(null,"Sorry but an unexpected error occured. Please contact your system administrator. A detail of the error can be found in the Java Console.","An Unexpected Error Occured",JOptionPane.ERROR_MESSAGE);
                    		  e.printStackTrace();
                    	  }
                 	  
                      } else {
                    	  JOptionPane.showMessageDialog(null,"You did not select a file with a \"JPG\" file extension.","Error - Wrong File Extension",JOptionPane.ERROR_MESSAGE);
                    	  System.out.println("Employee did not select a jpg file." );
                      }
                  } else {
                	  System.out.println("Open command cancelled." );
                  }
        	  } else {
            	  JOptionPane.showMessageDialog(null,"Sorry but you did not select a person document. Please re-try.","Error - Wrong Document Type Selected",JOptionPane.ERROR_MESSAGE);        		  
            	  System.out.println("Employee had not selected a person document.");
        	  }
        	  
        	  // Recycle the document
        	  doc.recycle();        	  
          } else {
        	  JOptionPane.showMessageDialog(null,"Sorry but you have selected more than 1 document. Please verify your selection and re-try.","Error - More than 1 Document Selected",JOptionPane.ERROR_MESSAGE);
        	  System.out.println("Employee had selected more than 1 documemt.");  
          }
          
          // Recycle the document collection
          dc.recycle();

      } catch(Exception e) {
          e.printStackTrace();
       }
   }
    
	/**
    * Convenience method that returns a scaled instance of the
    * provided {@code BufferedImage}.
    *
    * @param img the original image to be scaled
    * @param targetWidth the desired width of the scaled instance,
    *    in pixels
    * @param targetHeight the desired height of the scaled instance,
    *    in pixels
    * @param hint one of the rendering hints that corresponds to
    *    {@code RenderingHints.KEY_INTERPOLATION} (e.g.
    *    {@code RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR},
    *    {@code RenderingHints.VALUE_INTERPOLATION_BILINEAR},
    *    {@code RenderingHints.VALUE_INTERPOLATION_BICUBIC})
    * @param higherQuality if true, this method will use a multi-step
    *    scaling technique that provides higher quality than the usual
    *    one-step technique (only useful in downscaling cases, where
    *    {@code targetWidth} or {@code targetHeight} is
    *    smaller than the original dimensions, and generally only when
    *    the {@code BILINEAR} hint is specified)
    * @return a scaled version of the original {@code BufferedImage}
    */
   public BufferedImage getScaledInstance(BufferedImage img,
                                          int targetWidth,                                          
                                          Object hint,
                                          boolean higherQuality)
   {
       int type = (img.getTransparency() == Transparency.OPAQUE) ?
           BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
       BufferedImage ret = (BufferedImage)img;
       int w, h;
       double widthToHeightRatio;
       
       //Get the picture width to height ratio ... it will come in handy
       // when we reach the point where the current picture size is close
       // to the target width
       widthToHeightRatio = (double) img.getHeight() / img.getWidth();
       System.out.println( "The aspect ratio of the picture is " + widthToHeightRatio );       
       
       // Check if the user has requested a higher quality resize
       if (higherQuality) {
           // Use multi-step technique: start with original size, then
           // scale down in multiple passes with drawImage()
           // until the target size is reached
           w = img.getWidth();
           h = img.getHeight();
       } else {
           // Use one-step technique: scale directly from original
           // size to target size with a single drawImage() call
           // but since we want to preserve the aspect ratio, let's do
    	   // a bit of math to make sure that the picture height is
    	   // decent once the resize is done
    	   w = targetWidth;
    	   h = (int)((double) targetWidth * widthToHeightRatio);
       }
      
       do {
    	   
    	   // In case of higher quality, check if the width is higher than the targetWidth
    	   if (higherQuality && w > targetWidth) {
    		   // Divide the target width and height by 2 right away ...
    		   w /= 2;
    		   h /= 2;
    		   // Check if we are below the targetWidth
    		   if (w < targetWidth) {
    			   // We are ... so set w to the target width and re-calculate the height to the correct ratio
    			   w = targetWidth;
    			   h = (int)((double)targetWidth * widthToHeightRatio);
    		   } 
    	   }
    	             
    	   // Ok, now do all the crazy stuff to resize the image ...
           BufferedImage tmp = new BufferedImage(w, h, type);
           Graphics2D g2 = tmp.createGraphics();
           g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
           g2.drawImage(ret, 0, 0, w, h, null);
           g2.dispose();
           ret = tmp;
           
       } while (w > targetWidth );

       // Return the resized image ...
       return ret;
   }
   
}
