/* Zaznavanje 
   Postopek je naslednji:
	1. pritisnes Read
	2. pritisnes Invert po potrebi
	3. pritisnes Trig
	4. pritisnes Calc
*/

import java.awt.*;
import java.applet.*;
import java.awt.image.ColorModel;
import java.awt.image.MemoryImageSource;
import java.lang.InterruptedException;
import java.io.StreamTokenizer;
import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
import java.lang.Math;
import java.util.*;

public class RasterCalc extends Applet {
    RasterControls controls;
   
    public void init() {
        RasterCanvas canvas = new RasterCanvas();
      	setLayout(new BorderLayout());

	add("Center", canvas);
        add("South", controls = new RasterControls(canvas, getDocumentBase(),
		getAppletContext()));
	getAppletContext().showStatus("Press READ for start");

    }

    public void start() {
	controls.enable();
    }

    public void stop() {
	controls.disable();
    }

    public boolean handleEvent(Event e) {
	if (e.id == Event.WINDOW_DESTROY) {
	    System.exit(0);
	}
	return false;
    }

    public static void main(String args[]) {
        Frame f = new Frame("RasterCalc");
        RasterCalc RasterCalc = new RasterCalc();

        RasterCalc.init();
        RasterCalc.start();
        f.add("Center", RasterCalc);
	f.resize(400, 600);
	f.show();
    }
}
    
class RasterCanvas extends Canvas {
    Image img;
    int width, height;
    int histogram = 0, barva[] = new int[256] ;
    int working = 0;
    Font	font;
    int x1, x2, x3, x4, y1, y2, y3, y4, yCOG, xCOG,stp;
    float alfa, gl1, gl2;
    
    public void paint(Graphics g) {
	int w = size().width;
	int h = size().height;

        if(working > 0) {
 
           g.setColor(Color.black);
           g.drawString("Working...",140,150);
        }

	if (img != null) {
	   g.drawImage(img, 0, 0, width, height, this);
           working = 0;
	}

	g.setColor(Color.blue);
	g.drawLine(0, yCOG, width, yCOG);
        g.drawLine(xCOG, 0, xCOG, height);
        g.setColor(Color.red);
	g.drawLine(x1,y1,x2,y2);
        g.drawLine(x3,y3,x4,y4);
        int sx = 250;
        int sy = 10;
        g.setColor(Color.blue);
        g.drawString("xt = " + xCOG,sx,sy);
        g.drawString("yt = " + yCOG,sx,sy+14);
        g.drawString("alfa(deg) = " +alfa*180/Math.PI,sx,sy+28);
        g.drawString("I1 = " + gl1,sx,sy+42);
        g.drawString("I2 = " + gl2,sx,sy+56);
        g.drawString("A = " + stp,sx,sy+70);

	if( histogram == 1 ) {
            int i, max, offsetx, offsety ;
            float k ;
            offsetx = 50 ;
            offsety = 325 ;
            g.drawString( "(0)black", offsetx-15, offsety+15) ;
            g.drawString( "256(white)", offsetx+255, offsety+15);
            g.setColor(Color.blue);
            g.drawLine(offsetx-1,offsety+1,offsetx+256,offsety+1);
            for(int j = 1; j <= 32; j++) {
                g.setColor(Color.blue);     
                g.drawLine(50+j*8,327,50+j*8,323); 
                g.drawString( "pixels ",20,175);
                g.drawString("40",84,340);
                g.drawString("80",124,340);
                g.drawString("120",160,340);
                g.drawString("160",200,340);
                g.drawString("200",240,340);
                g.drawString("240",280,340);
            }
            g.setColor(Color.blue);
            g.drawLine(50,325,50,175);
            for(int l = 1; l <= 16; l++) {
                g.setColor(Color.blue);
                g.drawLine(48,165+l*10,52,165+l*10);
            }
            for(int p = 1; p <= 6; p++){
                g.setColor(Color.blue);
                g.drawLine(50+p*40,329,50+p*40,321);
            } 
            g.setColor(Color.red);
            for(i = 0;i < 256;i++){
                g.drawLine(offsetx+i,(int)(offsety-barva[i]),offsetx+i,offsety);
            }
	}       
    }
    public void setImage (int pixels[], int width, int height) {
        int pixelsARGB[] = new int[width*height];
	for (int i = 0; i < width*height; i++)
	    pixelsARGB[i] = (255 << 24) | (pixels[i] << 16) | (pixels[i] << 8) | pixels[i];
        img = createImage(new MemoryImageSource(width, height, pixelsARGB, 0, width));
	this.width = width;
	this.height = height;
        repaint();
    }

    public void setHistogram (int pixels[], int width, int height) {
	int i, m = 0;
	for(i = 0; i < 256; i++) barva[i] = 0;
	    for(i = 0; i < width * height; i++)
	        barva[pixels[i]]++;
                    for(i = 0; i < 256 ; i++ )
                        if( barva[i] > m ) m = barva[i]; 
                    for(i = 0; i < 256 ; i++ ) {
	                barva[i] *= 150;
	                barva[i] /= m;
	            }
	histogram = 1 ;
	repaint() ;
    }
    public void setCOG (int xCOG, int yCOG, float alfa, int stp,
                    float gl1, float gl2, int width, int height) {

        RasterCanvas.xCOG = xCOG;
        RasterCanvas.yCOG = yCOG;
        RasterCanvas.alfa = alfa;
        RasterCanvas.stp = stp;
        RasterCanvas.gl1 = gl1;
        RasterCanvas.gl2 = gl2;
        RasterCanvas.width = width;
        RasterCanvas.height = height;
        int r; 
     	r = (int)(height/2.0);
        x1=(int)(xCOG+r*Math.cos(alfa)); 
        y1=(int)(yCOG-r*Math.sin(alfa));
        x2=(int)(xCOG-r*Math.cos(alfa));
        y2=(int)(yCOG+r*Math.sin(alfa));
        x3=(int)(xCOG-r*Math.sin(alfa));
        y3=(int)(yCOG-r*Math.cos(alfa));
        x4=(int)(xCOG+r*Math.sin(alfa));
        y4=(int)(yCOG+r*Math.cos(alfa));
	repaint();
    }
}
class RasterControls extends Applet { 
    AppletContext master;
    TextField s;
    TextField e;
    Choice c;
    RasterCanvas canvas;
    URL documentBase;
    String modelName = "kljucki.txt";
    int width = 0;
    int height = 0;
    int pixels[] = null;

    public void loadSource(URL modelSource) { // Prebere datoteko modela podano z URL
        int token;
	try {
	   InputStream is = modelSource.openStream();
           StreamTokenizer st = new StreamTokenizer(is);
	   st.commentChar('#');

	   if ((token = st.nextToken()) != StreamTokenizer.TT_WORD
	       && st.sval != "P2" ) {
		master.showStatus("Error reading Portable Grey Map file");
	        return;
           }
	   

	   while ( (token = st.nextToken()) != StreamTokenizer.TT_EOF) {
	       if (token == StreamTokenizer.TT_NUMBER) {
                   width = (int)st.nval;
                   if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
                      height = (int)st.nval;
		      st.nextToken(); // preskocimo 255
		      pixels = new int [width*height];
	              int index = 0;
		      for (int j = 0; j < height; j++) {
                         for (int i = 0; i < width; i++) {
  			    if ( st.nextToken() == StreamTokenizer.TT_NUMBER) {
			       pixels[index++] = (int)st.nval;
	                    }
                         }
			 master.showStatus("Reading ... (" + 
			  (int)((float)(j+1)/(float)height*100) +"%)");
                      }
 		      break;
                   }
	       }
           }
	   is.close();
	} 
	  catch  ( IOException e ) {
	      System.out.println("An exception occurred: " + e.getMessage()); 
              e.printStackTrace(); 
          }
    }
    public void calculate() {
        float alfa, Ixy = 0, Ix = 0, Iy = 0, xt, yt, gl1, gl2;
        int x, y, xCOG, yCOG, rx, ry, stp = 0, xokn = 0, yokn = 0;
        System.out.println("racunam ");         
        for (y = 0; y < height; y++) {
            for (x = 0; x < width; x++) {
	        if(pixels[y*width + x] != 0) { 
  		    stp++;
                    xokn += x;
                    yokn += y;
                }
            }
        }     
	xCOG =xokn/stp;
     	yCOG =yokn/stp;
        for (y = 0; y < height; y++) {
            for (x = 0; x < width; x++) {
	        if(pixels[y*width + x] != 0) { 
                    ry=x-xCOG;
                    rx=y-yCOG;
                    Ix += ry*ry;
                    Iy +=rx*rx;
                    Ixy+=rx*ry;
                }
            }
        }              
	alfa=(float)(Math.atan2((double)(-2*Ixy),(double)(Ix-Iy))/2.0);
     	gl1 = (float)((Ix+Iy)/2+Math.sqrt(((Ix-Iy)/2)*((Ix-Iy)/2)+Ixy*Ixy));
     	gl2 = (float)((Ix+Iy)/2-Math.sqrt(((Ix-Iy)/2)*((Ix-Iy)/2)+Ixy*Ixy));
      	canvas.setCOG (xCOG, yCOG, alfa, stp, gl1, gl2, width, height);
    }

    public void edge(int pixels[], int width, int height) {       
        for (int i = 1; i < height - 1; i++) {
            for (int j = 1; j < width - 1; j++) {
                if ((pixels[i*width+j+1] & pixels[i*width+j-1]
		    & pixels[(i+1)*width+j] & pixels[(i-1)*width+j]) == 255)
		                                 pixels[i*width+j] = 0xffff;
            } 
 	}
	for (int i = 0; i < width * height; i++) 
	    if (pixels[i] > 255)
                pixels[i] = 0;
    }
    protected void makebutton(String name,GridBagLayout gridbag,
					GridBagConstraints z ) {
        Button button = new Button(name);
	gridbag.setConstraints(button, z);
	add(button);
    }   
    public RasterControls(RasterCanvas canvas, URL documentBase,
                          AppletContext master) {
        this.canvas = canvas;
	this.master = master;
        this.documentBase = documentBase;
        GridBagLayout gridbag = new GridBagLayout();
        GridBagConstraints z = new GridBagConstraints();
        setLayout(gridbag);
        z.fill = GridBagConstraints.HORIZONTAL;        
        z.weightx = 1.0;
        makebutton("Histogram",gridbag, z);
        s = new TextField("140", 4);
        gridbag.setConstraints(s, z);
	add(s);
        makebutton("Trig", gridbag, z);
        makebutton("Invert", gridbag, z);
        makebutton("Calc", gridbag, z); 
        z.gridwidth = GridBagConstraints.REMAINDER; 
        makebutton("Edge", gridbag, z);
        z.weightx = 1.0;
        z.gridwidth = 1;
        c = new Choice();
        c.addItem("kozarcek.pgm");
        c.addItem("kockica.pgm");
        c.addItem("kljucki.pgm");
        c.addItem("kocka.pgm");
        c.addItem("kozarec.pgm");
        c.addItem("pk.pgm");
        c.addItem("kljuci.pgm");
	gridbag.setConstraints(c, z);
        add(c);
        makebutton("Read", gridbag, z);
        z.gridwidth = 4;
        e = new TextField(" ", 12);
	gridbag.setConstraints(e, z);
	add(e);            
        z.gridwidth = GridBagConstraints.REMAINDER;
        makebutton("URL",gridbag, z);         
      
    }  

    public boolean action(Event ev, Object arg) {
        if (ev.target instanceof Button) {
	     String label = (String)arg;
	         if (label.equals("Read"))  {
		     try {
		         modelName = c.getSelectedItem().trim();  
		         URL source = new URL (documentBase, modelName);
			 e.setText(source.toString());
		         loadSource(source);
		     } catch  (  IOException e ) {
	    	         System.out.println("An exception occurred: " + e.getMessage()); 
            	         e.printStackTrace(); 
        	       }
		    canvas.setImage(pixels, width, height);
		    return true;
	        }

	         if (label.equals("URL"))  {
		     try {
		         modelName = e.getText().trim();  
		         URL source = new URL (modelName);
		         loadSource(source);
		     } catch  (  IOException e ) {
	    	         System.out.println("An exception occurred: " + e.getMessage()); 
            	         e.printStackTrace(); 
        	       }
		
		    canvas.setImage(pixels, width, height);
		    return true;
	        }

                if (label.equals("URL")) {
                    try {
		        modelName = e.getText().trim();
		        URL source = new URL (documentBase, modelName);
		        loadSource(source);
		    } catch  (  IOException e ) {
	    	        System.out.println("An exception occurred: " + e.getMessage()); 
            	        e.printStackTrace(); 
        	      }
	        } 
	        
	        if (label.equals("Invert")) {
		    for (int i = 0; i < width*height; i++)
		        pixels[i] = 255 - pixels[i];
		        canvas.setImage(pixels, width, height);
		        return true;
	        }

	        if (label.equals("Calc")) {
		    calculate();
		    return true;
	        }
	        if (label.equals("Edge")) {
		    edge(pixels, width, height);
		    canvas.setImage(pixels, width, height);
		    return true;
	        }

	        if (label.equals("Histogram")) {
		    canvas.setHistogram(pixels, width, height);
		    return true;
                }
            
	        if (label.equals("Trig")) {
		    int level = Integer.parseInt(s.getText().trim());
		        for (int i = 0; i < width*height; i++)
		            pixels[i] =  pixels[i] > level ? 255 : 0;
		            canvas.setImage(pixels, width, height);
		            return true;
	       }

	       return true;
	  }

	  return false;
     }
}
