content: // This file is part of AceWiki.
  // Copyright 2008-2013, AceWiki developers.
  // 
  // AceWiki is free software: you can redistribute it and/or modify it under the terms of the GNU
  // Lesser General Public License as published by the Free Software Foundation, either version 3 of
  // the License, or (at your option) any later version.
  // 
  // AceWiki 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
  // Lesser General Public License for more details.
  // 
  // You should have received a copy of the GNU Lesser General Public License along with AceWiki. If
  // not, see http://www.gnu.org/licenses/.
  
  package ch.uzh.ifi.attempto.acewiki.gui;
  
  import java.awt.FontMetrics;
  import java.awt.image.BufferedImage;
  import java.util.ArrayList;
  import java.util.List;
  
  import nextapp.echo.app.Alignment;
  import nextapp.echo.app.Color;
  import nextapp.echo.app.Column;
  import nextapp.echo.app.Component;
  import nextapp.echo.app.Font;
  import nextapp.echo.app.Row;
  import nextapp.echo.app.event.ActionEvent;
  import nextapp.echo.app.event.ActionListener;
  import nextapp.echo.app.layout.RowLayoutData;
  import ch.uzh.ifi.attempto.acewiki.Wiki;
  import ch.uzh.ifi.attempto.acewiki.core.Comment;
  import ch.uzh.ifi.attempto.acewiki.core.LanguageUtils;
  import ch.uzh.ifi.attempto.acewiki.core.OntologyElement;
  import ch.uzh.ifi.attempto.acewiki.core.OntologyTextElement;
  import ch.uzh.ifi.attempto.acewiki.core.ModuleElement;
  import ch.uzh.ifi.attempto.base.TextElement;
  import ch.uzh.ifi.attempto.echocomp.HSpace;
  import ch.uzh.ifi.attempto.echocomp.MessageWindow;
  import ch.uzh.ifi.attempto.echocomp.SolidLabel;
  import ch.uzh.ifi.attempto.echocomp.VSpace;
  
  /**
   * This class represents a comment component consisting of a drop down menu and a comment text.
   * 
   * @author Tobias Kuhn
   */
  public class CommentComponent extends Column implements ActionListener {
  
  	private static final long serialVersionUID = -540135972060005725L;
  
  	private static final int COMMENT_TEXT_WIDTH = 800;
  
  	private static FontMetrics fontMetrics =
  			(new BufferedImage(2, 2, BufferedImage.TYPE_4BYTE_ABGR_PRE)
  			.createGraphics()).getFontMetrics(new java.awt.Font("Verdana", java.awt.Font.ITALIC, 13));
  
  	private Comment comment;
  	private Wiki wiki;
  	private WikiPage hostPage;
  
  	private Row commentRow = new Row();
  	private StatementMenu statementMenu;
  
  	/**
  	 * Creates a new comment row.
  	 * 
  	 * @param comment The comment to be shown.
  	 * @param hostPage The host page of the comment row.
  	 */
  	public CommentComponent(Comment comment, WikiPage hostPage) {
  		this.comment = comment;
  		this.hostPage = hostPage;
  		this.wiki = hostPage.getWiki();
  		update();
  	}
  
  	private void update() {
  		statementMenu = new StatementMenu(StatementMenu.COMMENT_TYPE, wiki, this);
  		if (!wiki.getConfig().isReadOnly()) {
  			if (wiki.getConfig().isCommentingEnabled()) {
  				statementMenu.addMenuEntry("acewiki_statementmenu_edit", "acewiki_statementmenu_editcommtooltip");
  				statementMenu.addMenuEntry("acewiki_statementmenu_delete", "acewiki_statementmenu_delcommtooltip");
  				statementMenu.addMenuSeparator();
  			}
  			statementMenu.addMenuEntry("acewiki_statementmenu_addsent", "acewiki_statementmenu_addsenttooltip");
  			if (wiki.getConfig().isCommentingEnabled()) {
  				statementMenu.addMenuEntry("acewiki_statementmenu_addcomm", "acewiki_statementmenu_addcommtooltip");
  			}
  		}
  		RowLayoutData layout = new RowLayoutData();
  		layout.setAlignment(new Alignment(Alignment.CENTER, Alignment.TOP));
  		statementMenu.setLayoutData(layout);
  		Column c = new Column();
  		for (String s : (comment.getText() + " ").split("\\n")) {
  			int indent = s.replaceFirst("^(\\s*).*$", "$1").length() * 5;
  			s = s.replaceFirst("^\\s*", "");
  			if (indent > COMMENT_TEXT_WIDTH/2) indent = COMMENT_TEXT_WIDTH/2;
  			for (Component comp : wrapText(s, COMMENT_TEXT_WIDTH-indent)) {
  				Row r = new Row();
  				r.add(new VSpace(17));
  				r.add(new HSpace(indent));
  				r.add(comp);
  				c.add(r);
  			}
  		}
  
  		removeAll();
  		commentRow.removeAll();
  		commentRow.add(statementMenu);
  		commentRow.add(new HSpace(5));
  		commentRow.add(c);
  		commentRow.add(new HSpace(10));
  		add(commentRow);
  	}
  
  	public void actionPerformed(ActionEvent e) {
  		if (e.getActionCommand().equals("acewiki_statementmenu_edit")) {
  			wiki.log("page", "dropdown: edit comment: " + comment.getText());
  			if (!wiki.isEditable()) {
  				wiki.showLoginWindow();
  			} else {
  				wiki.showWindow(CommentEditorHandler.generateEditWindow(
  						comment,
  						(ArticlePage) hostPage
  						));
  			}
  		} else if (e.getActionCommand().equals("acewiki_statementmenu_addsent")) {
  			wiki.log("page", "dropdown: add sentence");
  			if (!wiki.isEditable()) {
  				wiki.showLoginWindow();
  			} else {
  				wiki.showWindow(SentenceEditorHandler.generateCreationWindow(
  						comment,
  						(ArticlePage) hostPage
  						));
  			}
  		} else if (e.getActionCommand().equals("acewiki_statementmenu_addcomm")) {
  			wiki.log("page", "dropdown: add comment");
  			if (!wiki.isEditable()) {
  				wiki.showLoginWindow();
  			} else {
  				wiki.showWindow(CommentEditorHandler.generateCreationWindow(
  						comment,
  						(ArticlePage) hostPage
  						));
  			}
  		} else if (e.getActionCommand().equals("acewiki_statementmenu_delete")) {
  			wiki.log("page", "dropdown: delete comment: " + comment.getText());
  			if (!wiki.isEditable()) {
  				wiki.showLoginWindow();
  			} else {
  				wiki.showWindow(new MessageWindow(
  						"acewiki_message_delstatementtitle",
  						"acewiki_message_delcomment",
  						null,
  						this,
  						"general_action_yes", "general_action_no"
  						));
  			}
  		} else if (e.getSource() instanceof MessageWindow && e.getActionCommand().equals("general_action_yes")) {
  			wiki.log("page", "dropdown: delete confirmed: " + comment.getText());
  			comment.getArticle().remove(comment);
  			wiki.update();
  			wiki.refresh();
  		}
  	}
  
  	// TODO: this is very ACE specific
  	private List<Component> wrapText(String text, int width) {
  		List<Component> wrappedText = new ArrayList<Component>();
  		String line = "";
  		Row row = new Row();
  		text = text.replaceAll("~", "~t");
  		while (text.matches(".*\\[\\[[^\\]]* [^\\]]*\\]\\].*")) {
  			text = text.replaceAll("\\[\\[([^\\]]*) ([^\\]]*)\\]\\]", "[[$1_$2]]");
  		}
  		text = text.replaceAll(" ", " ~b");
  		text = text.replaceAll("_of\\]\\]", " of]]");
  		text = text.replaceAll("_by\\]\\]", " by]]");
  		text = text.replaceAll("\\[\\[", "~b[[");
  		text = text.replaceAll("\\]\\]", "]]~b");
  		text = text.replaceAll("~t", "~");
  		for (String s : text.split("~b")) {
  			CommentPart cp = new CommentPart(s);
  			if (line.length() == 0 || fontMetrics.stringWidth(line + cp.getText()) < width) {
  				row.add(cp.getComponent());
  				line += cp.getText();
  				if (cp.getText().endsWith(" ")) row.add(new HSpace());
  			} else {
  				wrappedText.add(row);
  				row = new Row();
  				row.add(cp.getComponent());
  				line = cp.getText();
  				if (cp.getText().endsWith(" ")) row.add(new HSpace());
  			}
  		}
  		if (line.length() > 0) {
  			wrappedText.add(row);
  		}
  		return wrappedText;
  	}
  
  
  	private class CommentPart extends Component {
  
  		private static final long serialVersionUID = 8522664422692717971L;
  
  		private Component comp;
  		private String text;
  
  		public CommentPart(String s) {
  			if (s.startsWith("http://") || s.startsWith("https://") || s.startsWith("ftp://")) {
  				comp = new WebLink(s);
  				text = s;
  			} else if (s.startsWith("[[") && s.endsWith("]]")) {
  				String name = s.substring(2, s.length()-2);
  				Wiki wiki = hostPage.getWiki();
  				TextElement te = wiki.getLanguageHandler().getTextOperator().createTextElement(name);
  				if (te instanceof OntologyTextElement) {
  					OntologyTextElement ote = (OntologyTextElement) te;
  					OntologyElement oe = ote.getOntologyElement();
  					if (wiki.getConfig().isGrammarIntegrationEnabled() || !(oe instanceof ModuleElement)) {
  						String t = LanguageUtils.getPrettyPrinted(oe.getWord(ote.getWordNumber()));
  						comp = new WikiLink(oe, t, wiki, false);
  						text = name;
  					}
  				}
  			}
  			if (comp == null) {
  				SolidLabel label = new SolidLabel(s, Font.ITALIC);
  				label.setForeground(new Color(120, 120, 120));
  				comp = label;
  				text = s;
  			}
  		}
  
  		public Component getComponent() {
  			return comp;
  		}
  
  		public String getText() {
  			return text;
  		}
  
  	}
  
  }
  