/*
 * Copyright (c) 2010-2020, sikuli.org, sikulix.com - MIT license
 */
package org.sikuli.ide;

import org.sikuli.basics.Debug;
import org.sikuli.basics.FileManager;
import org.sikuli.script.Image;
import org.sikuli.script.Location;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.text.Element;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Locale;

public class EditorPatternLabel extends EditorRegionLabel {

  public static String CAPTURE = "__CLICK-TO-CAPTURE__";
  public static String NOTFOUND = "!? ";
  private String lblText;
  private EditorPane pane;
  private double sim;
  private float resizeFactor;
  private String mask;
  private Location off;
  private String imgName = null;
  private String imgNameShort = null;
  private String imgFile;
  private Image image;
  private JFrame imgpop = null;
  private boolean onImagePath = true;
  private boolean isFromCapture;
  private Border pbrd = BorderFactory.createEmptyBorder(5, 5, 5, 5);
  private Border ibrd = BorderFactory.createLineBorder(Color.BLACK);
  private Border brd = BorderFactory.createCompoundBorder(pbrd, ibrd);
//TODO clickToShow: make a user pref
  private boolean clickToShow = false;

  private SikuliIDEPopUpMenu popMenu = null;
  private boolean wasPopup = false;

  public EditorPatternLabel(EditorPane parentPane, String str) {
    super(parentPane, str);
    initLabel(parentPane);
  }

  public EditorPatternLabel(EditorPane parentPane, String str, boolean fromCapture) {
    super(parentPane, str);
    isFromCapture = fromCapture;
    initLabel(parentPane);
  }

  public EditorPatternLabel(EditorPane parentPane, String str, String oldString) {
    super(parentPane, str, oldString);
    isFromCapture = true;
    initLabel(parentPane);
  }

  public EditorPatternLabel(EditorPane parentPane, EditorPatternButton btn) {
    super(parentPane, btn.toString());
    initLabel(parentPane);
  }

  private void initLabel(EditorPane parentPane) {
    pane = parentPane;
    sim = 0.7;
    off = new Location(0, 0);
    resizeFactor = 0;
    mask = "";
    if ("".equals(pyText)) {
      lblText = CAPTURE;
      pyText = "\"" + lblText + "\"";
    } else if (pyText.startsWith("Pattern")) {
      String[] tokens = pyText.split("\\)\\s*\\.?");
      for (String tok : tokens) {
        //System.out.println("token: " + tok);
        if (tok.startsWith("exact")) {
          sim = 0.99;
        } else if (tok.startsWith("Pattern")) {
          setFileNames(tok.substring(tok.indexOf("\"") + 1, tok.lastIndexOf("\"")));
          if (lblText == null) {
            break;
          }
        } else if (tok.startsWith("similar")) {
          String strArg = tok.substring(tok.lastIndexOf("(") + 1);
          try {
            sim = Double.parseDouble(strArg);
          } catch (NumberFormatException e) {
            sim = 0.7;
          }
        } else if (tok.startsWith("targetOffset")) {
          String strArg = tok.substring(tok.lastIndexOf("(") + 1);
          String[] args = strArg.split(",");
          try {
            off = new Location(0, 0);
            off.x = Integer.parseInt(args[0]);
            off.y = Integer.parseInt(args[1]);
          } catch (NumberFormatException e) {
          }
        } else if (tok.startsWith("resize")) {
          String strArg = tok.substring(tok.lastIndexOf("(") + 1);
          float rf;
          try {
            rf = Float.parseFloat(strArg);
          } catch (NumberFormatException e) {
            rf = 0;
          }
          resizeFactor = rf;
        } else if (tok.toLowerCase().contains("mask")) {
          mask = tok;
        }
      }
      if (lblText != null) {
        setLabelText();
      }
    } else {
      setFileNames(pyText.replaceAll("\"", ""));
    }
    if (lblText == null) {
      onImagePath = false;
    } else {
      setText(lblText);
      setLabelPyText();
    }
  }

  @Override
  public boolean isRegionLabel() {
    return false;
  }

	private void setFileNames(String givenName) {
		lblText = null;
		if (!new File(givenName).isAbsolute()
						&& FileManager.isFilenameDotted(givenName)) {
			return;
		}
		Image img = new Image(givenName);
		if (img.isValid()) {
			if (isFromCapture || !img.isAbsolute() || img.isBundled()) {
				image = img;
				imgFile = img.getFilename();
				imgName = img.getName();
				imgNameShort = imgName.replaceFirst(".png", "").replaceFirst(".jpg", "");
				lblText = imgNameShort;
			}
		}
	}

  public boolean isOnImagePath() {
    return onImagePath;
  }

  public void showPopup(boolean show) {
    if (show) {
      if (imgpop == null) {
        BufferedImage img = image.getBufferedImage();
        if (img == null) {
          Debug.log(4, "EditorPatternLabel: mouseEntered: not found " + this.imgName);
          return;
        }
        imgpop = new JFrame();
        imgpop.setAlwaysOnTop(true);
        imgpop.setUndecorated(true);
        imgpop.setResizable(false);
        imgpop.setFocusableWindowState(false);
        imgpop.setBackground(Color.WHITE);
        Container p = imgpop.getContentPane();
        p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
        JLabel lbl = new JLabel();
        lbl.setIcon(new ImageIcon(img));
        lbl.setBorder(brd);
        p.add(Box.createHorizontalGlue());
        p.add(lbl);
        p.add(Box.createHorizontalGlue());
        imgpop.pack();
      }
      Point p = getLocationOnScreen();
      Rectangle r = (new Location(p)).getScreen().getRect();
      Point p1 = new Point();
      if (p.y < (r.y + r.height) / 2) {
        p1.y = p.y + getHeight() + 3;
      } else {
        p1.y = p.y - 3 - imgpop.getHeight();
      }
      if (p.x < (r.x + r.width) / 2) {
        p1.x = p.x;
      } else {
        p1.x = p.x - imgpop.getWidth() + getWidth();
      }
      imgpop.setLocation(p1);
      imgpop.setVisible(true);
    } else {
      if (imgpop != null) {
        imgpop.setVisible(false);
      }
    }
  }

  public boolean isCaptureButton() {
    return (CAPTURE.equals(lblText) || lblText.startsWith(NOTFOUND));
  }

  public void resetLabel(String givenFileName, double sim, Location off, float resizeFactor) {
    imgName = (new File(givenFileName)).getName();
    image = new Image(imgName);
    imgFile = image.getFilename();
    imgNameShort = imgName.replaceFirst(".png", "").replaceFirst(".jpg", "");
    this.sim = sim;
    this.off = off;
    this.resizeFactor = resizeFactor;
    setLabelText();
    setLabelPyText();
  }

  public void setLabelText() {
    String buttonSimilar = "";
    if (sim != 0.7) {
      buttonSimilar = String.format(Locale.ENGLISH, " .%d", (int) (sim * 100));
    }
    String buttonOffset = "";
    if (off != null && (off.x != 0 || off.y != 0)) {
      buttonOffset = String.format(" (%d,%d)", off.x, off.y);
    }
    String buttonResize = "";
    if (resizeFactor > 0 && resizeFactor != 1) {
      buttonResize = String.format(" +%3.1f", resizeFactor).replace(",", ".");
    }
    String buttonMask = "";
    if (!mask.isEmpty()) {
      buttonMask = " M";
    }
    lblText = imgNameShort + buttonSimilar + buttonOffset + buttonResize + buttonMask;
    setText(lblText);
  }

  public void setLabelPyText() {
    if (!lblText.startsWith(NOTFOUND)) {
      pyText = pane.getPatternString(image, sim, off, resizeFactor, mask);
    }
  }

  public void setFile(String imgFile) {
    imgName = (new File(imgFile)).getName();
    pyText = "\"" + imgName + "\"";
    imgNameShort = pyText.replaceAll("\"", "").replaceFirst(".png", "").replaceFirst(".jpg", "");
    lblText = imgNameShort;
    setText(lblText);
  }

  public String getFile() {
    return imgFile;
  }

  public void setFileName(String img) {
    this.imgName = img;
  }

  public void setTargetOffset(Location off) {
    this.off = off;
  }

  public Location getTargetOffset() {
    return off;
  }

  public void setSimilarity(double sim) {
    this.sim = sim;
  }

  public double getSimilarity() {
    return sim;
  }

  public float getResizeFactor() {
    return resizeFactor;
  }

  public EditorPane getPane() {
    return pane;
  }

  public static EditorPatternLabel labelFromString(EditorPane parentPane, String str) {
    EditorPatternLabel editorPatternLabel = new EditorPatternLabel(parentPane, str, false);
    if (editorPatternLabel.isOnImagePath()) {
      return editorPatternLabel;
    } else {
      return null;
    }
  }

  @Override
  public void mousePressed(MouseEvent me) {
    checkPopup(me);
  }

  @Override
  public void mouseReleased(MouseEvent me) {
    checkPopup(me);
  }

  private void checkPopup(MouseEvent me) {
    if (me.isPopupTrigger()) {
      wasPopup = true;
      popMenu = pane.getPopMenuImage();
      if (popMenu != null) {
        if (imgpop != null && imgpop.isShowing()) {
          showPopup(false);
        }
        popMenu.show(this, me.getX(), me.getY());
      }
      return;
    }
  }

  @Override
  public void mouseClicked(MouseEvent me) {
    if (wasPopup) {
      wasPopup = false;
      return;
    }
    if (clickToShow) {
      if (imgpop != null) {
        if (!imgpop.isShowing()) {
          showPopup(true);
          return;
        } else {
          showPopup(false);
        }
      } else {
        showPopup(true);
        return;
      }
    } else {
      if (imgpop != null && imgpop.isShowing()) {
        showPopup(false);
      }
    }
    if (!CAPTURE.equals(lblText) && !lblText.startsWith(NOTFOUND)) {
      (new EditorPatternButton(this)).actionPerformed(null);
    } else {
      Element x = pane.getLineAtPoint(me);
//TODO recapture not found image
      if (x == null || lblText.startsWith(NOTFOUND)) {
        return;
      }
      (new ButtonCapture(pane, x)).actionPerformed(null);
    }
  }

  @Override
  public void mouseEntered(MouseEvent me) {
    super.mouseEntered(me);
    if (CAPTURE.equals(lblText) || lblText.startsWith(NOTFOUND)) {
      return;
    }
    if (!clickToShow) {
      showPopup(true);
    }
  }

  @Override
  public void mouseExited(MouseEvent me) {
    super.mouseExited(me);
    if (CAPTURE.equals(lblText)) {
      return;
    }
    showPopup(false);
  }

  @Override
  public String toString() {
    return super.toString();
  }

}