/* PayByCheck.java   David Fourer
 *
 *	Takes some information from the user and creates a bank check.
 * The interesting part is writing out the dollar amount in words.
 * 	see class NumbersToWords.
 * There is also a "designer image" on the check, contained in a file
 * 	see fish.gif.
 * The writing on the check is dont in the print() method.
 * 	it makes the paint method rather long, but seems simplest.
 * 	This is easier to program with some graph paper and pencil handy.
 * Other methods are:
 * 	init()			gets image, calls inputPanel().
 * 	inputPanel()	the user interface.
 *		getInfo()		evaluates information supplied by user for appropriateness
 *		actionPerformed()
 */

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.text.DateFormat;
import java.applet.Applet;

public class PayByCheck extends Applet implements ActionListener {

											//user interface Panel
	private TextField comment, firstN, lastN, balance;
	private Button print, close;
	private TextArea ta;

											//check values:
	private String name, date, cmt;
	private int dollars, cents;

											//check image:
	private Image im;
	boolean firstPaint = true;
//_________________________________________________________________init()
	public void init() {
		im = getImage( getDocumentBase(), "fish.gif" );

		inputPanel();
	}
//________________________________________________________________paint()
	public void paint( Graphics g ) {
		int x = 180;									//coordinates for check image
		int y = 0;
		if( firstPaint ) {								//applet calls paint once
			g.drawImage( im, x, y, this );				//show blank form
			g.drawRect( x, y, 382, 177 );
			return;
		}																	//check printing fonts
		Font serif14 = new Font( "serif", Font.PLAIN, 14 );
		Font serif14Italic = new Font( "serif", Font.ITALIC, 14 );
		Font serif14BoldItalic = new Font( "serif", Font.BOLD+Font.ITALIC, 14 );
		Font serif20 = new Font( "serif", Font.PLAIN, 20 );
		Font serif20Italic = new Font( "serif", Font.ITALIC, 20 );
		Font serif20BoldItalic = new Font( "serif", Font.BOLD+Font.ITALIC, 20 );

		g.drawImage( im, x, y, this );
		g.drawRect( x, y, 382, 177 );
		g.setFont( serif14 );
			g.drawString( "David Fourer", x+20, 20 );			//account owner's name
			g.drawString( "18909 W. 60th Pl.", x+20, 35 );		//account owner's address
			g.drawString( date, x+240, 40 );					//date
			g.drawString( cmt, x+20, 150 );					//comment
			g.drawString( "_______________", x+20, 150 );		//comment underscore
			g.drawString( "XXO XO OOO XO XXOO XOOOX", x+30, 170 );	//lower left, bank #
		g.setFont( serif14Italic );
			g.drawString( "Pay to the", x+15, 70 );				//check text
			g.drawString( "Order of___________________________", x+30, 85 );
		g.setFont( serif20BoldItalic );						//long-hand amt underscore
			g.drawString( "___________________________________", x+15, 110 );
			g.drawString( "______________", x+220, 150 );		//signature underscore

			g.drawString( "$_______", x+275, 85 );				//right hand $ amount
			String s = String.valueOf( cents );				//with underscore
			String t = String.valueOf( dollars );				//prepare string
			if( cents <= 9 )
				s = "0" + s;
			g.drawString( t + "." + s, x+285, 85 );
													//long-hand $ amount
													//use small font if won't fit
			String d = new String( NumbersToWords.wordDollars( dollars ) );
			String c = new String( NumbersToWords.wordCents( cents ) );
			if( g.getFontMetrics( serif20BoldItalic ).stringWidth( d + " " + c ) < 355 )
				g.drawString( d + " " + c, x+15, 110 );
			else {									//wrap if still won't fit
				g.setFont( serif14BoldItalic );
				if( g.getFontMetrics( serif14BoldItalic ).stringWidth( d + " " + c ) > 355 ) {
			 		g.drawString( d + " ", x+15, 110 );
			 		g.drawString( c, x+290, 130 );
			 	}
			 	else
 					g.drawString( d + " " + c, x+15, 110 );
			}
													//name, truncate if won't fit
		g.setFont( serif20 );			
			while( g.getFontMetrics( serif20 ).stringWidth( name ) > 185 )
				name = name.substring( 0, name.length() - 1 );
			g.drawString( name, x+80, 85 );
	}
//____________________________________________________________inputPanel()
	public void inputPanel() {
		setLayout( null );								//overrides auto-sizing of panels
		Panel p = new Panel();						//Panel with all user action
		p.setSize( 160, 400 );
		p.setLayout( new GridLayout( 2, 1 ) );
		p.setFont( new Font( "Serif", Font.PLAIN, 14 ) );
		Panel pt = new Panel();						//top Panel with text fields
		Panel pb = new Panel();						//bottom Panel with textArea
		
		pt.setLayout( new GridLayout( 6, 2 ) );	//not the best layout, but works

		pt.add( new Label( "First Name" ) );		//name
		pt.add( firstN = new TextField() );

		pt.add( new Label( "Last Name" ) );
		pt.add( lastN = new TextField() );

		pt.add( new Label( "Balance" ) );			//user enters ###.## string amount
		pt.add( balance = new TextField() );

		pt.add( new Label( "Comment" ) );		//comment field at bottom of check
		pt.add( comment = new TextField() );

		print = new Button( "Print Check" );		//action buttons
		print.addActionListener( this );
		pt.add( print );

		close = new Button( "Done" );
		close.addActionListener( this );
		pt.add( close );
		p.add( pt );
										//user instructions go here
		ta = new TextArea( "", 8, 14, TextArea.SCROLLBARS_NONE );
		ta.setEditable( false );
		ta.setFont( new Font( "SansSerif", Font.PLAIN, 18 ) );
		ta.setForeground( Color.blue );
		ta.setText( "Enter information.  Then click 'Print Check' to see check." );
		pb.add( ta );
		p.add( pb );
		
		add( p );
		setVisible( true );
	}
//__________________________________________________________________getInfo()
	public boolean getInfo() {
									//get name
									//name is a must-fill field
		name = new String( firstN.getText() + " " + lastN.getText() );
		if( name.trim().equals( "" ) ) {
			ta.setText( "You need to enter a name" );
			return false;
		}							//get comment string
		cmt = comment.getText();
									//get today's date
		date = DateFormat.getDateInstance( DateFormat.LONG ).format( new Date() );		

									//get the amount string, parse, check for validity
		String bal = balance.getText();
		int decimalIndex = bal.indexOf( (int) '.' );
		if( decimalIndex < 0 ) {
			ta.setText( "For amount, you need to use a decimal point." );
			return false;
		}String dString = bal.substring( 0, decimalIndex );
		if( dString.length() == 0 )
			dString = "0";
		String cString = bal.substring( decimalIndex + 1 );
		if( cString.length() != 2 ) {
			ta.setText( "For amount, you need two places after the decimal point." );
			return false;
		}										
		try {									//convert dollar and cent strings to int.
			dollars = Integer.parseInt( dString );
			cents = Integer.parseInt( cString );
		}catch( NumberFormatException nfe ) {
			ta.setText( "Please correct the check amount.  It is not valid." );
			return false;
		}
		ta.setText( "Enter new information to view another check." );
		return true;									//all fields are OK
	}//________________________________________________________actionPerformed
	public void actionPerformed( ActionEvent e ) {
		if( e.getSource() == print ) {
			if( getInfo() ) {							//returns true if user input valid
				firstPaint = false;					//paint() called first by applet
				repaint();										// OK to paint
			}
		}
		if( e.getSource() == close ) {
			System.exit( 0 );
		}
	}
}

/**	class NumbersToWords.java  David Fourer
 *		contains two static methods used for applet PayByCheck.java.
 *		wordCents( int ) and wordDollars( int ) return two strings
 * 	needed to print the amount in a check.
 */

class NumbersToWords {
											
	private static final String AND = "and ";
	private static final String DOLLAR = "Dollar ";
	private static final String DOLLARS = "Dollars ";
	private static final String HUNDRED = "Hundred ";
	private static final String THOUSAND = "Thousand ";

	private static final String ONES[] = { "Zero ", "One ", "Two ", "Three ",
								"Four ", "Five ", "Six ", "Seven ", "Eight ", "Nine ",
								"Ten ", "Eleven ", "Twelve ", "Thirteen ", "Fourteen ",
								"Fifteen ", "Sixteen ", "Seventeen ", "Eighteen ",
								"Nineteen " };

	private static final String TENS[] = { "0", "1", "Twenty ", "Thirty ",
												"Forty ", "Fifty ", "Sixty ", "Seventy ",
												"Eighty ", "Ninety " };

	public static String wordCents( int c ) {		// string of form "00/00 cents"
		
		StringBuffer buf = new StringBuffer();
		if( c < 0 || c > 99 )
			return "error";

		buf.insert( 0, "/00 " );
		buf.insert( 0, String.valueOf( c ) );
		if( c<=9 )
			buf.insert( 0, "0" );
		buf.insert( 0, AND );
		return buf.toString();
	}
	
	public static String wordDollars( int d ) {	// string with dollars in words
		StringBuffer buf = new StringBuffer();
		if( d < 0 || d > 1000000 )
			return "error";
	
		if( d == 0 )
			return (buf.insert( 0, ONES[0] + DOLLARS ) ).toString();
		if( d == 1 )
			return (buf.insert( 0, ONES[1] + DOLLAR ) ).toString();
					
		buf.insert( 0, DOLLARS );						

		if( d % 100 < 20 && d % 100 > 0 ) 			// 1 to 19
			buf.insert( 0, ONES[d%100] );

		if( d % 100 >= 20 ) {						// 20 to 99
			if( d%10 != 0 )
				buf.insert( 0, ONES[d%10] );
			buf.insert( 0, TENS[d%100/10] );
		}
		if( d % 1000 > 99 ) 						// 100 to 999
			buf.insert( 0, ONES[(d%1000)/100] + HUNDRED );

		if( d % 1000000 > 999 )					// 1,000 TO 999,999
			buf.insert( 0, THOUSAND );
			
		if( (d % 100000)/1000 < 20 && (d % 100000)/1000 > 0 )
			buf.insert( 0, ONES[(d%100000)/1000] );	// 1,000 to 19,999

		if( (d % 100000) >= 20000 ) {				// 20,000 to 99,999
			if( (d % 10000)/1000 != 0 )
				buf.insert( 0, ONES[(d%10000)/1000] );
			buf.insert( 0, TENS[(d%100000)/10000] );
		}		
		if( d % 1000000 >= 100000 )				// 100,000 to 999,999
			buf.insert( 0, ONES[(d%1000000)/100000] + HUNDRED );

		return buf.toString();
	}
}