/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
  Part of the Processing project - http://processing.org

  Copyright (c) 2012-16 The Processing Foundation
  Copyright (c) 2004-12 Ben Fry and Casey Reas
  Copyright (c) 2001-04 Massachusetts Institute of Technology

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package processing.app.ui;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.plaf.basic.BasicSplitPaneDivider;
import javax.swing.plaf.basic.BasicSplitPaneUI;

import processing.app.Mode;
import processing.app.Platform;
import processing.core.PApplet;


/**
 * Panel just below the editing area that contains status messages.
 */
public class EditorStatus extends BasicSplitPaneDivider {  //JPanel {
  static final int HIGH = Toolkit.zoom(28);
  static final int LEFT_MARGIN = Editor.LEFT_GUTTER;
  static final int RIGHT_MARGIN = Toolkit.zoom(20);

  Color urlColor;
  Color[] fgColor;
  Color[] bgColor;
  Image[] bgImage;

  @SuppressWarnings("hiding")
  static public final int ERROR   = 1;
  static public final int CURSOR_LINE_ERROR = 2;
  static public final int WARNING = 3;
  static public final int CURSOR_LINE_WARNING = 4;
  static public final int NOTICE  = 0;

  static final int YES    = 1;
  static final int NO     = 2;
  static final int CANCEL = 3;
  static final int OK     = 4;

  static final String NO_MESSAGE = "";

  Editor editor;

  int mode;
  String message;

  String url;
  int rightEdge;
  int mouseX;
  boolean urlRollover;

  Font font;
  FontMetrics metrics;
  int ascent;

  Image offscreen;
  int sizeW, sizeH;

  int response;

  boolean indeterminate;
  Thread thread;


  public EditorStatus(BasicSplitPaneUI ui, Editor editor) {
    super(ui);
    this.editor = editor;
    empty();
    updateMode();

    addMouseListener(new MouseAdapter() {

      @Override
      public void mouseEntered(MouseEvent e) {
        updateMouse();
      }

      @Override
      public void mousePressed(MouseEvent e) {
        if (urlRollover) {
          Platform.openURL(url);
        }
      }

      @Override
      public void mouseExited(MouseEvent e) {
        updateMouse();
      }

    });

    addMouseMotionListener(new MouseMotionAdapter() {

      @Override
      public void mouseMoved(MouseEvent e) {
        mouseX = e.getX();
        updateMouse();
      }
    });
  }


  void updateMouse() {
    if (urlRollover) {
      setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    } else {
      setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
    }
    repaint();
  }


  static String findURL(String message) {
    String[] m = PApplet.match(message, "http\\S+");
    if (m != null) {
      return m[0];
    }
    return null;
  }


  public void updateMode() {
    Mode mode = editor.getMode();

    urlColor = mode.getColor("status.url.fgcolor");

    fgColor = new Color[] {
      mode.getColor("status.notice.fgcolor"),
      mode.getColor("status.error.fgcolor"),
      mode.getColor("status.error.fgcolor"),
      mode.getColor("status.warning.fgcolor"),
      mode.getColor("status.warning.fgcolor")
    };

    bgColor = new Color[] {
      mode.getColor("status.notice.bgcolor"),
      mode.getColor("status.error.bgcolor"),
      mode.getColor("status.error.bgcolor"),
      mode.getColor("status.warning.bgcolor"),
      mode.getColor("status.warning.bgcolor")
    };

    bgImage = new Image[] {
      mode.loadImage("/lib/status/notice.png"),
      mode.loadImage("/lib/status/error.png"),
      mode.loadImage("/lib/status/error.png"),
      mode.loadImage("/lib/status/warning.png"),
      mode.loadImage("/lib/status/warning.png")
    };

    font = mode.getFont("status.font");
    metrics = null;
  }


  public void empty() {
    mode = NOTICE;
    message = NO_MESSAGE;
    url = null;
    repaint();
  }


  public void message(String message, int mode) {
    this.message = message;
    this.mode = mode;

    url = findURL(message);
    repaint();
  }


  public void notice(String message) {
    message(message, NOTICE);
//    mode = NOTICE;
//    this.message = message;
//    url = findURL(message);
//    repaint();
  }


//  public void unnotice(String unmessage) {
//    if (message.equals(unmessage)) empty();
//  }


  public void warning(String message) {
    message(message, WARNING);
//    this.message = message;
//    mode = WARNING;
//    url = findURL(message);
//    repaint();
  }


  public void error(String message) {
    message(message, ERROR);
//    this.message = message;
//    mode = ERROR;
//    url = findURL(message);
//    repaint();
  }


  public void startIndeterminate() {
    indeterminate = true;
    thread = new Thread() {
      public void run() {
        while (Thread.currentThread() == thread) {
          repaint();
          try {
            Thread.sleep(1000 / 10);
          } catch (InterruptedException e) { }
        }
      }
    };
    thread.setName("Editor Status");
    thread.start();
  }


  public void stopIndeterminate() {
    indeterminate = false;
    thread = null;
    repaint();
  }


  //public void paintComponent(Graphics screen) {
  public void paint(Graphics screen) {
//    if (okButton == null) setup();

    Dimension size = getSize();
    if ((size.width != sizeW) || (size.height != sizeH)) {
      // component has been resized
      offscreen = null;
    }

    if (offscreen == null) {
      sizeW = size.width;
      sizeH = size.height;

      offscreen = Toolkit.offscreenGraphics(this, sizeW, sizeH);
    }

    Graphics g = offscreen.getGraphics();
    /*Graphics2D g2 =*/ Toolkit.prepareGraphics(g);

    g.setFont(font);
    if (metrics == null) {
      metrics = g.getFontMetrics();
      ascent = metrics.getAscent();
    }

    g.drawImage(bgImage[mode], 0, 0, sizeW, sizeH, this);

    g.setColor(fgColor[mode]);
    // https://github.com/processing/processing/issues/3265
    if (message != null) {
      // needs to be set each time on osx
      g.setFont(font);
      // calculate right edge of the text for rollovers (otherwise the pane
      // cannot be resized up or down whenever a URL is being displayed)
      rightEdge = LEFT_MARGIN + g.getFontMetrics().stringWidth(message);
      // set the highlight color on rollover so that the user's not surprised
      // to see the web browser open when they click
      urlRollover = (url != null) &&
        (mouseX > LEFT_MARGIN && mouseX < rightEdge);
      if (urlRollover) {
        g.setColor(urlColor);
      }
      g.drawString(message, LEFT_MARGIN, (sizeH + ascent) / 2);
    }

    if (indeterminate) {
      //int x = cancelButton.getX();
      //int w = cancelButton.getWidth();
      int w = Toolkit.getButtonWidth();
      int x = getWidth() - RIGHT_MARGIN - w;
      int y = getHeight() / 3;
      int h = getHeight() / 3;
      g.setColor(new Color(0x80000000, true));
      g.drawRect(x, y, w, h);
      for (int i = 0; i < 10; i++) {
        int r = (int) (x + Math.random() * w);
        g.drawLine(r, y, r, y+h);
      }
    }

    screen.drawImage(offscreen, 0, 0, sizeW, sizeH, null);
  }


  public Dimension getPreferredSize() {
    return getMinimumSize();
  }


  public Dimension getMinimumSize() {
    return new Dimension(Toolkit.zoom(300), HIGH);
  }


  public Dimension getMaximumSize() {
    return new Dimension(super.getMaximumSize().width, HIGH);
  }
}
