/*
 * jNPad v0.3 - jNPad's an Simple Text Editor written in Java
 *
 * Copyright (C) 2014-2017  rgs
 *
 * Require JDK 1.6 (or later)
 *
 * 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.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 *
 * Info, Questions, Suggestions & Bugs Report to rgsevero@gmail.com
 */

package jnpad.text;

import java.awt.Color;
import java.awt.Rectangle;

import javax.swing.JTextArea;
import javax.swing.text.BadLocationException;
import javax.swing.text.Caret;
import javax.swing.text.Document;
import javax.swing.text.Element;

import jnpad.GUIUtilities;
import jnpad.config.Configurable;

/**
 * The Class AbstractTextArea.
 *
 * @version 0.3
 * @since   jNPad v0.3
 */
public abstract class AbstractTextArea extends JTextArea implements Configurable {
  EditPane               editPane;

  /** UID */
  private static final long serialVersionUID = 155332570251202612L;

  /**
   * Instantiates a new abstract text area.
   *
   * @param editPane the edit pane
   */
  public AbstractTextArea(EditPane editPane) {
    this.editPane = editPane;
  }
  
  /**
   * Gets the view rect.
   *
   * @return the view rect
   */
  public Rectangle getViewRect() {
    return null;
  }
  
  /**
   * Checks if is view rect visible.
   *
   * @return true, if is view rect visible
   */
  public boolean isViewRectVisible() {
    return false;
  }

  /**
   * Sets the view rect visible.
   *
   * @param b the new view rect visible
   */
  public void setViewRectVisible(boolean b) { /* empty */}

  /**
   * Gets the content type.
   *
   * @return the content type
   */
  public abstract String getContentType();

  /**
   * Creates the default model.
   *
   * @return the document
   * @see javax.swing.JTextArea#createDefaultModel()
   */
  @Override
  protected Document createDefaultModel() {
    return new JNPadDocument();
  }

  /**
   * Gets the jNPad document.
   *
   * @return the jNPad document
   */
  public JNPadDocument getJNPadDocument() {
    return (JNPadDocument) getDocument();
  }
  
  /**
   * Checks if is right margin line visible.
   *
   * @return true, if is right margin line visible
   */
  public abstract boolean isRightMarginLineVisible();

  /**
   * Gets the right margin line width.
   *
   * @return the right margin line width
   */
  public abstract int getRightMarginLineWidth();

  /**
   * Gets the right margin line color.
   *
   * @return the right margin line color
   */
  public abstract Color getRightMarginLineColor();

  /**
   * Sets the right margin line width.
   *
   * @param width the new right margin line width
   */
  public void setRightMarginLineWidth(int width) {/* empty */}

  /**
   * Sets the right margin line visible.
   *
   * @param b the new right margin line visible
   */
  public void setRightMarginLineVisible(boolean b) { /* empty */}

  /**
   * Sets the right margin line color.
   *
   * @param c the new right margin line color
   */
  public void setRightMarginLineColor(Color c) {/* empty */}

  /**
   * Sets the caret0.
   */
  public void setCaret0() {
    setCaretPosition(0);
  }

  /**
   * Sets the caret end.
   */
  public void setCaretEnd() {
    final Document doc = getDocument();
    GUIUtilities.runOrInvokeLater(new Runnable() {
      public void run() {
        setCaretPosition(doc.getLength());
      }
    });
  }

  /**
   * Gets the line text.
   *
   * @param line int
   * @return String
   * @throws BadLocationException the bad location exception
   */
  public String getLineText(int line) throws BadLocationException {
    return getJNPadDocument().getLineText(line);
  }

  /**
   * Gets the line text of offset.
   *
   * @param offset the offset
   * @return the line text of offset
   * @throws BadLocationException the bad location exception
   */
  public String getLineTextOfOffset(int offset) throws BadLocationException {
    return getJNPadDocument().getLineTextOfOffset(offset);
  }

  /**
   * Gets the line text of offset only up to pos.
   *
   * @param offset the offset
   * @return the line text of offset only up to pos
   * @throws BadLocationException the bad location exception
   */
  public String getLineTextOfOffsetOnlyUpToPos(int offset) throws BadLocationException {
    return getJNPadDocument().getLineTextOfOffsetOnlyUpToPos(offset);
  }

  /**
   * Gets the line.
   *
   * @param line int
   * @return Element
   * @throws BadLocationException the bad location exception
   */
  public Element getLine(int line) throws BadLocationException {
    return getJNPadDocument().getLine(line);
  }
  
  /**
   * Checks for selection.
   *
   * @return boolean
   */
  public boolean hasSelection() {
    Caret caret = getCaret();
    return caret.getMark() != caret.getDot();
  }
  
  /**
   * Gets the caret line number.
   *
   * @return the caret line number
   */
  public int getCaretLineNumber() {
    try {
      return getLineOfOffset(getCaretPosition());
    }
    catch (BadLocationException ble) {
      return 0; // Never happens
    }
  }

  /**
   * Gets the caret offset from line start.
   *
   * @return the caret offset from line start
   */
  public int getCaretOffsetFromLineStart() {
    try {
      int pos = getCaretPosition();
      return pos - getLineStartOffset(getLineOfOffset(pos));
    }
    catch (BadLocationException ble) {
      return 0; // Never happens
    }
  }

  /**
   * Scroll to middle.
   *
   * @param pos the pos
   */
  public void scrollToMiddle(int pos) {
    TextUtilities.scrollToMiddle(this, pos);
  }

  /**
   * Scroll to middle.
   *
   * @param pos the pos
   * @param ratio the ratio
   */
  public void scrollToMiddle(int pos, float ratio) {
    TextUtilities.scrollToMiddle(this, pos, ratio);
  }

  /**
   * Jump to offset.
   *
   * @param offset the offset
   */
  public void jumpToOffset(int offset) {
    if (offset < 0 || offset > getDocument().getLength())
      return;
    requestFocusInWindow();
    scrollToMiddle(offset);
    setCaretPosition(offset);
  }

  /**
   * Move to offset.
   *
   * @param offset the offset
   */
  public void moveToOffset(int offset) {
    if (offset < 0 || offset > getDocument().getLength())
      return;
    requestFocusInWindow();
    scrollToMiddle(offset);
    moveCaretPosition(offset);
  }

  /**
   * Jump to line number.
   *
   * @param line the line
   * @return true, if successful
   */
  public boolean jumpToLineNumber(int line) {
    try {
      int offset = getLineStartOffset(line);
      if (offset < 0 || offset > getDocument().getLength())
        return false;
      requestFocusInWindow();
      scrollToMiddle(offset);
      setCaretPosition(offset);
      return true;
    }
    catch (BadLocationException ex) {
      return false;
    }
  }

  /**
   * Move to line number.
   *
   * @param line the line
   * @return true, if successful
   */
  public boolean moveToLineNumber(int line) {
    try {
      int offset = getLineStartOffset(line);
      if (offset < 0 || offset > getDocument().getLength())
        return false;
      requestFocusInWindow();
      scrollToMiddle(offset);
      moveCaretPosition(offset);
      return true;
    }
    catch (BadLocationException ex) {
      return false;
    }
  }
  
  /**
   * Checks if is main.
   *
   * @return true, if is main
   */
  abstract boolean isMain();
  
}
