package ditherapplet;

import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.*;
import java.awt.image.*;
import com.borland.jbcl.layout.*;
import javax.swing.event.*;

public class Dither extends Applet {

  MediaTracker tracker;
  Image picard;
  int selectionStyle=0;
  final int NUMSTYLES=7;
  int ditherType=0;
  int randomDitherFlag=0;


  private boolean isStandalone = false;
  String filename;
  BorderLayout borderLayout1 = new BorderLayout();
  JPanel filnamePanel = new JPanel();
  JPanel buttonPanel = new JPanel();
  JPanel drawingPanel = new JPanel();
  BorderLayout borderLayout2 = new BorderLayout();
  JPanel sliderpanel = new JPanel();
  VerticalFlowLayout verticalFlowLayout1 = new VerticalFlowLayout();
  JPanel jPanel1 = new JPanel();
  JSlider cuttoffSlider1 = new JSlider();
  JSlider cutoffSlider2 = new JSlider();
  JSlider cutoffSlider3 = new JSlider();
  JSlider cutoffSlider4 = new JSlider();
  JLabel jLabel1 = new JLabel();
  JPanel jPanel2 = new JPanel();
  JLabel lightGrayLabel = new JLabel();
  JLabel blackLabel = new JLabel();
  JLabel grayLabel = new JLabel();
  JLabel darkGrayLabel = new JLabel();
  VerticalFlowLayout verticalFlowLayout2 = new VerticalFlowLayout();
  JButton ditherButton = new JButton();
  JCheckBox randomDitherjCheckBox = new JCheckBox();
  JLabel fileLabel = new JLabel();
  BorderLayout borderLayout3 = new BorderLayout();
  //Get a parameter value
  public String getParameter(String key, String def) {
    return isStandalone ? System.getProperty(key, def) :
      (getParameter(key) != null ? getParameter(key) : def);
  }

  public void paint(Graphics g){
    super.paint(g);
    drawDithering(null);
  }

  private void drawDithering(ActionEvent e){

    if(e!=null){
      ditherType++;
      if(ditherType==0)
        ditherButton.setText("Dither Type: Top Left");
      else if(ditherType==1)
        ditherButton.setText("Dither Type: Average");
      else{
        ditherType=0;
        ditherButton.setText("Dither Type: Top Left");
      }
    }

    BufferedImage copy = new BufferedImage(picard.getWidth(null),picard.getHeight(null),BufferedImage.TYPE_BYTE_GRAY);
    BufferedImage copy2 = new BufferedImage(picard.getWidth(null),picard.getHeight(null),BufferedImage.TYPE_INT_RGB);
    copy2.getGraphics().drawImage(picard,0,0,null);
    copy.getGraphics().drawImage(picard,0,0,null);
    int rand1=0,rand2=0,rand3=0;

    int rgba=0;
    int red;
    int green;
    int blue;
    int alpha=255;
    float gray=0;
    int count=1;
    for(int i=0;i<picard.getWidth(null);i+=2)
      for(int j=0;j<picard.getHeight(null);j+=2){
        // (1) decoding
        if(ditherType==0){//topleft
          rgba = copy2.getRGB(i, j);
          red = (rgba >> 16) & 0xff;
          green = (rgba >> 8) & 0xff;
          blue = rgba & 0xff;
          alpha = (rgba >> 24) & 0xff;
          gray = (red+green+blue)/3;
        }

        else{//average
          gray=0;


          for(int k=0;k<2;k++){
            for(int l=0;l<2;l++){
              if(i+k<picard.getWidth(null)){
                if(j+l<picard.getHeight(null)) {
                  rgba = copy2.getRGB(i + k, j + l);
                  red = (rgba >> 16) & 0xff;
                  green = (rgba >> 8) & 0xff;
                  blue = rgba & 0xff;
                  alpha = (rgba >> 24) & 0xff;
                  gray += (red + green + blue) / 3;
                  count++;
                }
              }
            }
          }


          gray=gray/count;
          count=0;
        }


        if(gray<cuttoffSlider1.getValue()){//if it's in our black range
          copy2.setRGB(i, j, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
          if((i+1)<picard.getWidth(null))
             if((j+1)<picard.getHeight(null)){
               copy2.setRGB(i+1, j+1, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
               copy2.setRGB(i+1, j, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
               copy2.setRGB(i, j+1, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
             }
        }
        else if(gray<cuttoffSlider1.getValue()+cutoffSlider2.getValue()){//a little lighter
          if(randomDitherFlag==1)
            rand1=(int)(Math.random()*4);
          else
            rand1=(rand1++)%4;
          if(rand1==0){
            copy2.setRGB(i, j, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
            if ( (i + 1) < picard.getWidth(null))
              if ( (j + 1) < picard.getHeight(null)) {
                copy2.setRGB(i + 1, j + 1,
                             (alpha << 24) | (255 << 16) | (255 << 8) | 255);
                copy2.setRGB(i + 1, j, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
                copy2.setRGB(i, j + 1, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
              }
          }
          else if(rand1==1){
            copy2.setRGB(i, j, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
            if ( (i + 1) < picard.getWidth(null))
              if ( (j + 1) < picard.getHeight(null)) {
                copy2.setRGB(i + 1, j + 1,
                             (alpha << 24) | (0 << 16) | (0 << 8) | 0);
                copy2.setRGB(i + 1, j, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
                copy2.setRGB(i, j + 1, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
              }
          }
          else if(rand1==2){
            copy2.setRGB(i, j, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
            if ( (i + 1) < picard.getWidth(null))
              if ( (j + 1) < picard.getHeight(null)) {
                copy2.setRGB(i + 1, j + 1,
                             (alpha << 24) | (0 << 16) | (0 << 8) | 0);
                copy2.setRGB(i + 1, j, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
                copy2.setRGB(i, j + 1, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
              }
          }
          else{
            copy2.setRGB(i, j, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
            if ( (i + 1) < picard.getWidth(null))
              if ( (j + 1) < picard.getHeight(null)) {
                copy2.setRGB(i + 1, j + 1,
                             (alpha << 24) | (0 << 16) | (0 << 8) | 0);
                copy2.setRGB(i + 1, j, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
                copy2.setRGB(i, j + 1, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
              }
          }

        }
        else if(gray<cuttoffSlider1.getValue()+cutoffSlider2.getValue()+cutoffSlider3.getValue()){//half way
          if(randomDitherFlag==1)
            rand2=(int)(Math.random()*6);
          else
            rand2=(rand2++)%6;

          if(rand2==0){
            copy2.setRGB(i, j, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
            if ( (i + 1) < picard.getWidth(null))
              if ( (j + 1) < picard.getHeight(null)) {
                copy2.setRGB(i + 1, j + 1,
                             (alpha << 24) | (0 << 16) | (0 << 8) | 0);
                copy2.setRGB(i + 1, j, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
                copy2.setRGB(i, j + 1, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
              }
          }
          else if(rand2==1){
            copy2.setRGB(i, j, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
            if ( (i + 1) < picard.getWidth(null))
              if ( (j + 1) < picard.getHeight(null)) {
                copy2.setRGB(i + 1, j + 1,
                             (alpha << 24) | (255 << 16) | (255 << 8) | 255);
                copy2.setRGB(i + 1, j,
                             (alpha << 24) | (255 << 16) | (255 << 8) | 255);
                copy2.setRGB(i, j + 1, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
              }
          }
          else if(rand2==2){
            copy2.setRGB(i, j, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
            if ( (i + 1) < picard.getWidth(null))
              if ( (j + 1) < picard.getHeight(null)) {
                copy2.setRGB(i + 1, j + 1,
                             (alpha << 24) | (255 << 16) | (255 << 8) | 255);
                copy2.setRGB(i + 1, j,
                             (alpha << 24) | (0 << 16) | (0 << 8) | 0);
                copy2.setRGB(i, j + 1, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
              }
          }
          else if(rand2==3){
            copy2.setRGB(i, j, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
            if ( (i + 1) < picard.getWidth(null))
              if ( (j + 1) < picard.getHeight(null)) {
                copy2.setRGB(i + 1, j + 1,
                             (alpha << 24) | (0 << 16) | (0 << 8) | 0);
                copy2.setRGB(i + 1, j,
                             (alpha << 24) | (0 << 16) | (0 << 8) | 0);
                copy2.setRGB(i, j + 1, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
              }
          }

          else if(rand2==4){
            copy2.setRGB(i, j, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
            if ( (i + 1) < picard.getWidth(null))
              if ( (j + 1) < picard.getHeight(null)) {
                copy2.setRGB(i + 1, j + 1,
                             (alpha << 24) | (0 << 16) | (0 << 8) | 0);
                copy2.setRGB(i + 1, j,
                             (alpha << 24) | (255 << 16) | (255 << 8) | 255);
                copy2.setRGB(i, j + 1, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
              }
          }

          else{
            copy2.setRGB(i, j, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
            if ( (i + 1) < picard.getWidth(null))
              if ( (j + 1) < picard.getHeight(null)) {
                copy2.setRGB(i + 1, j + 1,
                             (alpha << 24) | (255 << 16) | (255 << 8) | 255);
                copy2.setRGB(i + 1, j,
                             (alpha << 24) | (0 << 16) | (0 << 8) | 0);
                copy2.setRGB(i, j + 1, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
              }
          }


        }

        else if(gray<cuttoffSlider1.getValue()+cutoffSlider2.getValue()+cutoffSlider3.getValue()+cutoffSlider4.getValue()){//a little dark
          if(randomDitherFlag==1)
            rand3=(int)(Math.random()*4);
          else
            rand3=(rand3++)%4;
          if(rand3==0){
            copy2.setRGB(i, j, (alpha << 24) | (0 << 16) | (0 << 8) | 0);
            if ( (i + 1) < picard.getWidth(null))
              if ( (j + 1) < picard.getHeight(null)) {
                copy2.setRGB(i + 1, j + 1,
                             (alpha << 24) | (255 << 16) | (255 << 8) | 255);
                copy2.setRGB(i + 1, j,
                             (alpha << 24) | (255 << 16) | (255 << 8) | 255);
                copy2.setRGB(i, j + 1,
                             (alpha << 24) | (255 << 16) | (255 << 8) | 255);
              }
          }
          else if(rand3==1){
            copy2.setRGB(i, j, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
            if ( (i + 1) < picard.getWidth(null))
              if ( (j + 1) < picard.getHeight(null)) {
                copy2.setRGB(i + 1, j + 1,
                             (alpha << 24) | (0 << 16) | (0 << 8) | 0);
                copy2.setRGB(i + 1, j,
                             (alpha << 24) | (255 << 16) | (255 << 8) | 255);
                copy2.setRGB(i, j + 1,
                             (alpha << 24) | (255 << 16) | (255 << 8) | 255);
              }
          }

          else if(rand3==2){
            copy2.setRGB(i, j, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
            if ( (i + 1) < picard.getWidth(null))
              if ( (j + 1) < picard.getHeight(null)) {
                copy2.setRGB(i + 1, j + 1,
                             (alpha << 24) | (255 << 16) | (255 << 8) | 255);
                copy2.setRGB(i + 1, j,
                             (alpha << 24) | (0 << 16) | (0 << 8) | 0);
                copy2.setRGB(i, j + 1,
                             (alpha << 24) | (255 << 16) | (255 << 8) | 255);
              }
          }

          else if(rand3==3){
            copy2.setRGB(i, j, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
            if ( (i + 1) < picard.getWidth(null))
              if ( (j + 1) < picard.getHeight(null)) {
                copy2.setRGB(i + 1, j + 1,
                             (alpha << 24) | (255 << 16) | (255 << 8) | 255);
                copy2.setRGB(i + 1, j,
                             (alpha << 24) | (255 << 16) | (255 << 8) | 255);
                copy2.setRGB(i, j + 1,
                             (alpha << 24) | (0 << 16) | (0 << 8) | 0);
              }
          }


        }

        else{//white
          copy2.setRGB(i, j, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
          if((i+1)<picard.getWidth(null))
             if((j+1)<picard.getHeight(null)){
               copy2.setRGB(i+1, j+1, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
               copy2.setRGB(i+1, j, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
               copy2.setRGB(i, j+1, (alpha << 24) | (255 << 16) | (255 << 8) | 255);
             }
        }

        // (2) now modify red, green, blue and alpha as you like;
        //     make sure that each of the four values stays in the
        //     interval 0 to 255
        //        ...
        // (3) and encode back to an int, e.g. to give it to MemoryImageSource or
        //     BufferedImage.setRGB
//        rgba = (alpha << 24) | (red << 16) | (green << 8) | blue;


//        copy.setRGB(i, j, rgba);

      }

    drawingPanel.getGraphics().drawImage(copy2,0,0,null);

  }

  //Construct the applet
  public Dither() {
  }
  //Initialize the applet
  public void init() {
    try {
      filename = this.getParameter("param0", "");
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
  //Component initialization
  private void jbInit() throws Exception {
    this.setSize(new Dimension(400,400));
    this.setLayout(borderLayout1);

    tracker = new MediaTracker(this);

    if(filename==null)
      filename="seanlucsmil.jpg";
    if(filename=="")
      filename="seanlucsmil.jpg";


    fileLabel.setText("File: "+filename);

    picard = Toolkit.getDefaultToolkit().createImage(Dither.class.getResource(filename));
    tracker.addImage(picard, 1);
    tracker.waitForAll();

    drawingPanel.setLayout(borderLayout2);
    sliderpanel.setLayout(verticalFlowLayout1);
    cuttoffSlider1.setOrientation(JSlider.VERTICAL);
    cuttoffSlider1.addChangeListener(new ChangeListener(){
    public void stateChanged(ChangeEvent e){
    drawDithering(null);
    blackLabel.setText("Black Cut Off: " + cuttoffSlider1.getValue());
    darkGrayLabel.setText("Dark Gray Cut Off: " + (cuttoffSlider1.getValue()+cutoffSlider2.getValue()));
    grayLabel.setText("Gray Cut Off: " + (cuttoffSlider1.getValue()+cutoffSlider2.getValue()+cutoffSlider3.getValue()));
    lightGrayLabel.setText("Light Gray Cut Off: " + (cuttoffSlider1.getValue()+cutoffSlider2.getValue()+cutoffSlider3.getValue()+cutoffSlider4.getValue()));
  }
});

    cutoffSlider2.setOrientation(JSlider.VERTICAL);
    cutoffSlider2.addChangeListener(new ChangeListener(){
      public void stateChanged(ChangeEvent e){
        drawDithering(null);
        darkGrayLabel.setText("Dark Gray Cut Off: " + (cuttoffSlider1.getValue()+cutoffSlider2.getValue()));
        grayLabel.setText("Gray Cut Off: " + (cuttoffSlider1.getValue()+cutoffSlider2.getValue()+cutoffSlider3.getValue()));
        lightGrayLabel.setText("Light Gray Cut Off: " + (cuttoffSlider1.getValue()+cutoffSlider2.getValue()+cutoffSlider3.getValue()+cutoffSlider4.getValue()));
      }
    });

    cutoffSlider3.setOrientation(JSlider.VERTICAL);
    cutoffSlider3.addChangeListener(new ChangeListener(){
      public void stateChanged(ChangeEvent e){
        drawDithering(null);
        grayLabel.setText("Gray Cut Off: " + (cuttoffSlider1.getValue()+cutoffSlider2.getValue()+cutoffSlider3.getValue()));
        lightGrayLabel.setText("Light Gray Cut Off: " + (cuttoffSlider1.getValue()+cutoffSlider2.getValue()+cutoffSlider3.getValue()+cutoffSlider4.getValue()));
      }
    });


    cutoffSlider4.setOrientation(JSlider.VERTICAL);
    cutoffSlider4.addChangeListener(new ChangeListener(){
      public void stateChanged(ChangeEvent e){
        drawDithering(null);
        lightGrayLabel.setText("Light Gray Cut Off: " + (cuttoffSlider1.getValue()+cutoffSlider2.getValue()+cutoffSlider3.getValue()+cutoffSlider4.getValue()));
      }
    });
    jLabel1.setPreferredSize(new Dimension(34, 15));
    jLabel1.setRequestFocusEnabled(true);
    jLabel1.setHorizontalAlignment(SwingConstants.CENTER);
    jLabel1.setHorizontalTextPosition(SwingConstants.CENTER);
    jLabel1.setText("Dithering Tolerences");
    lightGrayLabel.setText("Light Gray Cut Off: 200");
    blackLabel.setText("Black Cut Off: 50");
    grayLabel.setText("Gray Label Cut Off: 150");
    darkGrayLabel.setText("Dark Gray Cut Off: 100");
    jPanel2.setLayout(verticalFlowLayout2);
    ditherButton.setText("Dither Type: Top Left");
    ditherButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        drawDithering(e);
      }
    });
    randomDitherjCheckBox.setSelected(false);
    randomDitherjCheckBox.setText("Random Seed Dither");
    randomDitherjCheckBox.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        randomDitherjCheckBox_actionPerformed(e);
      }
    });
    fileLabel.setHorizontalAlignment(SwingConstants.LEFT);
    fileLabel.setHorizontalTextPosition(SwingConstants.LEFT);
    filnamePanel.setLayout(borderLayout3);
    this.add(filnamePanel, BorderLayout.NORTH);
    filnamePanel.add(fileLabel, BorderLayout.CENTER);
    this.add(buttonPanel, BorderLayout.SOUTH);
    buttonPanel.add(ditherButton, null);
    this.add(drawingPanel, BorderLayout.CENTER);
    drawingPanel.add(sliderpanel, BorderLayout.EAST);
    sliderpanel.add(jLabel1, null);
    sliderpanel.add(jPanel1, null);
    jPanel1.add(cuttoffSlider1, null);
    jPanel1.add(cutoffSlider2, null);
    jPanel1.add(cutoffSlider3, null);
    jPanel1.add(cutoffSlider4, null);
    sliderpanel.add(jPanel2, null);
    jPanel2.add(blackLabel, null);
    jPanel2.add(darkGrayLabel, null);
    jPanel2.add(grayLabel, null);
    jPanel2.add(lightGrayLabel, null);

    buttonPanel.add(randomDitherjCheckBox, null);
  }
  //Get Applet information
  public String getAppletInfo() {
    return "Applet Information";
  }
  //Get parameter info
  public String[][] getParameterInfo() {
    String[][] pinfo =
      {
      {"param0", "String", ""},
      };
    return pinfo;
  }

  void randomDitherjCheckBox_actionPerformed(ActionEvent e) {
    randomDitherFlag++;
    if(randomDitherFlag>1)
      randomDitherFlag=0;
    drawDithering(null);
  }
}