
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.io.*;
import java.util.*;

class BoilerDraw 
    extends JPanel
    implements MouseInputListener
{
    static final int SELECT_MODE = 1;
    static final int LINE_MODE = 2;
    static final int OVAL_MODE = 3;
    static final int RECTANGLE_MODE = 4;

    List _figures;
    int _mode;
    int _currentX;
    int _currentY;
    int _oldX;
    int _oldY;

    Figure _currentFigure;
    Vector _currentFigures;
    String _currentColor;
    boolean _paintMarkRectangle;

    public void mouseMoved( MouseEvent evt ) {
    }
  
    public void mouseDragged( MouseEvent evt ) {
	_currentX = evt.getX();
	_currentY = evt.getY();

	switch (_mode) {
	case RECTANGLE_MODE:
	case OVAL_MODE:
	case LINE_MODE:
	    _currentFigure.resize( _oldX, _oldY, _currentX, _currentY );
	    repaint();
	    break;
	case SELECT_MODE:
	    if ( _currentFigure != null ) {
		int dx = _currentX - _oldX;
		int dy = _currentY - _oldY;

		_currentFigure.setPosition( _currentFigure.getX0() + dx, 
					    _currentFigure.getY0() + dy );

		_oldX = _currentX;
		_oldY = _currentY;
		repaint();
	    }
	    else {
		_paintMarkRectangle = true;
		repaint();
	    }
	    break;
	}
    }
  
    public void mouseClicked( MouseEvent evt ) {
    }
  
    public void mousePressed( MouseEvent evt ) {
	_currentX = evt.getX();
	_currentY = evt.getY();
	_oldX = _currentX;
	_oldY = _currentY;

	switch (_mode) {
	case RECTANGLE_MODE:
	    Rectangle r = new Rectangle( _currentColor, _currentX, _currentY, 0, 0 );
	    r.resize( _currentX, _currentY, _oldX, _oldY );
	    _figures.addToFront( r );
	    _currentFigure = r;
	    repaint();
	    break;
	case OVAL_MODE:
	    Oval o = new Oval( _currentColor, _currentX, _currentY, 0, 0 );
	    o.resize( _currentX, _currentY, _oldX, _oldY );
	    _figures.addToFront( o );
	    _currentFigure = o;
	    repaint();
	    break;
	case LINE_MODE:	
	    Line l = new Line( _currentColor, _currentX, _currentY, _oldX, _oldY );
	    l.resize( _currentX, _currentY, _oldX, _oldY );
	    _figures.addToFront( l );
	    _currentFigure = l;
	    repaint();
	    break;
	case SELECT_MODE:
	    // Find selected figure
	    _currentFigure = null;
	    ListForwardIterator iterator = new ListForwardIterator( _figures );
	    while ( iterator.hasMoreNodes() ) {
		Figure f = (Figure) iterator.nextNode();
		if ( f.isSelected( _currentX, _currentY ) ) {
		    _currentFigure = f;
		    break;
		}
	    }
	    repaint();
	}
    }
  
    public void mouseReleased( MouseEvent evt ) {
	switch (_mode) {
	case RECTANGLE_MODE:
	case OVAL_MODE:
	case LINE_MODE:	
	    _mode = SELECT_MODE;
	    break;
	case SELECT_MODE:
	    break;
	}
	
	if ( _paintMarkRectangle ) {
	    // get box
	    int minX = _oldX;
	    int maxX = _currentX;
	    int minY = _oldY;
	    int maxY = _currentY;
	    if ( minX > maxX ) {
		minX = _currentX;
		maxX = _oldX;
	    }
	    if ( minY > maxY ) {
		minY = _currentY;
		maxY= _oldY;
	    }

	    // Find selected figures
	    _currentFigures.clear();
	    ListForwardIterator iterator = new ListForwardIterator( _figures );
	    while ( iterator.hasMoreNodes() ) {
		Figure f = (Figure) iterator.nextNode();
		if ( f.isInBox( minX, minY, maxX, maxY ) ) {
		    _currentFigures.add(f);
		}
	    }
 	    _paintMarkRectangle = false;
	    repaint();
	}
    }
  
    public void mouseEntered( MouseEvent evt ) {
    }

    public void mouseExited( MouseEvent evt ) {
    }

    public void menuOption( String option ) {
	if ( option.equals( "Select" ) ) {
	    _mode = SELECT_MODE;
	}
	else if ( option.equals( "Line" ) ) {
	    _mode = LINE_MODE;
	}
	else if ( option.equals( "Oval" ) ) {
	    _mode = OVAL_MODE;
	}
	else if ( option.equals( "Rectangle" ) ) {
	    _mode = RECTANGLE_MODE;
	}
	else if ( option.equals( "New" ) ) {
	    _figures.clear();
	    repaint();
	}
	else if ( option.equals( "Delete" ) ) {
	    if ( _currentFigure != null ) {
		_currentFigure.unlink();
		_currentFigure = null;
		repaint();
	    }
	}
	else if ( option.equals( "Bring to front" ) ) {
	    if ( _currentFigure != null ) {
		_currentFigure.unlink();
		_figures.addToFront( _currentFigure );
		repaint();
	    }
	}
	else if ( option.equals( "Send to back" ) ) {
	    if ( _currentFigure != null ) {
		_currentFigure.unlink();
		_figures.addToTail( _currentFigure );
		repaint();
	    }
	}
	else if ( option.equals( "To String" ) ) {
	    System.out.println( toString() );
	}
	else if ( option.equals( "Exit" ) ) {
	    System.exit( 0 );
	}
	else {
	    // See if it matches a color
	    for ( int i =0; i < Figure.palette.length; i++ ) {
		if ( Figure.palette[i].equals( option ) ) {
		    _currentColor = option;
		}
	    }
	    if (_currentFigure != null ) {
		_currentFigure.setColor( _currentColor );
		repaint();
	    }
	}
    }

    public void openFile( String fileName ) {
	_figures.clear();

	try {
	    BufferedReader in = new BufferedReader( new FileReader( fileName ) );
	    
	    // read line by line
	    String s = in.readLine();
	    while ( s != null ) {
		StringTokenizer t = new StringTokenizer( s, "|" );
		String figureName = t.nextToken();
		Figure fig = null;
		if ( figureName.equals( "Rectangle" )) {
		    _figures.addToFront( new Rectangle( t ) );
		}
		else if ( figureName.equals( "Oval" )) {
		    _figures.addToFront( new Oval( t ) );
		}
		else if ( figureName.equals( "Line" )) {
		    _figures.addToFront( new Line( t ) );
		}
		else if ( figureName.equals( "Text" )) {
		    _figures.addToFront( new Text( t ) );
		}
		s = in.readLine();
	    }
	    in.close();
	    repaint();
	}
	catch ( Exception e ) {
	    System.out.println( "*** Error reading file" );
	}

	repaint();
    }

    public String toString() {
	String s = "";
	ListBackwardIterator iterator = new ListBackwardIterator( _figures );
	while ( iterator.hasMoreNodes() ) {
	    Figure f = (Figure) iterator.nextNode();
	    s += f.toString();
	}
	return s;
    }

    public void saveFile( String fileName ) {
	try {
	    PrintWriter out = new PrintWriter( new FileOutputStream( fileName ) );
	    out.print( toString() );
	    out.close();
	}
	catch ( Exception e ) {
	    System.out.println( "*** Error writing file" );
	}
    }

    public void addText( String text ) {
	Text t = new Text( _currentColor, _currentX, _currentY, text );
	t.resize( _currentX, _currentY, _oldX, _oldY );
	_figures.addToFront( t );
	_currentFigure = t;
	repaint();
    }
    
    public void paintComponent( Graphics g ) {
	super.paintComponent( g );
	ListBackwardIterator iterator = new ListBackwardIterator( _figures );
	
	while ( iterator.hasMoreNodes() ) {
	    Figure f = (Figure) iterator.nextNode();
	    f.paint( g );
	    if ( _currentFigure == f ) {
		_currentFigure.paintSelected( g );
	    }
	}

	if ( _paintMarkRectangle ) {
	    // Paint mark rectangle
	    g.setColor( Color.blue.brighter() );
	    int minX = _oldX;
	    int maxX = _currentX;
	    int minY = _oldY;
	    int maxY = _currentY;
	    if ( minX > maxX ) {
		minX = _currentX;
		maxX = _oldX;
	    }
	    if ( minY > maxY ) {
		minY = _currentY;
		maxY= _oldY;
	    }
	    g.drawRect( minX, minY, maxX - minX, maxY - minY );
	}
    }
    
    public BoilerDraw() {
	_figures = new List();
	_currentFigure = null;;
	_currentFigures = new Vector();
	_mode = SELECT_MODE;
	_currentColor = "Green";
	_paintMarkRectangle = false;
    }
}

