import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Fractal extends JApplet
{
    public void init ( )
    {
        //super("Fractal in Execution Model by Hans Ji");
        frameSize = 600;
        bigSquareLength = 360;
        smallestSquareLength = 10;
        int input = ( int ) ( Math.random ( ) * 8 );
        divisionNumber = input;
        v = new Vector();
        pseudoSleepTime = 1;
        _colorIndex = 0;


        //setSize(frameSize, frameSize);
        //show();
        Container c = getContentPane ( );
        c.setLayout ( new BorderLayout ( ) );

        _resultField = new JTextField ( 40 );
        //_resultField.setEditable ( false );
        c.add ( _resultField, BorderLayout.NORTH );
        _resultField.setText ( "Fractal Dimension = ???????????" );
    
        setVisible ( true );
    }

    public void paint(Graphics g)
    {
        _resultField.repaint ( );
        g.setColor( _availableColors [ _colorIndex ] );
        int originalX = 40;
        int originalY = 40;
        int length = bigSquareLength;
        SquareInfo si = new SquareInfo(originalX, originalY, 
                                       length);
        drawSquare(si, g);
        addSmallSquares(si, g);
        
        if (v.isEmpty() == true)
        {
            return;
        }
        SquareInfo tempSi = (SquareInfo)v.elementAt(0);
        double smallSquareLength = tempSi.getLength();
        while (smallSquareLength > smallestSquareLength &&
               v.isEmpty ( ) == false )
        {
            addSmallSquares(tempSi, g);
            v.removeElementAt(0);
            tempSi = (SquareInfo)v.elementAt(0);
            smallSquareLength = tempSi.getLength();
            System.out.println ( "smallSquareLength="+smallSquareLength );
        }
        v.clear();
        System.out.println ( "v cleared" );

        double FractalDimension = 0; 
        if ( divisionNumber == 1 )
        {
            FractalDimension = 0; 
        }
        else
        {
            if ( divisionNumber % 2 == 0 )
            {
                FractalDimension = Math.log ( divisionNumber * divisionNumber 
                                    / 2 ) / ( Math.log ( divisionNumber ) );
            }
            else
            {
                FractalDimension = Math.log ( divisionNumber * divisionNumber 
                                 / 2 + 1 ) / ( Math.log ( divisionNumber ) );
            }
        }
        StringBuffer fractalDimensionStrBuf = 
                new StringBuffer ( "Fractal Dimension = " );
        fractalDimensionStrBuf.append ( FractalDimension );
        _resultField.setText ( fractalDimensionStrBuf.toString ( ) );
    }

    private void drawSquare(final SquareInfo si, Graphics g)
    {
        g.drawRect((int)si.getX(), (int)si.getY(), 
                   (int)si.getLength(), (int)si.getLength());
    }
    private void fillSquare(final SquareInfo si, Graphics g)
    {

        g.fillRect((int)si.getX(), (int)si.getY(), 
                   (int)si.getLength(), (int)si.getLength());
    }
    private void addSmallSquares(SquareInfo si, Graphics g)
    {
        _colorIndex = ( int ) ( Math.random ( ) * _availableColors.length );
        g.setColor ( _availableColors [ _colorIndex ] ); 
        if (divisionNumber <= 0)
        {
            System.out.println("invalid divisionNumber");
            System.exit(0);
        }
        double smallSquareLength = si.getLength()/
                                   (double)divisionNumber;
        SquareInfo smallSquares[][];
        double smallSquareOriginXs[][];
        double smallSquareOriginYs[][];
        smallSquares = new SquareInfo[divisionNumber][]; 
        smallSquareOriginXs = new double[divisionNumber][];
        smallSquareOriginYs = new double[divisionNumber][];
        for (int i = 0; i < divisionNumber; i++)
        {
            smallSquares[i] = new SquareInfo[divisionNumber];
            smallSquareOriginXs[i] = new double[divisionNumber];
            smallSquareOriginYs[i] = new double[divisionNumber];
        }
        for (int i = 0; i < divisionNumber; i++)
        {
            for (int j = 0; j < divisionNumber; j++)
            {
                smallSquareOriginXs[i][j] = si.getX() + 
                                            j*smallSquareLength;
                smallSquareOriginYs[i][j] = si.getY() + 
                                            i*smallSquareLength;
                smallSquares[i][j] = new SquareInfo(
                                     smallSquareOriginXs[i][j],
                                     smallSquareOriginYs[i][j],
                                     smallSquareLength);
                if (shouldFillSmallSquare(i, j) == true)
                {
                    fillSquare(smallSquares[i][j], g);
                }
                else
                {
                    //drawSquare(smallSquares[i][j], g);
                    v.addElement(smallSquares[i][j]);
                }
                Sleeper.sleep(pseudoSleepTime);
            }
        }
    }
    private boolean shouldFillSmallSquare(int i, int j)
    {
/*
        if ( ( (i == 0) && (j == divisionNumber - 1) ) ||
             ( (i == (int)divisionNumber/2) &&
               (j == (int) divisionNumber/2) ) 
             //(i == j) ||
             //(i + j == divisionNumber - 1)
           )
        {
            return true;
        }
        return false;
*/
        if (i % 2 == 0)
        {
            if (j % 2 == 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            if (j % 2 == 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
    }
    

    static public void main (String args[])
    {
        /*
        int i;
        if (args.length == 0)
        {
            i = 3;
        }
        else
        {
            Integer I = new Integer (args[0]);
            i = I.intValue();
        }
        Fractal f = new Fractal(i);
        MyWindowAdapter wa = new MyWindowAdapter();
        f.addWindowListener(wa);
        */
    }

    private 
    Vector v;
    int frameSize;
    int bigSquareLength;
    int smallestSquareLength;
    int divisionNumber;
    int pseudoSleepTime;

    private final Color _availableColors [ ] = { 
            Color.red, Color.gray, Color.green, Color.white, 
            Color.orange, Color.blue, Color.black, Color.cyan, 
            Color.darkGray, Color.magenta, Color.pink, Color.yellow, 
            Color.lightGray };
    int _colorIndex;

    JTextField _resultField;

}

class SquareInfo
{
    public SquareInfo(double x_, double y_, double length_)
    {
        x = x_;
        y = y_;
        length = length_;
    }
    public double getX() { return x; } 
    public double getY() { return y; } 
    public double getLength() { return length; } 
    public void print()
    {
        System.out.print("SquareInfo::x="+x+",y="+y+",length=");
        System.out.println(length);
    }
    private
    double x;
    double y;
    double length;
}
class MyWindowAdapter extends WindowAdapter
{
    public MyWindowAdapter()
    { 
        super();
    }
    public void windowClosing (WindowEvent e)
    {
        System.exit(0);
    }
}

class Sleeper
{
    public static void sleep ( final int miliSeconds_ )
    {
        try 
        {
            Thread.sleep ( miliSeconds_ );
        }
        catch ( InterruptedException e )
        {
            System.err.println ( e.toString ( ) ); 
        }
    }
}

