/*
 * [ISBN.java]
 *
 * Summary: Applet to validate and format ISBNs (International Standard Book Numbers).
 *
 * Copyright: (c) 1998-2014 Roedy Green, Canadian Mind Products, http://mindprod.com
 *
 * Licence: This software may be copied and used freely for any purpose but military.
 *          http://mindprod.com/contact/nonmil.html
 *
 * Requires: JDK 1.7+
 *
 * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/
 *
 * Version History:
 *  1.1 1998-12-28 handle empty or null clipboard better.
 *  1.2 1998-12-31 handle variable first dash position.
 *  1.3 1999-01-07 check for invalid publisher number.
 *                 correctly handle group codes 80.. 99990.
 *  1.4 2000-06-07 looser publisher number checks on high groups.
 *                 No longer attempt to place dash between
 *                 publisher and title for groups other than 0 and 1.
 *  1.5 2001-02-09 check on group number
 *  1.6 2002-02-17 add support for 1-4000-4728-5, new ranges
 *                 formerly illegal.
 *                 update list of valid groups.
 *                 Fix bug that was marking some groups ending in 9 as invalid.
 *  1.7 2005-06-18 add about box, tidy code, use stomp
 *                 minor change in hyphenation rules.
 *                 precise list of valid groups, generated from web page.
 *                 reorganised code in validate class to more cleanly handle
 *                 lead and trail junk. Now works better when ISBN has surrounding junk.
 *  1.8 2005-06-19 methods no longer preserve enclosing junk.
 *  1.9 2005-12-16 adds Javadoc
 *  2.0 2006-03-05 reformat with IntelliJ and add Javadoc.
 *  2.1 2007-08-24 convert to JDK 1.5. handle ISBN-13
 *  2.2 2008-04-04 add build number to title, tidy code, fix spelling errors.
 *  2.3 2009-03-16 tidy code, rename some methods.
 *  2.4 2011-09-30 now display isbn-10 and isbn-13 both with and without dashes.
 *  2.5 2011-12-03 configurable look and feel
 */
package com.mindprod.isbn;

import com.mindprod.common17.Build;
import com.mindprod.common17.CMPAboutJBox;
import com.mindprod.common17.ClipboardPoker;
import com.mindprod.common17.FontFactory;
import com.mindprod.common17.HybridJ;
import com.mindprod.common17.JEButton;
import com.mindprod.common17.Laf;
import com.mindprod.common17.VersionCheck;

import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * Applet to validate and format ISBNs (International Standard Book Numbers).
 * <p/>
 * The ISBN Amanuensis will help you proofread, validate, convert
 * and tidy ISBN (International Standard Book Number)
 * references in your HTML or other documentation.
 * <p/>
 * Description of the hyphenation rules.
 * <p/>
 * http://www.isbn.org/standards/home/isbn/international/hyphenation-instructions.asp
 * <p/>
 * his program does not deal with the new 13-digit bar-code ISBNs.
 * <p/>
 * Here are some sample ISBNs correctly formatted:
 * <p/>
 * group/country-publisher-title#-checkdigit
 * <p/>
 * examples of good formatted ISBNs
 * 0-00-000000-0
 * 0-200-00000-4
 * 0-7000-0000-3
 * 0-85000-000-9
 * 0-900000-00-7
 * 0-9500000-0-0
 * 0-9999999-9-0
 * 1-00-000000-1
 * 1-09-999999-5
 * 1-100-00000-3
 * 1-399-99999-0
 * 1-4000-0000-9
 * 1-4999-9999-2
 * 1-5000-0000-0
 * 1-5499-9999-0
 * 1-55000-000-4
 * 1-86979-999-2
 * 1-869800-00-1
 * 1-9990000-0-5
 * 2-00000000-2
 * 2-95000000-2
 * 3-00000000-3
 * 3-99999999-3
 * 4-00000000-4
 * 4-95000000-4
 * 5-00000000-5
 * 5-95000000-5
 * 7-00000000-7
 * 7-20000000-0
 * 7-95000000-7
 * 80-0000000-8
 * 93-9999999-8
 * 950-000000-8
 * 950-999999-7
 * 9949-99999-5
 * 9950-00000-9
 * 9959-99999-8
 * 9960-00000-1
 * 9989-99999-6
 * 99901-9601-X
 * <p/>
 * examples of bad ISBNs
 * 6000000006
 * 6950000006
 * 6999999996
 * 9400000006
 * 9419000001
 * 949999999X
 * 992999999X
 * 9930000003
 * 9934000008
 * 9939999992
 * 9940000006
 * 9999900003
 * 9999999999
 * <p/>
 * Unfortunately the program cannot correctly place the dash
 * between publisher and title for groups other than 0 and 1.
 * <p/>
 * e.g. it does not currently hyphenate these Brazilian ISBNs correctly
 * 85-7393-116-7
 * 85-216-0551-X
 * <p/>
 * The lead 0 is significant. ISBNs always contain 10 or 13 digits.
 * <p/>
 * It takes the rawISBN ISBN (which may contain dashes, lead, trail
 * or embedded spaces or other miscellaneous junk), validates
 * the check digit and insert the dashes in the proper places
 * using a set of rules described at
 * <p/>
 * Just paste the rawISBN ISBN into the left window, click Tidy
 * then copy the tidied ISBN from the right window.
 * <p/>
 * When you run the ISBN Amanuensis as an application, it is
 * even more automatic. You don't need to do any manual pasting
 * and copying. Just click Tidy to tidy the current contents of
 * the clipboard. The tidied ISBN replaces the old the rawISBN text
 * clipboard contents. This automatic feature is not available
 * in the Applet version because the Applet sandbox considers
 * it a security risk.
 *
 * @author Roedy Green, Canadian Mind Products
 * @version 2.5 2011-12-03 configurable look and feel
 * @since 1998
 */
public final class ISBN extends JApplet implements ClipboardOwner
    {
    // todo:
    // prepare a CSV file of triples, low, high, pattern. eg.
    // 000000000, 199999999, 0-00-bbbbbb-x.  The pattern can be formed with 0-9 a-z. - is dash.
    // low and high are 9 digits with out dashs, without the check digit.
    // must be sorted by low, much cover all numbers.
    // Gets turned into a binary search list.
    // The list might be automatically generated from ISBN standards XML file.
    // May use same table for 10 and 13 or something similar for 13, with not all numbers covered.
    // or could just have a big list of examples, including on for first and last of a range.
    // If put extras not needed in, they would be deleted.
    // Read a binary resourc eof band objests : low value, high value, array of offsets to insert -.
    // scheme could handle variable # of dashes in future.
    // instead of absolute offsets in undashed or dashed version where - go, might code
    // the length of each chunk between dashes. Would be easier to proofread/debug.
    // could also build by strings rather than char by char.

    /**
     * height of Applet box in pixels. Does not include surrounding frame.
     */
    private static final int APPLET_HEIGHT = 380;

    /**
     * Width of Applet box in pixels.
     */
    private static final int APPLET_WIDTH = 640;

    private static final int FIRST_COPYRIGHT_YEAR = 1998;

    /**
     * undisplayed copyright notice
     */
    @SuppressWarnings( { "UnusedDeclaration" } )
    private static final String EMBEDDED_COPYRIGHT =
            "Copyright: (c) 1998-2014 Roedy Green, Canadian Mind Products, http://mindprod.com";

    private static final String RELEASE_DATE = "2011-12-03";

    private static final String TITLE_STRING = "CMP ISBN Validator";

    private static final String VERSION_STRING = "2.5";

    private static final Color BACKGROUND_FOR_APPLET = new Color( 0xf6fff6 );

    private static final Color BACKGROUND_FOR_EDITABLE = Color.WHITE;

    private static final Color BACKGROUND_FOR_UNEDITABLE = new Color( 0xdef9ff );

    private static final Color FOREGROUND_FOR_INSTRUCTIONS = new Color( 0x008000 );

    private static final Color FOREGROUND_FOR_LABEL = new Color( 0x0000b0 );

    /**
     * for titles
     */
    private static final Color FOREGROUND_FOR_TITLE = new Color( 0xdc143c );

    private static final Font FONT_FOR_LABELS = FontFactory.build( "Dialog", Font.BOLD, 15 );

    /**
     * for for titles and buttons buttons
     */
    private static final Font FONT_FOR_TITLE = FontFactory.build( "Dialog", Font.BOLD, 16 );

    /**
     * for for title second line
     */
    private static final Font FONT_FOR_TITLE2 = FontFactory.build( "Dialog", Font.PLAIN, 14 );

    /**
     * clear ISBN
     */
    private JButton clearButton;

    /**
     * paste ISBN from clipboard
     */
    private JButton pasteButton;

    /**
     * tidy the ISBN
     */
    private JButton tidyButton;

    /**
     * label for isbn10
     */
    private JLabel isbn10Lab;

    /**
     * label for isbn13
     */
    private JLabel isbn13Lab;

    /**
     * label for raw isbn
     */
    private JLabel isbnRawLab;

    /**
     * title
     */
    private JLabel title;

    /**
     * title, second line
     */
    private JLabel title2;

    /**
     * instructions
     */
    private JTextArea instructions;

    /**
     * result ISBN-13 with dashes.
     */
    private JTextField cookedISBN10;

    /**
     * result ISBN-13 with dashes.
     */
    private JTextField cookedISBN13;

    /**
     * result ISBN-13 without dashes.
     */
    private JTextField plainISBN10;

    /**
     * result ISBN-13 without dashes.
     */
    private JTextField plainISBN13;

    /**
     * where user enters rawISBN ISBN10 or 13 with or without dashes.
     */
    private JTextField rawISBN;

    /**
     * Allow this Applet to run as as application as well.
     *
     * @param args command line arguments ignored.
     */
    public static void main( String args[] )
        {
        // app is smaller than Applet since fewer fields.
        HybridJ.fireup( new ISBN(),
                TITLE_STRING + " " + VERSION_STRING,
                APPLET_WIDTH,
                APPLET_HEIGHT );
        } // end main

    /**
     * Called by the browser or Applet viewer to inform
     * this Applet that it is being reclaimed and that it should destroy
     * any resources that it has allocated.
     */
    public void destroy()
        {
        clearButton = null;
        plainISBN10 = null;
        plainISBN13 = null;
        cookedISBN10 = null;
        cookedISBN13 = null;
        instructions = null;
        isbn10Lab = null;
        isbn13Lab = null;
        isbnRawLab = null;
        pasteButton = null;
        rawISBN = null;
        tidyButton = null;
        title2 = null;
        title = null;
        }

    /**
     * Called by the browser or Applet viewer to inform
     * this Applet that it has been loaded into the system.
     */
    @Override
    public void init()
        {
        if ( !VersionCheck.isJavaVersionOK( 1, 7, 0, this ) )
            {
            return;
            }
        buildMenu();
        Container contentPane = this.getContentPane();
        contentPane.setBackground( BACKGROUND_FOR_APPLET );
        contentPane.setLayout( new GridBagLayout() );
        buildComponents();
        setDefaultInstructions();
        layoutFields( contentPane );
        // REGISTER LISTENERS
        hookClearButton();
        hookTidyButton();
        hookPasteButton();
        this.validate();
        this.setVisible( true );
        } // end init

    /**
     * If we put data in the Clipboard, and somebody else changes the clipboard, we lose ownership and are notified
     * here. Satisfies the requirement of this class to implement java.awt.datatransfer.ClipboardOwner.
     *
     * @param clipboard the clipboard for this Applet
     * @param contents  The contents of the clipboard.
     */
    public void lostOwnership( Clipboard clipboard, Transferable contents )
        {
        // we don't care.
        }

    /**
     * allocate all components
     */
    private void buildComponents()
        {
        title = new JLabel( TITLE_STRING + " " + VERSION_STRING );
        title.setFont( FONT_FOR_TITLE );
        title.setForeground( FOREGROUND_FOR_TITLE );
        title2 = new JLabel(
                "released:" +
                RELEASE_DATE +
                " build:" +
                Build.BUILD_NUMBER
        );
        title2.setFont( FONT_FOR_TITLE2 );
        title2.setForeground( FOREGROUND_FOR_TITLE );
        // With Applet we have two text windows you must manually cut/paste,
        // with Clear and Tidy Button.
        // With application, you have no windows, just the Tidy Button.
        isbnRawLab = new JLabel( "raw" );
        isbnRawLab.setFont( FONT_FOR_LABELS );
        isbnRawLab.setForeground( FOREGROUND_FOR_LABEL );
        rawISBN = new JTextField( "", 13 + 4 + 2 );
        rawISBN.setEditable( true );
        rawISBN.setFont( FontFactory.build( "Dialog", Font.PLAIN, 15 ) );
        rawISBN.setBackground( BACKGROUND_FOR_EDITABLE );
        isbn10Lab = new JLabel( "ISBN-10" );
        isbn10Lab.setFont( FONT_FOR_LABELS );
        isbn10Lab.setForeground( FOREGROUND_FOR_LABEL );
        plainISBN10 = new JTextField( "", 10 + 3 + 2 );
        plainISBN10.setEditable( false );
        plainISBN10.setBackground( BACKGROUND_FOR_UNEDITABLE );
        plainISBN10.setFont( FontFactory.build( "Dialog", Font.PLAIN, 15 ) );
        cookedISBN10 = new JTextField( "", 10 + 3 + 2 );
        cookedISBN10.setEditable( false );
        cookedISBN10.setBackground( BACKGROUND_FOR_UNEDITABLE );
        cookedISBN10.setFont( FontFactory.build( "Dialog", Font.PLAIN, 15 ) );
        isbn13Lab = new JLabel( "ISBN-13" );
        isbn13Lab.setFont( FONT_FOR_LABELS );
        isbn13Lab.setForeground( FOREGROUND_FOR_LABEL );
        plainISBN13 = new JTextField( "", 13 + 4 + 2 );
        plainISBN13.setEditable( false );
        plainISBN13.setBackground( BACKGROUND_FOR_UNEDITABLE );
        plainISBN13.setFont( FontFactory.build( "Dialog", Font.PLAIN, 15 ) );
        cookedISBN13 = new JTextField( "", 13 + 4 + 2 );
        cookedISBN13.setEditable( false );
        cookedISBN13.setBackground( BACKGROUND_FOR_UNEDITABLE );
        cookedISBN13.setFont( FontFactory.build( "Dialog", Font.PLAIN, 15 ) );
        clearButton = new JEButton( "Clear" );
        clearButton.setToolTipText( "Clear everything" );
        pasteButton = new JEButton( "Paste" );
        pasteButton.setToolTipText(
                "Paste ISBN, convert and copy resulting tidied ISBN-13 back to the clipboard." );
        // three lines
        tidyButton = new JEButton( "Tidy | Convert | Validate" );
        tidyButton.setToolTipText( "Convert, Tidy and validate the raw ISBN" );
        instructions = new JTextArea( "" );
        instructions.setEditable( false );
        instructions.setMargin( new Insets( 2, 2, 2, 2 ) );
        instructions.setBackground( BACKGROUND_FOR_UNEDITABLE );
        instructions.setForeground( FOREGROUND_FOR_INSTRUCTIONS );
        }

    /**
     * build a menu with Look & Feel and About across the top
     */
    private void buildMenu()
        {
        final JMenuBar menubar = new JMenuBar();
        setJMenuBar( menubar );
        final JMenu lafMenu = Laf.buildLookAndFeelMenu();
        if ( lafMenu != null )
            {
            menubar.add( lafMenu );
            }
        final JMenu menuHelp = new JMenu( "Help" );
        menubar.add( menuHelp );
        final JMenuItem aboutItem = new JMenuItem( "About" );
        menuHelp.add( aboutItem );
        aboutItem.addActionListener( new ActionListener()
        {
        public void actionPerformed( ActionEvent e )
            {
            new CMPAboutJBox( TITLE_STRING,
                    VERSION_STRING,
                    "Convert, Tidy and Validate the ISBN-10 and ISBN-13",
                    "numbers used to identify books",
                    "freeware",
                    RELEASE_DATE,
                    FIRST_COPYRIGHT_YEAR,
                    "Roedy Green",
                    "ISBN",
                    "1.7" );
            }
        } );
        }

    /**
     * display isbn in 10 and 13 form, with and without dashes.
     *
     * @param raw the raw input isbn may or may not have dashes
     */
    private void displayResults( final String raw )
        {
        try
            {
            rawISBN.setText( raw );
            final String stripped = ISBNValidate.tidyISBN10or13RemovingDashes( raw );
            rawISBN.setText( stripped );
            final String isbn10WithoutDashes;
            final String isbn13WithoutDashes;
            final String isbn13WithDashes;
            final String isbn10WithDashes;
            switch ( stripped.length() )
                {
                case 10:
                    isbn10WithoutDashes = stripped;
                    isbn13WithoutDashes = ISBNValidate.isbn10To13( isbn10WithoutDashes );
                    isbn10WithDashes = ISBNValidate.tidyISBN10or13InsertingDashes( isbn10WithoutDashes );
                    isbn13WithDashes = ISBNValidate.tidyISBN10or13InsertingDashes( isbn13WithoutDashes );
                    plainISBN10.setText( isbn10WithoutDashes );
                    plainISBN13.setText( isbn13WithoutDashes );
                    cookedISBN10.setText( isbn10WithDashes );
                    cookedISBN13.setText( isbn13WithDashes );
                    break;
                case 13:
                    isbn13WithoutDashes = stripped;
                    isbn10WithoutDashes = ISBNValidate.isbn13To10( isbn13WithoutDashes );
                    isbn13WithDashes = ISBNValidate.tidyISBN10or13InsertingDashes( isbn13WithoutDashes );
                    isbn10WithDashes =
                            isbn10WithoutDashes.equals( "n/a" )
                            ? "n/a"
                            : ISBNValidate.tidyISBN10or13InsertingDashes( isbn10WithoutDashes );
                    plainISBN10.setText( isbn10WithoutDashes );
                    plainISBN13.setText( isbn13WithoutDashes );
                    cookedISBN10.setText( isbn10WithDashes );
                    cookedISBN13.setText( isbn13WithDashes );
                    break;
                default:
                    throw new IllegalArgumentException(
                            "ISBN must be 10 or 13 digits long." );
                }
            setDefaultInstructions();
            }
        catch ( IllegalArgumentException oops )
            {
            plainISBN10.setText( null );
            plainISBN13.setText( null );
            cookedISBN10.setText( null );
            cookedISBN13.setText( null );
            instructions.setText( oops.getMessage() );
            }
        }

    /**
     * hook up ActionListener for Clear button
     */
    private void hookClearButton()
        {
        clearButton.addActionListener( new ActionListener()
        {
        public void actionPerformed( ActionEvent e )
            {
            rawISBN.setText( null );
            plainISBN10.setText( null );
            plainISBN13.setText( null );
            cookedISBN10.setText( null );
            cookedISBN13.setText( null );
            }
        } );
        }

    /**
     * hook up ActionListener for Paste button
     */
    private void hookPasteButton()
        {
        pasteButton.addActionListener( new ActionListener()
        {
        public void actionPerformed( ActionEvent e )
            {
            displayResults( ClipboardPoker.getClip( ISBN.this ) );
            ClipboardPoker.setClip( cookedISBN13.getText(), ISBN.this );
            }
        } );
        }

    /**
     * hook up ActionListener for Tidy button
     */
    private void hookTidyButton()
        {
        tidyButton.addActionListener( new ActionListener()
        {
        public void actionPerformed( ActionEvent e )
            {
            displayResults( rawISBN.getText() );
            }
        } );
        }

    /**
     * layout fields in a GridBag
     *
     * @param contentPane contentPane of JApplet
     */
    private void layoutFields( Container contentPane )
        {
        // Applet GridBag:
        // ----- 0 - 1---  --------- 2 -----
        // --------title-------- title2------ 0
        // raw   ---rawISBN ----  ---------- 2
        // isbn10  --plain10 -- --cooked-10- 3
        // inbn13 --plain13-- --cooked-13--- 4
        // Clear--------  tidy--- --(paste)- 5
        // -----instructions---------------- 6
        // x y w h wtx wty anchor fill T L B R padx pady
        contentPane.add( title,
                new GridBagConstraints( 0,
                        0,
                        2,
                        1,
                        0.0,
                        0.0,
                        GridBagConstraints.WEST,
                        GridBagConstraints.NONE,
                        new Insets( 10, 10, 5, 5 ),
                        0,
                        0 )
        );
        // x y w h wtx wty anchor fill T L B R padx pady
        contentPane.add( title2,
                new GridBagConstraints( 2,
                        0,
                        1,
                        1,
                        0.0,
                        0.0,
                        GridBagConstraints.EAST,
                        GridBagConstraints.NONE,
                        new Insets( 0, 5, 5, 10 ),
                        0,
                        0 )
        );
        // x y w h wtx wty anchor fill T L B R padx pady
        contentPane.add( isbnRawLab,
                new GridBagConstraints( 0,
                        2,
                        1,
                        1,
                        0.0,
                        0.0,
                        GridBagConstraints.EAST,
                        GridBagConstraints.NONE,
                        new Insets( 5, 10, 5, 5 ),
                        0,
                        0 )
        );
        // x y w h wtx wty anchor fill T L B R padx pady
        contentPane.add( rawISBN,
                new GridBagConstraints( 1,
                        2,
                        1,
                        1,
                        50.0,
                        0.0,
                        GridBagConstraints.WEST,
                        GridBagConstraints.BOTH,
                        new Insets( 5, 10, 5, 5 ),
                        0,
                        0 )
        );
        // x y w h wtx wty anchor fill T L B R padx pady
        contentPane.add( isbn10Lab,
                new GridBagConstraints( 0,
                        3,
                        1,
                        1,
                        0.0,
                        0.0,
                        GridBagConstraints.EAST,
                        GridBagConstraints.NONE,
                        new Insets( 5, 10, 5, 5 ),
                        0,
                        0 )
        );
        // x y w h wtx wty anchor fill T L B R padx pady
        contentPane.add( plainISBN10,
                new GridBagConstraints( 1,
                        3,
                        1,
                        1,
                        50.0,
                        0.0,
                        GridBagConstraints.EAST,
                        GridBagConstraints.BOTH,
                        new Insets( 5, 10, 5, 5 ),
                        0,
                        0 )
        );
        // x y w h wtx wty anchor fill T L B R padx pady
        contentPane.add( cookedISBN10,
                new GridBagConstraints( 2,
                        3,
                        1,
                        1,
                        50.0,
                        0.0,
                        GridBagConstraints.EAST,
                        GridBagConstraints.BOTH,
                        new Insets( 5, 10, 5, 5 ),
                        0,
                        0 )
        );
        // x y w h wtx wty anchor fill T L B R padx pady
        contentPane.add( isbn13Lab,
                new GridBagConstraints( 0,
                        4,
                        1,
                        1,
                        0.0,
                        0.0,
                        GridBagConstraints.EAST,
                        GridBagConstraints.NONE,
                        new Insets( 5, 10, 5, 5 ),
                        0,
                        0 )
        );
        // x y w h wtx wty anchor fill T L B R padx pady
        contentPane.add( plainISBN13,
                new GridBagConstraints( 1,
                        4,
                        1,
                        1,
                        50.0,
                        0.0,
                        GridBagConstraints.EAST,
                        GridBagConstraints.BOTH,
                        new Insets( 5, 10, 5, 5 ),
                        0,
                        0 )
        );
        // x y w h wtx wty anchor fill T L B R padx pady
        contentPane.add( cookedISBN13,
                new GridBagConstraints( 2,
                        4,
                        1,
                        1,
                        50.0,
                        0.0,
                        GridBagConstraints.EAST,
                        GridBagConstraints.BOTH,
                        new Insets( 5, 10, 5, 5 ),
                        0,
                        0 )
        );
        // x y w h wtx wty anchor fill T L B R padx pady
        contentPane.add( clearButton,
                new GridBagConstraints( 0,
                        5,
                        1,
                        1,
                        0.0,
                        0.0,
                        GridBagConstraints.WEST,
                        GridBagConstraints.NONE,
                        new Insets( 10, 10, 5, 5 ),
                        0,
                        0 )
        );
        // x y w h wtx wty anchor fill T L B R padx pady
        contentPane.add( tidyButton,
                new GridBagConstraints( 1,
                        5,
                        1,
                        1,
                        0.0,
                        0.0,
                        GridBagConstraints.CENTER,
                        GridBagConstraints.NONE,
                        new Insets( 10, 5, 5, 5 ),
                        0,
                        0 )
        );
        // x y w h wtx wty anchor fill T L B R padx pady
        contentPane.add( pasteButton,
                new GridBagConstraints( 2,
                        5,
                        1,
                        1,
                        0.0,
                        0.0,
                        GridBagConstraints.EAST,
                        GridBagConstraints.NONE,
                        new Insets( 10, 5, 5, 10 ),
                        0,
                        0 )
        );
        // x y w h wtx wty anchor fill T L B R padx pady
        contentPane.add( instructions,
                new GridBagConstraints( 0,
                        6,
                        3,
                        1,
                        0.0,
                        0.0,
                        GridBagConstraints.CENTER,
                        GridBagConstraints.HORIZONTAL,
                        new Insets( 5, 10, 10, 10 ),
                        0,
                        0 )
        );
        }

    /**
     * set default instructions on how to work the Applet
     */
    private void setDefaultInstructions()
        {
        instructions.setText( "Ctrl-C the raw ISBN-10 or 13 to the clipboard;\n"
                              + "click Paste;\n"
                              + "then Ctrl-V the tidied ISBN-13 to your application." );
        }
    }
