import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
import javax.imageio.*;
import java.io.*;

// with thanks to: http://www.wikipedia.org/wiki/Wikipedia%3AASCII_art_conversion_tool

public class ASCIIArt {
	private final static char[] tiles = {
		'M', 'P', 'V', '"',
		'b', ')', '\\','\'',
		'd', '/', '(', '`',
		'a', '.', ',', ' '
	};
	
	private BufferedImage image = null;
	private int width, height;
	private int[] pixels = null;
	private int[] bits = null;
	private final StringBuffer buffer = new StringBuffer();
	
	private JFrame frame = null;
	private JLabel imageLabel = null;
	private JTextArea textArea = null;
	private JSlider slider = null;

	public static void threshold( int cutoff, int[] pixels, int[] bits ) {
		for ( int i = 0; i < pixels.length; i++ ) {
			int p = pixels[ i ];
			int r = (p & 0xFF0000) >> 16;
			int g = (p & 0xFF00) >> 8;
			int b = (p & 0xFF);
			bits[ i ] = (r+g+b)/3 < cutoff? 0 : 1; 
		}
	}

	public static void convertBitmap( int[] bits, int width, int height, StringBuffer asciiImage ) {
		int asciiIndex = 0;
		for ( int j = 0; j < height; j+=2 ) {
			int jWidth = j*width;
			for ( int i = 0; i < width; i += 2, asciiIndex++ ) {
				int c = 0;
				int b11 = bits[ jWidth + i ]; int b21 = bits[ jWidth + i + 1 ];
				int b12 = bits[ jWidth + width + i ]; int b22 = bits[ jWidth + width + i + 1 ];
				if ( b11 != 0 )
					c |= 8;
				if ( b21 != 0 )
					c |= 4;
				if ( b12 != 0 )
					c |= 2;
				if ( b22 != 0 )
					c |= 1;

				asciiImage.append( tiles[c] );
			}
			asciiImage.append( '\n' );
		}
	}

	public void changeThreshold( int threshold ) {
		if ( pixels != null ) {
			threshold( threshold, pixels, bits );
			buffer.setLength( 0 );
			convertBitmap( bits, width, height, buffer );
			textArea.setText( buffer.toString() );
		}
	}

	public void openImage() {
		JFileChooser fileChooser = new JFileChooser();
		int returnVal = fileChooser.showOpenDialog(frame);
		
		if ( returnVal == JFileChooser.APPROVE_OPTION ) {
			try {
				File file = fileChooser.getSelectedFile();
				image = ImageIO.read( file );
				imageLabel.setText( "" );
				imageLabel.setIcon( new ImageIcon( image ) );
				imageLabel.invalidate();
				
				width = image.getWidth();
				if ( width % 2 != 0 )
					width--;
				
				height = image.getHeight();
				if ( height % 2 != 0 )
					height--;
			
				pixels = new int[ width*height ];
				image.getRGB( 0, 0, width, height, pixels, 0, width );
				bits = new int[ pixels.length ];
				
				frame.validate();
				
				changeThreshold( slider.getValue() );
			}
			catch( Exception e ) {
				e.printStackTrace();
			}
		}
	}

	public void initGUI() {
		frame = new JFrame( "ASCII Art" );
		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		
		JMenuItem openFileItem = new JMenuItem( "Open Image..." );
		openFileItem.addActionListener(
			new ActionListener() {
				public void actionPerformed( ActionEvent ae ) {
					openImage();
				}			
			}
		 );
		
		JMenu fileMenu = new JMenu( "File" );
		/*fileMenu.addMenuListener( new MenuListener() {
			public void menuSelected( MenuEvent me ) {
				System.out.println( "Selected" );
			}
			
			public void menuDeselected( MenuEvent me ) {
				System.out.println( "Deselected" );
			}
						
			public void menuCanceled( MenuEvent me ) {
				System.out.println( "Canceled" );
			}
		} );*/
		
		JMenuBar menuBar = new JMenuBar();
		
		menuBar.add( fileMenu );
		fileMenu.add( openFileItem );
		
		frame.setJMenuBar( menuBar );
		
		slider = new JSlider( 0, 255, 128 );
		slider.addChangeListener( new ChangeListener() {
			public void stateChanged( ChangeEvent ce ) {
				changeThreshold( ((JSlider)ce.getSource()).getValue() );
			}
		} );
		
		textArea = new JTextArea( 100, 200 );
		textArea.setFont( new Font( "monospaced", Font.PLAIN, 4 ) );
		textArea.setEditable( false );
		
		JScrollPane textScrollPane = new JScrollPane(textArea);
		
		imageLabel = new JLabel( "<no image>" );
		imageLabel.setHorizontalAlignment( JLabel.CENTER );
		imageLabel.setVerticalAlignment( JLabel.CENTER );
		imageLabel.setVerticalTextPosition( JLabel.CENTER );
		imageLabel.setHorizontalTextPosition( JLabel.CENTER );
		
		JPanel panel = new JPanel( new GridLayout( 1, 2 ) );
		
		panel.add( imageLabel );
		panel.add( textScrollPane );
		
		frame.getContentPane().add( panel, BorderLayout.CENTER );
		frame.getContentPane().add( slider, BorderLayout.SOUTH );
		
		frame.pack();
		frame.setVisible( true );
	};

	public static void main( String[] args ) {
		(new ASCIIArt()).initGUI();
		/*try {
			String file = args.length != 0? args[ 0 ] : "wiki.png";
			BufferedImage image = ImageIO.read( new File( file ) );
			
			int width = image.getWidth();
			if ( width % 2 != 0 )
				width--;
				
			int height = image.getHeight();
			if ( height % 2 != 0 )
				height--;
			
			int[] pixels = new int[ width*height ];
			image.getRGB( 0, 0, width, height, pixels, 0, width );
			StringBuffer buffer = new StringBuffer( pixels.length +2*width );
			for ( int i = 0; i < pixels.length; i++ ) {
				int p = pixels[ i ];
				int r = (p & 0xFF0000) >> 16;
				int g =  (p & 0xFF00) >> 8;
				int b = p & 0xFF;
				p = ( r+ g+ b)/3;
				
				pixels[ i ] = p < 240? 0 : 1;
			}
			convertBitmap( pixels, width, height, buffer );
			
			System.out.println( buffer );
		}
		catch( Exception e ) {
			e.printStackTrace();
		}*/
	}

}

