// Listing of client source code

/*
Author: Srikanta Patnaik and Team 
Machine Intelligence Laboratory, University College of Engineering, Burla, India
Date of Writing: April, 2003; Version: 1.0
Book: Robot Cognition and Navigation: An Experiment with Mobile Robots
Publisher: Springer
ISBN: 978-3-540-23446-3
URL: http://www.springer.com/3-540-23446-2
*/


// filename : Garbage.java
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import java.io.*;
import java.net.*;
import java.awt.event.*;
import java.awt.image.*;
import java.text.*;
import java.lang.*;
import java.util.*;

public class Garbage extends JFrame implements MouseListener,   
 		MouseMotionListener, ActionListener, ChangeListener
{
boolean flag1 = true;
boolean flagMouse = false;
boolean flagGo = false;
int tol=5,cTotal=10;
int iw=320,ih=240; // image dimensions
int pixels[] = new int[iw*ih]; // image pixels
int x1=0,x2=0,y1=0,y2=0; // initial coordiantess
double avg = 0.0,r_avg=0.0,b_avg=0.0,g_avg=0.0;
Container container=null;
ImageIcon icon;
Socket socket;

// for input and output streams of socket
InputStream input;
OutputStream output;
DataInputStream dis;
Image image=null,image1;
JButton b1,b2,b3,b4;
JSlider thSlider,cSlider;
JButton box;
ImageLabel lbl;

public Garbage(String title)
{
super(title);
		 
container = this.getContentPane();
container.setLayout(null);
		
addMouseListener(this);
addMouseMotionListener(this);

JLabel l;
	
// for Threshold slider
l = new JLabel("Threshold Value");
l.setBounds(470,350,100,20);
container.add(l);

// for min count slider
l = new JLabel("Min. Count Value");
l.setBounds(100,350,100,20);
container.add(l);

// for Box color
l = new JLabel("Box Color");
l.setBounds(300,340,70,20);
container.add(l);
		
// color box
box = new JButton();
box.setBounds(300,380,50,50);
box.setEnabled(false);
box.setBackground(Color.black);
container.add(box);

// threshold slider
thSlider = new JSlider(0,15);
thSlider.setPaintLabels(true);
thSlider.createStandardLabels(5);
thSlider.setValue(5);
thSlider.setMinorTickSpacing(1);
thSlider.setMajorTickSpacing(5);
thSlider.setPaintTicks(true);
thSlider.setBounds(420,380,200,50);
thSlider.addChangeListener(this);
container.add(thSlider);

// counter slider
cSlider = new JSlider(10,80);
cSlider.setPaintLabels(true);
cSlider.createStandardLabels(10);
cSlider.setValue(15);
cSlider.setMinorTickSpacing(5);
cSlider.setMajorTickSpacing(10);
cSlider.setPaintTicks(true);
cSlider.setBounds(50,380,200,50);
cSlider.addChangeListener(this);
container.add(cSlider);

// connection label
JLabel cLabel = new JLabel("Not Connected");
cLabel.setBounds(500,450,150,30);
container.add(cLabel);

// image button
b1 = new JButton("Get Image");
b1.setMnemonic('I');
b1.setBounds(40,290,110,25);
b1.addActionListener(this);
container.add(b1);

// color button
b2 = new JButton("Select Color");
b2.setMnemonic('C');
b2.setBounds(180,290,110,25);
b2.addActionListener(this);
container.add(b2);

// go button
b3 = new JButton("Go");
b3.setMnemonic('G');
b3.setBounds(380,290,110,25);
b3.addActionListener(this);
container.add(b3);

// Stop button
b4 = new JButton("Stop");
b4.setMnemonic('S');
b4.setBounds(520,290,110,25);
b4.addActionListener(this);
container.add(b4);

// for black image
for ( int i = 0 ; i < iw*ih ; i++ )
{
pixels[i] = (0xff000000|0<<16|0<<8|0);
}

icon = new ImageIcon();
// create image from pixels 
image = createImage(new MemoryImageSource(iw,ih,pixels,0,iw));
icon.setImage(image);
image1 = image;		
lbl = new ImageLabel();
lbl.setBounds(0,0,655,250);
container.add(lbl);

// opening the sockets
try
{
socket = new Socket("192.168.0.9",9990);
cLabel.setText("Connected to 192.168.0.9");
}
catch(UnknownHostException e)
{
System.out.println(e);
System.exit(ERROR);
}
catch(IOException e)
{
System.out.println(e);
System.exit(ERROR);
}
// opening their streams
try
{
socket.setTcpNoDelay(true);
output = socket.getOutputStream();
input = socket.getInputStream();
dis = new DataInputStream(socket.getInputStream());
}
catch(IOException e)
{
System.out.println(e);
}

// the window features being added
addWindowListener(new WindowEventHandler());
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setSize(659,500);
show();
	
activate(false,false,false,false);
getImageFromServer(); // gets the image
icon.setImage(image);
lbl.repaint();
try{
System.out.println(getString(input));
}catch(IOException er){}
activate(true,true,false,false);
	
String strToSend="";
double angle = 0.0;
while(true)
{
try
{
while(flagGo)
{
// gets image
getImageFromServer();				
icon.setImage(image);
lbl.repaint();			
// mapping done here
thresholding();
icon.setImage(image1);
lbl.repaint();

// finding k the angle
angle = getTheAngle();
strToSend = angle+"";

if ( !flagGo )
{
writeString(output,"STOP");
activate(false,false,true,false);
}
else
{
System.out.println(strToSend);
writeString(output,strToSend);
}
}		
}
catch(IOException err){}
}
}

// if slider value being changed	
public void stateChanged(ChangeEvent evt)
{
tol = thSlider.getValue();
cTotal = cSlider.getValue();
}

// activate the appropriate buttons
public void activate(boolean x1,boolean x2,boolean x3,boolean x4)
{
b1.setEnabled(x1);
b2.setEnabled(x2);
b3.setEnabled(x3);
b4.setEnabled(x4);
}
	
// the action performed function
public void actionPerformed(ActionEvent ae)
{
String s = ae.getActionCommand();
try{
if (s.equals("Go"))
{
activate(false,false,false,true);
writeString(output,"GO");
flagGo = true;
}
if (s.equals("Stop"))
{
flagGo = false;
}	
if (s.equals("Get Image"))
{
activate(false,false,false,false);
writeString(output,"IMAGE");
getImageFromServer();

icon.setImage(image);
lbl.repaint();
				
activate(true,true,false,false);
}
if (s.equals("Select Color"))
{
activate(false,false,false,false);
try
{
PixelGrabber gb = new PixelGrabber(image,0,0,iw,ih,pixels,0,iw);
gb.grabPixels();
}
catch (InterruptedException exp){}
flagMouse = true;
}
}
catch(IOException err){}
}

// function used for getting image from server
void getImageFromServer()
{
int c = 0,r = 0,g = 0,b = 0,x = 0,y=0;
while (true)
{
try
{
r =dis.read();
g =dis.read();
b =dis.read();
}
catch(Exception e){}
if((r==0)&&(g==0)&&(b==0))
{
y++;
if(y==240)
break;				
}
else
{
x=x%(iw*ih);
pixels[x] = (255<<24)|(r<<16)|(g<<8)|b;
x++;
}
if((r==-1)||(g==-1)||(b==-1))
break;
}
image = createImage(new MemoryImageSource(iw,ih,pixels,0,iw));
}

// finalizing funciton
void finalise()
{
try
{
socket.close();
}
catch(IOException e)
{
System.out.println(e);
}
}

// get the angle from the mapped iamges
double getTheAngle()
{
int count[] = new int[12];
int angle=45;
int temp;
// the angle array.
int arr[] = {15,0,0,-20,	35,0,0,-30,40,0,0,-35	};
for ( int i = 0 ; i < iw*ih ; i++ )
{
temp = (pixels[i])&0xff;
if ( temp == 0 )
{
int k = (i/320)/80*4+(i%320)/80;
count[k]++;
}
}

temp = 0;
for ( int i = 0 ; i < 12 ; i++ )
{ 
//finding maximum count 
if (temp < count[i] && count[i] > cTotal) 
{
angle = arr[i];
}
}
return angle;
}

// function for getting data from socket
private String getString(InputStream in) throws IOException
{
int c;
int pos =0;
byte buf[]= new byte[1024];
pos = in.read(buf);
if(pos<=0) return null;
String str = new String(buf,0,pos);
	
return str;
}

// function for writing data to socket
public void writeString(OutputStream o,String s) throws IOException
{
o.write(s.getBytes());
}

public void mouseClicked(MouseEvent e){}
public void mousePressed(MouseEvent e)
{
if (flagMouse && (e.getX()-5 < iw) && (e.getY()-24 < ih))
{
x1 = e.getX()-5;
y1 = e.getY()-24;
}
}	
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mouseDragged(MouseEvent e)
{
if (flagMouse)
{
x2 = e.getX()-5;
y2 = e.getY()-24;
lbl.repaint();
}
}
public void mouseMoved(MouseEvent e){}
// here the color of the box is selected
public void mouseReleased(MouseEvent e)
{
if (flagMouse && (e.getX()-5 < iw) && (e.getY()-24 < ih))
{
x2 = e.getX()-5;
y2 = e.getY()-24;
flagMouse = false; // check here
if (x1 > x2)
{
int temp = x1;
x1 = x2;
x2 = temp;
}
if ( y1 > y2)
{
int temp = y1;
y1 = y2;
y2 = temp;
}
	
// calculating the average values.RGB
int i,j,k;
int count=0;

for ( j = y1 ; j <= y2 ; j++ )
{
for ( i = x1 ; i <= x2 ; i++ )
{
k = j*iw+i;
int temp = pixels[k];
r_avg += (temp>>16)&0xff;
g_avg += (temp>>8)&0xff;
b_avg += (temp)&0xff;
count++;
}
}
r_avg /= count;
b_avg /= count;
g_avg /= count;

activate(true,false,true,false);
flagMouse = false;
thresholding(); // mapping
icon.setImage(image1);
lbl.repaint();
box.setBackground(new Color((int)r_avg,(int)g_avg,(int)b_avg));
}
}

// mapping color image into b/w image indicating the object
public void thresholding()
{
for ( int i = 0 ; i < ih*iw ; i++ )
{
int p = pixels[i];
int r = (p>>16)&0xff;
int g = (p>>8)&0xff;
int b = (p)&0xff;
if ( tolerance(r,r_avg) && tolerance(g,g_avg)  
&& tolerance(b,b_avg))
p = 0;// white
else
p = 255; //black
pixels[i] = (0xff000000|p<<16|p<<8|p);
}
image1 = createImage(new MemoryImageSource(iw,ih,pixels,0,iw));
}

// for the range of RGB
public boolean tolerance(int val,double avg)
{
if ( val > (int)(avg-tol) && val < (int)(avg +tol) )
return true;
else
return false;
}
// class for window features
class WindowEventHandler extends WindowAdapter
{
public void windowClosing(WindowEvent e)
{
flag1 = false;
try
{
writeString(output,"EXIT");
}
catch(IOException exc){}
System.exit(0);
}
}

// for main function
public static void main(String args[])
{
Garbage frame = new Garbage("Garbage Collector");
}
// for displaying the image
class ImageLabel extends JLabel
{
public ImageLabel(){	}
public void paint(Graphics g)
{
if (flagMouse) // image with out mouse clicking
{
g.drawImage(image,0,0,this);
g.setColor(Color.black);
g.drawRect(x1,y1,(x2-x1),(y2-y1));
}
else // image with mouse dragged
{
g.drawImage(image,0,0,this);
g.drawImage(image1,330,0,this);
g.setColor(Color.red);
g.drawRect(330,0,320,240);
g.drawLine(330,80,650,80);
g.drawLine(330,160,650,160);
g.drawLine(410,0,410,240);
g.drawLine(490,0,490,240);
g.drawLine(570,0,570,240);
}
}
}
}

