package visual.statik.sampled;

import java.awt.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;

import io.ResourceFinder;


/**
 * A factory class for constructing/creating 
 * BufferedImage objects of type ARGB or RGB
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class ImageFactory
{
    private ResourceFinder    finder;
    
    private static final int  DEFAULT_CHANNELS = 3;
    

    /**
     * Default Constructor
     */
    public ImageFactory()
    {
       super();       
       finder = ResourceFinder.createInstance();       
    }
    
//[step0.
    /**
     * Create a BufferedImage from an Image
     *
     * @param image       The original Image
     * @param channels    3 for RGB; 4 for ARGB
     * @return            The BufferedImage
     */
    public BufferedImage createBufferedImage(Image image,
                                             int   channels)
    {
//]step0.
//[step1.
       int                 type;
       if (channels == 3) type = BufferedImage.TYPE_INT_RGB;
       else               type = BufferedImage.TYPE_INT_ARGB;
//]step1.
//[step2.
       BufferedImage       bi;
       bi = null;
       bi = new BufferedImage(image.getWidth(null), 
                              image.getHeight(null),
                              type);
//]step2.
//[step3.
       Graphics2D          g2;
       g2 = bi.createGraphics();
       g2.drawImage(image, null, null);
//]step3.
//[step4.
       return bi;
    }
//]step4.

    /**
     * Create a BufferedImage (with the default number
     * of channels) from an Image
     *
     * @param image       The original Image
     * @return            The BufferedImage
     */
    public BufferedImage createBufferedImage(Image image)
    {
       return createBufferedImage(image, DEFAULT_CHANNELS);
    }


//[method2.
    /**
     * Create a BufferedImage from a file/resource 
     * containing an Image
     *
     * @param name        The name of the file/resource
     * @param channels    3 for RGB; 4 for ARGB
     * @return            The BufferedImage
     */
    public BufferedImage createBufferedImage(String name, 
                                             int channels)
    {
       BufferedImage   image, result;       
       InputStream     is;       
       int             imageType;       
       

       image = null;       
       is    = finder.findInputStream(name);       

       if (is != null)
       {
          try
          {
             image       = ImageIO.read(is);       
             is.close();             
          }
          catch (IOException io)
          {
             image       = null;          
          }
       }

       // Modify the type, if necessary
       result = image;
       if (image != null)
       {
          imageType = image.getType();
          if (((channels == 3) && 
               (imageType != BufferedImage.TYPE_INT_RGB)) ||
              ((channels == 4) && 
               (imageType != BufferedImage.TYPE_INT_ARGB))    )
          {
             result = createBufferedImage(image, channels);
          }
       }
       
       return result;
    }
//]method2.

    /**
     * Create a BufferedImage (with a default number of channels) from
     * a file containing an Image
     *
     * @param name    The name of the file/resource
     * @return        The BufferedImage
     */
    public BufferedImage createBufferedImage(String name)
    {
       return createBufferedImage(name, DEFAULT_CHANNELS);       
    }



    /**
     * Read BufferedImage objects from a group of files/resources
     *
     * @param names    The names of the files/resources
     * @param channels 3 for RGB, 4 for ARGB
     * @return         The images or null if an Exception was thrown
     */
    public BufferedImage[] createBufferedImages(String[] names, 
                                                int channels)    
    {
       BufferedImage[]        result;
       int                    n;

       result = null;
        
       if (names != null)
       {
          n         = names.length;
          result    = new BufferedImage[n];
          for (int i=0; i<n; i++)
          {
             result[i] = createBufferedImage(names[i], channels);
          }
       }

       return result;
    }    
    

    /**
     * Read a row-oriented array of BufferedImage objects from a file
     *
     * @param name     The name of the file/resource
     * @param n        The number of images
     * @param channels 3 for RGB, 4 for ARGB
     * @return         The images or null if an Exception was thrown
     */
    public BufferedImage[] createBufferedImages(String name, 
                                                int n, int channels)    
    {
       BufferedImage          composite;
       BufferedImage[]        result;
       int                    height, width;
        
       result    = null;
       composite = createBufferedImage(name, channels);
        
       if (composite != null)
       {
          height = composite.getHeight(null);
          width  = composite.getWidth(null) / n;
          result = new BufferedImage[n];
            
          for (int j=0; j<n; j++)
          {
             result[j] = composite.getSubimage(j*width, 0, 
                                               width, height);

          }
       }
       return result;
    }    
    

    /**
     * Read a table-oriented array of BufferedImage objects from a file
     *
     * @param name     The name of the file/resource
     * @param rows     The number of rows
     * @param columns  The number of columns
     * @param channels 3 for RGB, 4 for ARGB
     * @return         The images or null if an Exception was thrown
     */
    public BufferedImage[][] createBufferedImages(String name, 
                                                  int rows, int columns, 
                                                  int channels)    
    {
       BufferedImage          composite;
       BufferedImage[][]      result;
       int                    height, width;
        
       result    = null;
       composite = createBufferedImage(name, channels);
        
       if (composite != null)
       {
          height = composite.getHeight(null) / rows;
          width  = composite.getWidth(null) / columns;
          result = new BufferedImage[rows][columns];
          for (int r=0; r<rows; r++)
          {
             for (int c=0; c<columns; c++)
             {
                result[r][c] = composite.getSubimage(c*width, r*height, 
                                                     width, height);
             }
          }
            
       }
       return result;
    }    
    
}
