package ip.raul;

import ip.gui.frames.OpenFrame;
import ip.gui.frames.ImageFrame;

import java.awt.*;
import java.awt.event.*;

public class GridImage extends OpenFrame
    implements ActionListener, MouseListener, MouseMotionListener {

  MenuBar mb = new MenuBar();
  Menu SettingsMenu = new Menu("Settings");

  MenuItem openGif_mi = addMenuItem(SettingsMenu, "[c]hange image...");
  MenuItem openFTPGif_mi = addMenuItem(SettingsMenu, "[C]hange image(FTP)...");
  MenuItem default_mi = addMenuItem(SettingsMenu, "[d]efault image");
  MenuItem revert_mi = addMenuItem(SettingsMenu, "[r]evert");
  MenuItem groff_mi = addMenuItem(SettingsMenu, "[g]rid on/off");
  MenuItem applyBilinear4Points_mi = addMenuItem(SettingsMenu, "[a]pplyBilinear4Points");

  public Polygon p = new Polygon();
  Image img = null;
  Color c = Color.black;
  boolean doRevert = false;
  short rn[][] = new short[0][0];
  short gn[][] = new short[0][0];
  short bn[][] = new short[0][0];
  int xPoints = 5; //grid X
  int yPoints = 5; //grid Y
  boolean busy = false;
  int groff = 1;
  int pointToMove = -1;
  MyFileDialog mf = null;


  public void actionPerformed(ActionEvent e) {
    try {
      Button b = (Button) e.getSource();
      if (b == mf.openButton) {
        getShortImage(mf.theFile);
        short2Image();
          setImageWidth(getR().length);
          setImageHeight(getR()[0].length);
          img = getImage();
        doRevert = true;
        p = new Polygon();
        init();
          setSize(getImageWidth(), getImageHeight());
        repaint();
      }
    } catch (Exception ex) {
    }

    if (match(e, applyBilinear4Points_mi)) {
      revert();
      applyBilinear();
      return;
    }
    if (match(e, revert_mi)) {
      revert1();
      return;
    }
    if (match(e, groff_mi)) {
      groff = 1 - groff;
      repaint();
      return;
    }

    if (match(e, openGif_mi)) {
      openGif1();
      return;
    }

    if (match(e, openFTPGif_mi)) {
      openFTPGif();
      return;
    }

    if (match(e, default_mi)) {
      default1();
      return;
    }

    super.actionPerformed(e);
  }

  GridImage(String title, Color Clr) {
    super(title);
    default1();
    c = Clr;
    addMouseListener(this);
    addMouseMotionListener(this);
    mb.add(SettingsMenu);
    setMenuBar(mb);
    repaint();
  }

  private void init() {
    groff = 1;
    for (int i = 0; i <= yPoints; i++)
      for (int j = 0; j <= xPoints; j++) p.addPoint((int) (j * getImageWidth() / xPoints), (int) (i * getImageHeight() / yPoints));
    groff = 0;
  }


  private void openGif1() {
    openGif();
    img = getImage();
    doRevert = true;
    p = new Polygon();
    init();
      setSize(getImageWidth(), getImageHeight());
    repaint();
  }

  private void openFTPGif() {
    mf = new MyFileDialog(this);
    mf.show();
    mf.openButton.addActionListener(this);
  }

  public void revert1() {
    revert();
    img = getImage();
    doRevert = true;
    p = new Polygon();
    init();
      setSize(getImageWidth(), getImageHeight());
    repaint();
  }

  public void default1() {
    grabNumImage();
    show();
      setSize(getImageWidth(), getImageHeight());
    img = getImage();
    doRevert = true;
    p = new Polygon();
    init();
  }

  public static void main(String args[]) {
    GridImage af = new GridImage(
        "GridImage", Color.green);
    af.setSize(150, 150);
    af.setVisible(true);
    af.default1();
  }


  public void setGrid(int x, int y) {
    xPoints = x;
    yPoints = y;
    revert1();
  }

  public void update(Graphics g) {
    paint(g);
  }


  public void paint(Graphics g) {
    if (img == null) return;
    if (doRevert) {
      if ((img != null)) g.drawImage(img, 0, 0, getImageWidth(), getImageHeight(), this);
    }
    g.setColor(c);
    if (groff == 0) {
      for (int i = 0; i <= yPoints; i++)
        for (int j = 0; j <= xPoints; j++) {
          if (j != (xPoints))
            g.drawLine(p.xpoints[j + i * (xPoints + 1)],
                       p.ypoints[j + i * (xPoints + 1)],
                       p.xpoints[j + 1 + i * (xPoints + 1)],
                       p.ypoints[j + 1 + i * (xPoints + 1)]);
          if (i != (yPoints))
            g.drawLine(p.xpoints[j + i * (xPoints + 1)],
                       p.ypoints[j + i * (xPoints + 1)],
                       p.xpoints[j + (i + 1) * (xPoints + 1)],
                       p.ypoints[j + (i + 1) * (xPoints + 1)]);
        }
      for (int i = 0; i < p.npoints; i++)
        g.drawRect(p.xpoints[i] - 2, p.ypoints[i] - 2, 4, 4);
    }
  }

  public void applyBilinear() {
      rn = new short[getImageWidth()][getImageHeight()];
      gn = new short[getImageWidth()][getImageHeight()];
      bn = new short[getImageWidth()][getImageHeight()];
    Point s0,s1,s2,s3,d0,d1,d2,d3;

    for (int i = 0; i < yPoints; i++)
      for (int j = 0; j < xPoints; j++) {
          s0 = new Point((int) (j * getImageWidth() / xPoints), (int) (i * getImageHeight() / yPoints));
          s1 = new Point((int) ((j + 1) * getImageWidth() / xPoints), (int) (i * getImageHeight() / yPoints));
          s2 = new Point((int) ((j + 1) * getImageWidth() / xPoints), (int) ((i + 1) * getImageHeight() / yPoints));
          s3 = new Point((int) (j * getImageWidth() / xPoints), (int) ((i + 1) * getImageHeight() / yPoints));
        d0 = new Point(p.xpoints[j + i * (xPoints + 1)], p.ypoints[j + i * (xPoints + 1)]);
        d1 = new Point(p.xpoints[j + 1 + i * (xPoints + 1)], p.ypoints[j + 1 + i * (xPoints + 1)]);
        d2 = new Point(p.xpoints[j + 1 + (i + 1) * (xPoints + 1)], p.ypoints[j + 1 + (i + 1) * (xPoints + 1)]);
        d3 = new Point(p.xpoints[j + (i + 1) * (xPoints + 1)], p.ypoints[j + (i + 1) * (xPoints + 1)]);
        solve(s0, s1, s2, s3, d0, d1, d2, d3);
      }
    setR(rn);
    setG(gn);
    setB(bn);
    short2Image();
    img = getImage();
  }

  int Dist(Point a, Point b) {
    return (int) (Math.sqrt(((b.x - a.x) * (b.x - a.x)) + ((b.y - a.y) * (b.y - a.y))));
  }

  public void solve(Point s0, Point s1, Point s2, Point s3, Point d0, Point d1, Point d2, Point d3) {
    double xStart1, xEnd1,yStart1, yEnd1;
    double xStart2, xEnd2,yStart2, yEnd2;
    double k = 0;
    int MAX = 0;
    int MAX1 = 0;
    int xc, yc, xp, yp;

    MAX = Dist(d0, d1);
    MAX1 = Dist(d1, d2);
    if (MAX1 > MAX) MAX = MAX1;
    MAX1 = Dist(d2, d3);
    if (MAX1 > MAX) MAX = MAX1;
    MAX1 = Dist(d3, d0);
    if (MAX1 > MAX) MAX = MAX1;

    MAX1 = Dist(s0, s1);
    if (MAX1 > MAX) MAX = MAX1;
    MAX1 = Dist(s1, s2);
    if (MAX1 > MAX) MAX = MAX1;
    MAX1 = Dist(s2, s3);
    if (MAX1 > MAX) MAX = MAX1;
    MAX1 = Dist(s3, s0);
    if (MAX1 > MAX) MAX = MAX1;
    MAX = MAX + 1;

    for (int i = 0; i <= MAX; i++) {
      k = (double) ((double) i / (double) MAX);

      xStart1 = linearY(d0.x, d3.x, k);
      yStart1 = linearY(d0.y, d3.y, k);
      xEnd1 = linearY(d1.x, d2.x, k);
      yEnd1 = linearY(d1.y, d2.y, k);

      xStart2 = linearY(s0.x, s3.x, k);
      yStart2 = linearY(s0.y, s3.y, k);
      xEnd2 = linearY(s1.x, s2.x, k);
      yEnd2 = linearY(s1.y, s2.y, k);

      for (int j = 0; j <= MAX; j++) {
        k = (double) ((double) j / (double) MAX);
        xc = (int) (linearY(xStart1, xEnd1, k));
        yc = (int) (linearY(yStart1, yEnd1, k));

        xp = (int) (linearY(xStart2, xEnd2, k));
        yp = (int) (linearY(yStart2, yEnd2, k));

          if ((xp < getImageWidth()) && (yp < getImageHeight()) && (xp >= 0) && (yp >= 0) &&
            (xc < getImageWidth()) && (yc < getImageHeight()) && (xc >= 0) && (yc >= 0)) {
          rn[xc][yc] = getR()[xp][yp];
          gn[xc][yc] = getG()[xp][yp];
          bn[xc][yc] = getB()[xp][yp];
        }
      }
    }
  }


  double linearY(double x1, double x2, double t) {
    double dx = 0;
    dx = (double) (x2 - x1);
    return (double) (x1 + (double) (dx * t));
  }

  public void movePoints(MouseEvent e) {
    int i = pointToMove;
    p.xpoints[i] = getX(e);
    p.ypoints[i] = getY(e);
    repaint();
  }

  private int getX(MouseEvent e) {
    return (int) (e.getX());
  }

  private int getY(MouseEvent e) {
    return (int) (e.getY());
  }

  public void mousePressed(MouseEvent e) {
  }

  public void mouseExited(MouseEvent e) {
  }

  public void mouseEntered(MouseEvent e) {
  }

  public void mouseClicked(MouseEvent e) {
  }

  public void mouseReleased(MouseEvent e) {
    busy = false;
    repaint();
  }

  public void mouseDragged(MouseEvent e) {
    e.consume();
    double dx = getX(e);
    double dy = getY(e);
    double sx, sy;
    double ray = 100000;
    if (!busy) {
      busy = true;
      pointToMove = -1;
      for (int i = 0; i < p.npoints; i++) {
        sx = (p.xpoints[i] - dx) * (p.xpoints[i] - dx);
        sy = (p.ypoints[i] - dy) * (p.ypoints[i] - dy);
        if ((sx + sy) < ray) {
          ray = sx + sy;
          pointToMove = i;
        }
      }
    }
    if (pointToMove != -1) {
      movePoints(e);
      return;
    }
    repaint();
  }

  public void mouseMoved(MouseEvent e) {
  }
}