
package jp.riken.brain.ni.samuraigraph.base;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JToggleButton;
import javax.swing.event.MouseInputListener;


/**
 * The panel used to select the axis in the plane: bottom, top, left and right.
 */
public abstract class SGAxisSelectionPanel extends javax.swing.JPanel
	implements ActionListener
{
    
	/**
	 * The default constructor.
	 */
    public SGAxisSelectionPanel()
    {
    	super();
        initComponents();
        this.initProperty();
    }

    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    private void initComponents() {//GEN-BEGIN:initComponents
        java.awt.GridBagConstraints gridBagConstraints;

        mScaleReferenceLabel2 = new javax.swing.JLabel();
        mScaleReferenceLabel1 = new javax.swing.JLabel();
        mFormPanel = new javax.swing.JPanel();
        mTopButton = new javax.swing.JRadioButton();
        mBottomButton = new javax.swing.JRadioButton();
        mLeftButton = new javax.swing.JRadioButton();
        mRightButton = new javax.swing.JRadioButton();

        setLayout(new java.awt.GridBagLayout());

        mScaleReferenceLabel2.setFont(new java.awt.Font("Dialog", 0, 12));
        mScaleReferenceLabel2.setText("(Value <-> Scale)");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0);
        add(mScaleReferenceLabel2, gridBagConstraints);

        mScaleReferenceLabel1.setFont(new java.awt.Font("Dialog", 1, 12));
        mScaleReferenceLabel1.setText("Scale Reference");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.ipadx = 7;
        gridBagConstraints.insets = new java.awt.Insets(5, 10, 0, 0);
        add(mScaleReferenceLabel1, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridheight = 2;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 0, 5);
        add(mFormPanel, gridBagConstraints);

        mTopButton.setFont(new java.awt.Font("Dialog", 0, 12));
        mTopButton.setText("Top");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        add(mTopButton, gridBagConstraints);

        mBottomButton.setFont(new java.awt.Font("Dialog", 0, 12));
        mBottomButton.setText("Bottom");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        add(mBottomButton, gridBagConstraints);

        mLeftButton.setFont(new java.awt.Font("Dialog", 0, 12));
        mLeftButton.setText("Left");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        add(mLeftButton, gridBagConstraints);

        mRightButton.setFont(new java.awt.Font("Dialog", 0, 12));
        mRightButton.setText("Right");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        add(mRightButton, gridBagConstraints);

    }//GEN-END:initComponents
    
    
    // 変数宣言 - 編集不可//GEN-BEGIN:variables
    protected javax.swing.JRadioButton mBottomButton;
    private javax.swing.JPanel mFormPanel;
    protected javax.swing.JRadioButton mLeftButton;
    protected javax.swing.JRadioButton mRightButton;
    private javax.swing.JLabel mScaleReferenceLabel1;
    private javax.swing.JLabel mScaleReferenceLabel2;
    protected javax.swing.JRadioButton mTopButton;
    // 変数宣言の終わり//GEN-END:variables


	private static final int RECTANGLE_WIDTH = 45;
	private static final int RECTANGLE_HEIGHT = 30;
	private static final int LINE_WIDTH = 2;


	protected AxisImagePanel mAxisImagePanel = new AxisImagePanel();


	/**
	 * 
	 *
	 */
	public void dispose()
	{
		this.mAxisImagePanel.dispose();
		this.mAxisImagePanel = null;

		this.mBottomLine = null;
		this.mTopLine = null;
		this.mLeftLine = null;
		this.mRightLine = null;
	}


	// initialization
	private void initProperty()
	{
		this.mFormPanel.add( this.mAxisImagePanel );
		
		this.mTopButton.addActionListener(this);
		this.mBottomButton.addActionListener(this);
		this.mLeftButton.addActionListener(this);
		this.mRightButton.addActionListener(this);
		this.mAxisImagePanel.addActionListener(this);

		// set the image
		final String name = SGIConstants.RESOURCES_DIRNAME + "GraphImage.png";
		final URL url = getClass().getResource(name);
		final Image image = Toolkit.getDefaultToolkit().getImage( url );

		// set the media tracker
		final MediaTracker mt = new MediaTracker(this);
		mt.addImage( image, 0 );
		try
		{
			mt.waitForAll();
		}
		catch( InterruptedException ex )
		{
		}

		this.mAxisImagePanel.setImage( image );
		this.mAxisImagePanel.setImageLocation( MARGIN, MARGIN );
		this.mAxisImagePanel.setImageSize( RECTANGLE_WIDTH, RECTANGLE_HEIGHT );

//		// set icon images
//		final String[] filenameArray = {
//			"Top.png", "Bottom.png", "Left.png", "Right.png" };
//		final AbstractButton[] btnArray = {
//			this.mTopButton, this.mBottomButton, this.mLeftButton, this.mRightButton };
//
//		this.setIconImages( filenameArray, btnArray );

	}


//	//
//	protected void setIconImages( String[] filenameArray, AbstractButton[] btnArray )
//	{
//		if( filenameArray.length!=btnArray.length )
//		{
//			throw new IllegalArgumentException("filenameArray.length!=btnArray.length");
//		}
//
//		final int num = filenameArray.length;
//
//		ImageIcon[] icons = new ImageIcon[num];
//		for( int ii=0; ii<num; ii++ )
//		{
//			icons[ii] = this.createIcon( filenameArray[ii] );
//		}
//		MediaTracker mt = new MediaTracker(this);
//		for( int ii=0; ii<num; ii++ )
//		{
//			mt.addImage( icons[ii].getImage(), ii );
//		}
//		try
//		{
//			mt.waitForAll();
//		}
//		catch( InterruptedException e )
//		{
//			e.printStackTrace();
//		}
//
//		for( int ii=0; ii<num; ii++ )
//		{
//			btnArray[ii].setIcon( icons[ii] );
//			btnArray[ii].updateUI();
//			btnArray[ii].setPreferredSize( new Dimension(36,36) );
//		}
//	}


//	/**
//	 * Create an icon object.
//	 * @param name - name of resource file
//	 */
//	private ImageIcon createIcon( final String name )
//	{
//		URL url = this.getClass().getResource( SGIConstants.RESOURCES_DIRNAME + name );
//		ImageIcon icon = new ImageIcon(url);
//		return icon;
//	}


	public void actionPerformed( final ActionEvent e )
	{
		Object source = e.getSource();
		if( source.equals( this.mAxisImagePanel ) )
		{
			this.setTopSelected( this.mAxisImagePanel.isTopSelected() );
			this.setBottomSelected( this.mAxisImagePanel.isBottomSelected() );
			this.setLeftSelected( this.mAxisImagePanel.isLeftSelected() );
			this.setRightSelected( this.mAxisImagePanel.isRightSelected() );
			this.updateButtons();
		}
		else if( source instanceof JToggleButton )
		{
			this.setTopSelected( this.mTopButton.isSelected() );
			this.setBottomSelected( this.mBottomButton.isSelected() );
			this.setLeftSelected( this.mLeftButton.isSelected() );
			this.setRightSelected( this.mRightButton.isSelected() );
			this.updateImage();
		}
	}


	// selection flag
	private boolean mTopFlag;
	private boolean mBottomFlag;
	private boolean mLeftFlag;
	private boolean mRightFlag;


	/**
	 * Returns whether the top axis is seleced.
	 */
	public boolean isTopSelected()
	{
		return this.mTopFlag;
	}

	/**
	 * Returns whether the bottom axis is seleced.
	 */
	public boolean isBottomSelected()
	{
		return this.mBottomFlag;
	}

	/**
	 * Returns whether the left axis is seleced.
	 */
	public boolean isLeftSelected()
	{
		return this.mLeftFlag;
	}

	/**
	 * Returns whether the right axis is seleced.
	 */
	public boolean isRightSelected()
	{
		return this.mRightFlag;
	}


	/**
	 * Selects or deselects the top axis.
	 * @param b - true selects the axis, false deselects the axis
	 */
	public void setTopSelected( final boolean b )
	{
		this.mTopFlag = b;
	}

	/**
	 * Selects or deselects the bottom axis.
	 * @param b - true selects the axis, false deselects the axis
	 */
	public void setBottomSelected( final boolean b )
	{
		this.mBottomFlag = b;
	}

	/**
	 * Selects or deselects the left axis.
	 * @param b - true selects the axis, false deselects the axis
	 */
	public void setLeftSelected( final boolean b )
	{
		this.mLeftFlag = b;
	}

	/**
	 * Selects or deselects the right axis.
	 * @param b - true selects the axis, false deselects the axis
	 */
	public void setRightSelected( final boolean b )
	{
		this.mRightFlag = b;
	}


	// clear all flags
	protected void clearAll()
	{
		this.setTopSelected(false);
		this.setBottomSelected(false);
		this.setLeftSelected(false);
		this.setRightSelected(false);
	}


	// update the image
	protected abstract void updateImage();


	// update the toggle buttons
	protected abstract void updateButtons();


	// lines
	protected Line mTopLine;
	protected Line mBottomLine;
	protected Line mLeftLine;
	protected Line mRightLine;


	/**
	 * Set the given line to be selected.
	 */
	protected abstract void selectLine( Line l );

	private static final int MARGIN = 3;


	// A class of panel displaying the image of axes.
	protected class AxisImagePanel extends SGImagePanel implements MouseInputListener
	{

		/**
		 * 
		 */
		private static final long serialVersionUID = 7607803033956753182L;

		protected AxisImagePanel()
		{
			super();

			final int width = RECTANGLE_WIDTH + 2*MARGIN;
			final int height = RECTANGLE_HEIGHT + 2*MARGIN;
			this.setPreferredSize( new Dimension( width, height ) );
			this.setSize( new Dimension( width, height ) );

			final int left = MARGIN;
			final int top = MARGIN;
			final int right = left + RECTANGLE_WIDTH;
			final int bottom = top + RECTANGLE_HEIGHT;

			mTopLine = new Line( left, top, right, top );
			mBottomLine = new Line( left, bottom, right, bottom );
			mLeftLine = new Line( left, top, left, bottom );
			mRightLine = new Line( right, top, right, bottom );

			mTopLine.setLocation(0);
			mBottomLine.setLocation(1);
			mLeftLine.setLocation(2);
			mRightLine.setLocation(3);
			
			this.addMouseListener(this);
			this.addMouseMotionListener(this);
		}


		/**
		 * 
		 */
		public void paintComponent( Graphics g )
		{
			super.paintComponent(g);
			Graphics2D g2d = (Graphics2D)g;

			g2d.setPaint( Color.GRAY );
			if(mTopLine.isSelected()){
				mBottomLine.draw(g2d);
			}else{
				mTopLine.draw(g2d);
			}
			if(mLeftLine.isSelected()){
				mRightLine.draw(g2d);
			}else{
				mLeftLine.draw(g2d);
			}
			g2d.setPaint( Color.BLACK );				
			if(mTopLine.isSelected()){
				mTopLine.draw(g2d);
			}else{
				mBottomLine.draw(g2d);
			}
			if(mLeftLine.isSelected()){
				mLeftLine.draw(g2d);
			}else{
				mRightLine.draw(g2d);
			}
		}
		
		
		public void mouseClicked( MouseEvent e )
		{
			final int x = e.getX();
			final int y = e.getY();

			final Line[] array = { mTopLine, mBottomLine, mLeftLine, mRightLine };
			final int len = array.length;

			for( int ii=0; ii<len; ii++ )
			{
				if( array[ii].contains(x,y) )
				{
					selectLine( array[ii] );
				}
			}

			ArrayList list = this.mActionListenerList;
			for( int ii=0; ii<list.size(); ii++ )
			{
				ActionListener l = (ActionListener)list.get(ii);
				l.actionPerformed( new ActionEvent( this, 0, "" ) );
			}

			this.repaint();
		}

		public void mousePressed( MouseEvent e )
		{
		}

		public void mouseReleased( MouseEvent e )
		{
		}

		public void mouseEntered( MouseEvent e )
		{
		}

		public void mouseExited( MouseEvent e )
		{
		}

		public void mouseMoved( MouseEvent e )
		{
			final int x = e.getX();
			final int y = e.getY();

			final Line[] array = { mTopLine, mBottomLine, mLeftLine, mRightLine };
			final int len = array.length;

			boolean b = false;
			for( int ii=0; ii<len; ii++ )
			{
				if( array[ii].contains(x,y) )
				{
					b = true;
					break;
				}
			}

			Cursor cur = null;			
			if(b)
			{
				cur = new Cursor( Cursor.HAND_CURSOR );
			}
			else
			{
				cur = Cursor.getDefaultCursor();
			}
			this.setCursor(cur);
		}

		public void mouseDragged( MouseEvent e )
		{
		}


		public boolean isTopSelected()
		{
			return mTopLine.isSelected();
		}

		public boolean isBottomSelected()
		{
			return mBottomLine.isSelected();
		}

		public boolean isLeftSelected()
		{
			return mLeftLine.isSelected();
		}

		public boolean isRightSelected()
		{
			return mRightLine.isSelected();
		}

		public void setTopSelected( final boolean b )
		{
			mTopLine.setSelected(b);
		}

		public void setBottomSelected( final boolean b )
		{
			mBottomLine.setSelected(b);
		}

		public void setLeftSelected( final boolean b )
		{
			mLeftLine.setSelected(b);
		}

		public void setRightSelected( final boolean b )
		{
			mRightLine.setSelected(b);
		}


		private ArrayList mActionListenerList = new ArrayList();

		public void addActionListener( final ActionListener l )
		{
			List list = this.mActionListenerList;
			for( int ii=0; ii<list.size(); ii++ )
			{
				final ActionListener el = (ActionListener)list.get(ii);
				if( el.equals(l) )
				{
					return;
				}
			}
			list.add(l);
		}

		public void removeActionListener( ActionListener l )
		{
			List list = this.mActionListenerList;
			for( int ii=list.size()-1; ii>=0; ii-- )
			{
				final ActionListener el = (ActionListener)list.get(ii);
				if( el.equals(l) )
				{
					list.remove(l);
				}
			}
		}

		public void dispose()
		{
			super.dispose();
			if( this.mActionListenerList!=null )
			{
				this.mActionListenerList.clear();
				this.mActionListenerList = null;
			}
		}
	}


	// The class of line drawn on the panel.
	protected static class Line extends Line2D.Float implements SGISelectable
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = -5656791063642132045L;
		private boolean mSelected = false;
		private float mLineWidth = 0.0f;
		private int mLocation = 0;
		
		protected Line( final float X1, final float Y1, final float X2, final float Y2)
		{
			super(X1,Y1,X2,Y2);
		}

		public boolean contains( final double x, final double y )
		{
			final float lw = 3.0f*LINE_WIDTH;
			return (this.ptLineDistSq(x,y)<lw*lw);
		}

		public boolean isSelected()
		{
			return this.mSelected;
		}

		public void setSelected( final boolean b )
		{
			this.mSelected = b;
			this.mLineWidth = b ? LINE_WIDTH : 1.0f;
		}

		public void setLocation( final int l )
		{
			this.mLocation = l;
		}
		
		protected void draw( Graphics2D g2d )
		{
			BasicStroke stroke = new BasicStroke(
					this.mLineWidth, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER );
			g2d.setStroke( stroke );
			g2d.draw(this);
			
			// draw tickmark
			final int TICKMARKSKIP = 5;
			final int TICKMARKLENGTH = 2;
			stroke = new BasicStroke(
					1.0f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER );
				g2d.setStroke( stroke );
			if( mSelected ){
				switch( mLocation ){
				case 0: /* top */
					for(int i = (int)x1; i < (int)x2; i += TICKMARKSKIP ){
						g2d.drawLine( i, (int)y1, i, (int)y1 + TICKMARKLENGTH );
					}
					break;
				case 1: /* buttom */
					for(int i = (int)x1; i < (int)x2; i += TICKMARKSKIP ){
						g2d.drawLine( i, (int)y1 - TICKMARKLENGTH - 1, i, (int)y1 );
					}
					break;
				case 2: /* Left */
					for(int i = (int)y1; i < (int)y2; i += TICKMARKSKIP ){
						g2d.drawLine( (int)x1, i, (int)x1 + TICKMARKLENGTH, i );
					}
					break;
				case 3: /* Right */
					for(int i = (int)y1; i < (int)y2; i += TICKMARKSKIP ){
						g2d.drawLine( (int)x1 - TICKMARKLENGTH - 1, i, (int)x1, i );
					}
					break;
				}
			}
		}

	}


}

