/* @(#)PicturePages.java 1.0  24 September 2004 */

/* Useful imports */

import edu.neu.ccs.*;
import edu.neu.ccs.gui.*;
import edu.neu.ccs.codec.*;
import edu.neu.ccs.console.*;
import edu.neu.ccs.filter.*;
import edu.neu.ccs.jpf.*;
import edu.neu.ccs.parser.*;
import edu.neu.ccs.pedagogy.*;
import edu.neu.ccs.quick.*;
import edu.neu.ccs.util.*;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.font.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.border.*;
import java.io.*;
import java.util.*;
import java.math.*;
import java.beans.*;
import java.lang.reflect.*;
import java.net.URL;
import java.util.regex.*;

// import java.text.*;


public class PicturePages extends JPF 
{
    
    public static void main(String[] args) { 
        // To optionally adjust the look and feel,
        // remove the comments from one of the two statements below.
        
        // LookAndFeelTools.showSelectLookAndFeelDialog();
        LookAndFeelTools.adjustAllDefaultFontSizes(10);
        
        new PicturePages();
    }
    
    
    // member variables
    
    /** The image directory. */
    private String directory = null;
    
    /** The web site title. */
    private String pagetitle = null;
    
    /** The list of image file names in the image directory. */
    private String[] files = new String[0];
    
    /** The length of the files list. */
    private int length = 0;
    
    
    // constants
    
    /** The doctype string. */
    private final String doctype =
        "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.1 Transitional//EN\">\n\n";
    
    /** The css file name. */
    private final String cssname =
        "pictures_style.css";
    
    /** The css link string. */
    private final String csslink =
        "\n<link type=\"text/css\" rel=\"stylesheet\" href=\""
        + cssname
        + "\">\n";
    
    /** The html string. */
    private final String html = "<html>\n";
    
    /** The end html string. */
    private final String endhtml = "\n</html>\n";
    
    /** The head string. */
    private final String head = "\n<head>\n";
    
    /** The end head string. */
    private final String endhead = "\n</head>\n";
    
    /** The title string. */
    private final String title = "<title>\n";
    
    /** The end title string. */
    private final String endtitle = "\n</title>\n";
    
    /** The body string. */
    private final String body = "\n<body>\n";
    
    /** The end body string. */
    private final String endbody = "\n</body>\n";
    
    /** The paragraph string. */
    private final String paragraph = "<p>\n";
    
    /** The end paragraph string. */
    private final String endparagraph = "\n</p>\n\n";
    
    /** The open link string. */
    private final String openlink = "\n<a href=\"";
    
    /** The shut link string. */
    private final String shutlink = "\">";
    
    /** The end link string. */
    private final String endlink = "</a>\n";
    
    /** The open image string. */
    private final String openimage = "\n<img src=\"";
    
    /** The shut image string. */
    private final String shutimage = "\" />\n";
    
    /** The filter to pick out jpg, gif, and png files. */
    private final FilenameFilter filter = new FilenameFilter() {
        public boolean accept(File dir, String name) {
            if (name == null)
                return false;
            
            return name.startsWith(".jpg", name.length() - 4)
                || name.startsWith(".JPG", name.length() - 4)
                || name.startsWith(".gif", name.length() - 4)
                || name.startsWith(".GIF", name.length() - 4)
                || name.startsWith(".png", name.length() - 4)
                || name.startsWith(".PNG", name.length() - 4);
        }
    };
        
    
    
    /**
     * Build a GUI to input the image directory and page title that
     * calls the master method to build the image web site.
     *
     */
    public void makePictureWebSiteGUI() {
        // define the input text fields for directory and page title
        final TextFieldView directoryView = new TextFieldView(600);
        final TextFieldView pagetitleView = new TextFieldView(600);
        
        // define the panel to annotate and display input text fields
        TablePanel viewPanel =
            new TablePanel(
                new Object[][] {
                    { "Images Directory" , directoryView },
                    { "Web Page Title",    pagetitleView } },
                10, 10, WEST);
        
        // define the action that will make the site using the directory
        // and page title
        SimpleAction makeSite = new SimpleAction("Make Web Site") {
            public void perform() {
                directory = directoryView.getViewState();
                pagetitle = pagetitleView.getViewState();
                makePictureWebSite();
            }
        };
        
        // define the panel to hold the input text fields and the button
        // that executes the make site action
        TablePanel mainPanel =
            new TablePanel(
                new Object[] { viewPanel, makeSite },
                VERTICAL, 10, 10, CENTER);
        
        // place the main panel in a frame that is centered on screen
        JPTFrame.createQuickJPTFrame("Make Picture Web Site", mainPanel);
    }
    
    
    /** Master method to build the image web site. */
    private void makePictureWebSite() {
        // copy the default cascading style sheet file to the directory
        copyCSS();
        
        // read the images file names from the directory
        readImageFileNames();
        
        // create the htm files in the directory
        createPictureWebSite();
    }
    
    
    /** The method that reads the file names of the image files. */
    private void readImageFileNames() {
        // open File object to access the directory with images
        File imagesDirectory = new File(directory);
        
        // obtain array of file names for image files in directory
        files = imagesDirectory.list(filter);
        
        // save count of image file names
        length = files.length;
    }
    
    
    /**
     * Extracts a picture label from an image file name.
     *
     * Removes file extension.
     * Skips leading digits and underscores.
     * Replaces later underscores with spaces.
     * Adds spaces before initial digits and initial uppercase letters
     */
    private String refineFileName(String name) {
        // eliminate image file extension from name
        name = name.substring(0, name.length() - 4);
        
        // test string size
        int size = name.length();
        
        if (size == 0)
            return name;
        
        // skip leading digits and underscores as long as this does not
        // make the string empty
        int index = 0;
        
        while (index < size) {
            char next = name.charAt(index);
            
            if (Character.isDigit(next))
                index++;
            else
            if (next == '_')
                index++;
            else
                break;
        }
        
        if ((index > 0) && (index < (length - 1)))
            name = name.substring(index);
        
        size = name.length();
        
        // replace later underscores with spaces
        // add spaces before initial digits or initial uppercase letters
        //
        // use a StringBuffer to collect characters
        StringBuffer buffer = new StringBuffer(128);
        
        buffer.append(name.charAt(0));
        
        for (index = 1; index < size; index++) {
            char c = name.charAt(index);
            char d = name.charAt(index - 1);
            
            if (Character.isDigit(c)) {
                if (! Character.isDigit(d)) {
                    buffer.append(' ');
                }
            }
            
            if (Character.isUpperCase(c)) {
                if (! Character.isUpperCase(d)) {
                    buffer.append(' ');
                }
            }
            
            if (c == '_')
                buffer.append(' ');
            else
                buffer.append(c);
        }
        
        // convert the buffer back to a string and return it
        name = buffer.toString();
       
        return name;
    }
    
    
    /** Create the web site by creating each page. */
    private void createPictureWebSite() {
        // build the site page by page
        for (int i = 0; i < length; i++)
            createPictureWebPage(i);
        
        // print confirmation message in text console
        console.out.println("Web Site Done: " + length + " Image Files");
    }
    
    
    /** Create the i-th page of the web site. */
    private void createPictureWebPage(int i) {
        // use StringBuffer to collect characters
        StringBuffer buffer = new StringBuffer(1024);
        
        // standard web page opening
        buffer.append(doctype);
        buffer.append(html);
        
        // web page head
        buffer.append(head);
        buffer.append(title);
        buffer.append(pagetitle);
        buffer.append(endtitle);
        buffer.append(csslink);
        buffer.append(endhead);
        
        // web page body
        buffer.append(body);
        
        // repeat page title in window
        buffer.append(paragraph);
        buffer.append(pagetitle);
        buffer.append(endparagraph);
        
        // make links First Back Next Last
        appendSideLinks(buffer, i);
        
        // make link that brings in picture with its caption
        makePictureLink(buffer, files[i]);
        
        // standard web page closing
        buffer.append(endbody);
        buffer.append(endhtml);
        
        // convert the buffer back to a string to get page text
        String page = buffer.toString();
        
        
        // send the i-th page text to the i-th web site file
        try {
            // use pattern: open file; write page; close file
            FileWriter writer = new FileWriter(createWebPagePathName(i));
            writer.write(page);
            writer.close();
        }
        catch (IOException ex) {
            // print messages if IO errors happen
            console.out.println("IO failure for web page: " + i);
            console.out.println("Message: " + ex.getMessage());
            
            // exit since things are not OK
            throw new RuntimeException("Exiting due to IO Failure");
        }
    }
    
    
    /**
     * Append to the buffer the html code that links one picture page to
     * the first page, the back page, the next page, and the last page.
     */
    private void appendSideLinks(StringBuffer buffer, int i) {
        // start paragraph
        buffer.append(paragraph);
        
        // make link to first page unless we are the first page
        if (i > 0)
            linkTo(buffer, "First", 0);
        else
            buffer.append("First");
        
        buffer.append("\n");
        
        // make link to back page unless we are the first page
        if (i > 0)
            linkTo(buffer, "Back", (i-1));
        else
            buffer.append("Back");
        
        buffer.append("\n");
        
        // make link to next page unless we are the last page
        if (i < (length - 1))
            linkTo(buffer, "Next", (i+1));
        else
            buffer.append("Next");
        
        buffer.append("\n");
        
        // make link to last page unless we are the last page
        if (i < (length - 1))
            linkTo(buffer, "Last", (length - 1));
        else
            buffer.append("Last");
        
        buffer.append("\n");
        
        // finish paragraph
        buffer.append(endparagraph);
    }
    
    
    /** Create html for a link to the k-th page with given link text. */ 
    private void linkTo(StringBuffer buffer, String text, int k) {
        if ((k < 0) || (k >= length))
            return;
        
        buffer.append(openlink);
        buffer.append(createWebPageName(k));
        buffer.append(shutlink);
        buffer.append(text);
        buffer.append(endlink);
    }
    
    
    /**
     * Create the file name for the i-th web page.
     *
     * If i equals zero use "index.htm".
     *
     * If i is positive use "pictureXXX.htm" where XXX is the
     * three digit represention of (i+1) in digit characters.
     *
     * This convention means that the file names start with
     * "image.htm" and continue with "picture002.htm" etc.
     */
    private String createWebPageName(int i) {
        // for i equal to zero return "index.htm"
        if (i == 0)
            return "index.htm";
        
        // otherwise build "pictureXXX.htm"
        return "picture" + threeChars(i + 1) + ".htm";
    }
    
    
    /** Create the full path name for the i-th web page. */
    private String createWebPagePathName(int i) {
        return directory + File.separatorChar + createWebPageName(i);
    }
    
    
    /** Returns the integer i represented as XXX. */
    private String threeChars(int i) {
        if (i < 10)
            return "00" + i;
        
        if (i < 100)
            return "0" + i;
        
        return "" + i;
    }
    
    
    /** Create html for the link to the image and for its caption. */
    private void makePictureLink(StringBuffer buffer, String name) {
        String caption = refineFileName(name);
        
        buffer.append(paragraph);
        buffer.append(openimage);
        buffer.append(name);                
        buffer.append(shutimage);
        buffer.append(endparagraph);
        
        buffer.append(paragraph);
        buffer.append(caption);
        buffer.append(endparagraph);
    }
    
    
    /** Copy the pictures css file target directory. */
    private void copyCSS() {
        String oldPath = "./" + cssname;
        String newPath = directory + File.separatorChar + cssname;
        
        copySmallFile(oldPath, newPath);
    }
    
    
    /**
     * Copy a small text file from one place to another.
     *
     * Assumes that the entire file can be read into memory at once.
     */
    private void copySmallFile(String oldPath, String newPath) {
        if ((oldPath == null) || (newPath == null))
            return;
        
        int bufferSize = 8092;
        
        StringBuffer buffer = new StringBuffer(bufferSize);
        char[] data = new char[bufferSize];
        
        // read file
        try {
            // use pattern: open file; read file; close file
            FileReader reader = new FileReader(oldPath);
            
            while(true) {
                int count = reader.read(data);
                
                if (count > 0)
                    buffer.append(data, 0, count);
                else
                    break;
            }
            
            reader.close();
        }
        catch (IOException ex) {
            // print messages if IO errors happen
            console.out.println("IO failure reading: " + oldPath);
            console.out.println("Message: " + ex.getMessage());
            
            // exit since things are not OK
            throw new RuntimeException("Exiting due to IO Failure");
        }
        
        // copy file
        try {
            // use pattern: open file; write page; close file
            FileWriter writer = new FileWriter(newPath);
            writer.write(buffer.toString());
            writer.close();
        }
        catch (IOException ex) {
            // print messages if IO errors happen
            console.out.println("IO failure writing: " + newPath);
            console.out.println("Message: " + ex.getMessage());
            
            // exit since things are not OK
            throw new RuntimeException("Exiting due to IO Failure");
        }
    }
    
    
    /** TEST CODE: Test the reading of file names. */
    private void printRawFileNames() {
        console.out.println("Image Directory:" + directory + "\n");
        
        console.out.println("Image File Count: " + length + "\n");
        
        for (int i = 0; i < length; i++)
            console.out.println(files[i]);
        
        console.out.println();
    }
    
    
    /** TEST CODE: Test the conversion of file names to picture labels. */
    private void printRefinedFileNames() {
        console.out.println("Image Directory:" + directory + "\n");
        
        console.out.println("Image File Count: " + length + "\n");
        
        for (int i = 0; i < length; i++)
            console.out.println(refineFileName(files[i]));
        
        console.out.println();
    }
    
    
}
