// --------------------------------------------------------------------
// Author: Maciej Dziemianczuk
// www.faces-of-nature.art.pl/
// maciek.ciupa at gmail com
//
// Henon map

import java.awt.*;
import java.applet.Applet;

import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;



// --------------------------------------------------------------------
class CCoordinate extends java.applet.Applet
{
    public double x0, y0;
    public double xn, yn;

    public int Width, Height;

    public int OX, OY;
    public double dx, dy;

    // -------------------------------------------
    public CCoordinate(int _width, int _height, double _x0, double _xn, double _y0, double _yn)
    {
    	Width = _width;
    	Height = _height;
    	
        x0 = _x0;
        y0 = _y0;
        xn = _xn;
        yn = _yn;

        OX = 15;
        OY = Height + 15;
        dx = (xn - x0)/(double)(Width);
        dy = (yn - y0)/(double)(Height);
    }
    // -------------------------------------------
    // return X value on the coordinate system
    public int getX(double _x)
    {
        return OX + (int)((_x - x0)/dx);
    }
    public int getY(double _y)
    {
        return OY - (int)((_y - y0)/dy);
    }
	// -------------------------------------------
	// return double from integer pixel coordinate
	public double getX(int _x)
	{
		return (_x - OX)*dx + x0;
	}
	public double getY(int _y)
	{
		return (OY - _y)*dy + y0;
	}
	
	public void drawPoint(Graphics g, double _x, double _y)
	{
		if (_x > x0 && _x < xn && _y > y0 && _y < yn)
		{
			int x = getX(_x);
			int y = getY(_y);
			g.drawLine(x, y, x, y);
		}
	}
	
	public void drawColumn(Graphics g, double _x, double _y, int width)
	{
		if (_x > x0 && _x < xn && _y > y0 && _y < yn)
		{
			int x = getX(_x);
			int y = getY(_y);
			g.fillRect(x, y, width, getY(0.0) - getY(_y));
		}
	}
	
    // -------------------------------------------
    public void paint(Graphics g)
    {
    	
        // draw axis
        g.drawRect(OX,OY-Height,Width,Height);
        
        //System.out.println("AAA=" + getX(-0.5));
        
        g.drawLine(getX(x0)-3,getY(0.0),getX(xn)+10,getY(0.0)); // X axis
        g.drawLine(getX(xn)+10,getY(0.0), getX(xn)+5,getY(0.0)-3);
        g.drawLine(getX(xn)+10,getY(0.0), getX(xn)+5,getY(0.0)+3);
        
        g.drawLine(getX(0.0),getY(y0)+3,getX(0.0),getY(yn)-10); // Y axis
		g.drawLine(getX(0.0),getY(yn)-10, getX(0.0)-3,getY(yn)-5);
		g.drawLine(getX(0.0),getY(yn)-10, getX(0.0)+3,getY(yn)-5);
		
		
		// draw units
		for (int i=0; i<((xn-x0)*10); ++i)
		{
			g.drawLine(getX(x0+0.1*i), getY(0.0)-2,getX(x0+0.1*i), getY(0.0)+2);
		}
		for (int i=0; i<((yn-y0)*10); ++i)
		{
			g.drawLine(getX(0.0)-2, getY(y0+0.1*i),getX(0.0)+2, getY(y0+0.1*i));
		}
    }
}

//---------------------------------------------------------------------
class CHenonHistGraph extends java.applet.Applet
{
	CCoordinate Coord;
	double x0,xn,y0,yn, dx, dy;
	double alpha,beta;
	int Iterations;
	int Mode = 0;
	int Prec = 1;
	int Width;
	
	// array for histogram
	long Histogram[];// = new long[Width];
	
	int __iterPass = 100000;
	
	//-----------------------------------------------------------------
	public CHenonHistGraph(double _x0, double _xn, double _y0, double _yn, double _alpha, double _beta, int _Iterations, int _Mode, int _Prec)
	{
    	Mode = _Mode;
    	x0 = _x0;
        y0 = _y0;
        xn = _xn;
        yn = _yn;
        alpha = _alpha;
        beta = _beta;
        Iterations = _Iterations;
        Prec = _Prec;
    	
    	Rectangle r = getBounds();
    	Coord = new CCoordinate(r.width-30, r.height-30, x0, xn, y0, yn);
	}

	//-----------------------------------------------------------------
	public void paint ( Graphics g )
	{
		// get size of window
		Rectangle r = getBounds();
		Coord = new CCoordinate(r.width-30, r.height-30, x0, xn, y0, yn);
		
		Coord.paint(g);
		
		Histogram( g );
		
	}
	// ----------------------------------------------------------------
	public double FDeriv( double x )
	{
		return - 2.0 * alpha * x;
	}
	// ----------------------------------------------------------------
	public double Lapunow ( )
	{
		double value = 0;
		double x = x0;
		for (int i=0; i<Width; ++i)
		{
			value += (Math.log(Math.abs(FDeriv(x)))) * Histogram[i]/(double)(Iterations-1);
			x += dx;
		}
		
		return value;
	}
	// ----------------------------------------------------------------
	public void Histogram ( Graphics g )
	{
		
		Rectangle r = getBounds();
		Width = r.width-30;
		Width = Width / Prec;
		
		// array of args
		Histogram = new long[Width];
		long Sum = 0;
		int Idx;
		
		double X = 0, Y = 0;
		double nX, nY;
		
		double A = alpha;
		double B = beta;
		
		
		
		dx = (xn - x0)/Width;
		dy = (xn - x0)/Width;
		
		//System.out.println("Width = " + Width + " dx = " + dx + " Iterations " + Iterations);
		
		g.drawString (Double.toString(x0), Coord.getX(x0)+10, Coord.getY(-0.05) );
		g.drawString (Double.toString(xn), Coord.getX(xn)-20, Coord.getY(-0.05) );
		g.drawString (Double.toString(1.0), Coord.getX(1.0)-10, Coord.getY(-0.05) );
		
		
		for (int i=0; i<Width; ++i)
		{
			Histogram[i] = 0;
		}
		
		// ----------------------------------------------------------
		
		X = 0.5;
		Y = 0.5;
		for (int iter=0; iter<__iterPass+Iterations; ++iter)
		{
			//if (iter == 0) 
				//System.out.println("X = " + X + " Y = " + Y + " A " + A + " B " + B);
				
			nX = Y + 1 - A*X*X;
			nY = B * X;
			
			X = nX;
			Y = nY;
			
			if (iter > __iterPass)
			{
				if (Mode == 0)
				{
					if (X > x0 && X < xn)
					{
						Idx = (int)((X - x0)/dx);
						Histogram[Idx] ++;
						++ Sum;
					}
				}
				else
				{
					if (Y > x0 && Y < xn)
					{
						Idx = (int)((Y - x0)/dy);
						Histogram[Idx] ++;
						++ Sum;
					}
				}
				
			}			
		}
				
		
		
		// get the max count
		long MaxCount = 0;
		for (int i=0; i<Width; ++i)
		{
			if (Histogram[i] > MaxCount) MaxCount = Histogram[i];
		}
		
		
		System.out.println("dx = " + dx + " max = " + MaxCount + " Sum = " + Sum );
		System.out.println("Lapunow = " + Lapunow() );
		
		// draw histogram
		X = x0;
		for (int i_arg=0; i_arg < Width; ++i_arg)
		{
			
			Coord.drawColumn(g, X, (double)(Histogram[i_arg])/(double)(MaxCount), Prec);
			X += dx;
		}
		g.drawString (Double.toString(MaxCount), Coord.getX(0.0)+10, Coord.getY(1.0)+5);
		
	}
	
};

//---------------------------------------------------------------------
//---------------------------------------------------------------------
public class CHenonHist extends Applet implements ItemListener
{
        Choice mode;
        TextField tf1,  tf2, tf3, tf4, tf5, tf6, tf7, tf8;
        Button but1;

        CHenonHistGraph tablet;
        
        int Mode = 0;
        
        double x0 = -1.4,
        	   xn = 1.4,
        	   y0 = -1.5,
        	   yn = 1.5;
        
        double alpha = 1.4, 
        	   beta=0.3;
        
        int prec = 1;
        
        int Iterations = 1000000;

        //-----------------------------------------------------------------
        public void init()
        {
                //getSize().width
                tablet = new CHenonHistGraph(x0,xn,-0.1,1.1,alpha,beta,Iterations,Mode,prec);

                tf1 = new TextField(Double.toString(x0), 2);
                tf2 = new TextField(Double.toString(xn), 2);
                
                tf3 = new TextField(Double.toString(y0), 2);
                tf4 = new TextField(Double.toString(yn), 2);
                tf5 = new TextField(Integer.toString(Iterations), 10);
                tf6 = new TextField(Double.toString(alpha), 2);
                tf7 = new TextField(Double.toString(beta), 2);
                tf8 = new TextField(Integer.toString(prec), 2);
                but1 = new Button("Draw");


                mode = new Choice();
				mode.addItem( "wart. X" );
				mode.addItem( "wart. Y" );

                
                setLayout( new BorderLayout() );

                Panel sPanel = new Panel();
                Panel nPanel = new Panel();

                sPanel.setLayout( new FlowLayout() );

                // Labels  in South panel

				Label L1 = new Label("Zakres");
                L1.setBackground(Color.gray);
                sPanel.add( L1 );
                sPanel.add( tf1);
                
                L1 = new Label(" - ");
                L1.setBackground(Color.gray);
                sPanel.add( L1 );
                sPanel.add( tf2);
                
               	L1 = new Label("A:");
                L1.setBackground(Color.gray);
                sPanel.add( L1 );
                sPanel.add( tf6);
                
                L1 = new Label("B:");
                L1.setBackground(Color.gray);
                sPanel.add( L1 );
                sPanel.add( tf7);
                
                L1 = new Label("Tryb:");
                L1.setBackground(Color.gray);
                sPanel.add( L1 );
                sPanel.add( mode );
                
                L1 = new Label("Prec.:");
                L1.setBackground(Color.gray);
                sPanel.add( L1 );
                sPanel.add( tf8 );
                
                L1 = new Label("Iter.:");
                L1.setBackground(Color.gray);
                sPanel.add( L1 );
                sPanel.add( tf5 );

                sPanel.add( but1 );

                // Labels and others in north panel
                L1 = new Label("Henon Map - Histogram");

                Font ft = new Font ( "Tahoma", Font.BOLD, 12 );
                L1.setFont(ft);

                L1.setBackground(Color.white);
                nPanel.add( L1 );




                add( "North", nPanel );
                add( "South", sPanel );
                add( "Center", tablet );


                tablet.setBackground(Color.white);
                sPanel.setBackground(Color.gray);
                nPanel.setBackground(Color.white);


                //mode.addActionListener(itemStateChanged);
				mode.addItemListener( this );

        }

        public boolean action(Event e, Object arg)
        {

                if (e.target == but1)
                {

                        x0 = Double.parseDouble( tf1.getText() );
                        xn = Double.parseDouble( tf2.getText() );
                        y0 = Double.parseDouble( tf3.getText() );
                        yn = Double.parseDouble( tf4.getText() );
                        Iterations = Integer.parseInt( tf5.getText() );
                        alpha = Double.parseDouble( tf6.getText() );
                        beta = Double.parseDouble( tf7.getText() );
                        prec = Integer.parseInt(tf8.getText() );

                }

                remove( tablet );
                tablet = new CHenonHistGraph(x0,xn,-0.1,1.1,alpha,beta,Iterations,Mode,prec);
                tablet.setBackground(Color.white);
                add( "Center", tablet );
                validate();

                return true;
        }
        
    //-----------------------------------------------------------------
	public void itemStateChanged( ItemEvent evt )
	{
		if ( evt.getSource() == mode )
		{
			Mode = mode.getSelectedIndex();
		}

	} 

};

