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.util.ArrayList;
  import java.util.List;
  
  import nextapp.echo.app.Color;
  import nextapp.echo.app.Component;
  import nextapp.echo.app.Extent;
  import nextapp.echo.app.Font;
  import nextapp.echo.app.Grid;
  import nextapp.echo.app.ImageReference;
  import nextapp.echo.app.Insets;
  import nextapp.echo.app.WindowPane;
  import nextapp.echo.app.event.ActionEvent;
  import nextapp.echo.app.event.ActionListener;
  import ch.uzh.ifi.attempto.acewiki.Wiki;
  import ch.uzh.ifi.attempto.acewiki.core.Concept;
  import ch.uzh.ifi.attempto.acewiki.core.Individual;
  import ch.uzh.ifi.attempto.acewiki.core.InvalidWordException;
  import ch.uzh.ifi.attempto.acewiki.core.LanguageUtils;
  import ch.uzh.ifi.attempto.acewiki.core.LexiconChanger;
  import ch.uzh.ifi.attempto.acewiki.core.LexiconDetail;
  import ch.uzh.ifi.attempto.acewiki.core.OntologyElement;
  import ch.uzh.ifi.attempto.acewiki.core.OntologyTextElement;
  import ch.uzh.ifi.attempto.acewiki.core.Relation;
  import ch.uzh.ifi.attempto.acewiki.core.Sentence;
  import ch.uzh.ifi.attempto.acewiki.core.TopicElement;
  import ch.uzh.ifi.attempto.echocomp.CheckBox;
  import ch.uzh.ifi.attempto.echocomp.Label;
  import ch.uzh.ifi.attempto.echocomp.MessageWindow;
  import ch.uzh.ifi.attempto.echocomp.TextField;
  import ch.uzh.ifi.attempto.preditor.WordEditorForm;
  
  /**
   * This class describes the basic structure for forms to create and modify words (represented by
   * ontology elements).
   * 
   * @author Tobias Kuhn
   */
  public class FormPane extends WordEditorForm {
  
  	private static final long serialVersionUID = 1433983400709841847L;
  	
  	private OntologyElement element;
  	private int wordNumber;
  	private Wiki wiki;
  	private LexiconChanger lexiconChanger;
  	private boolean locked;
  	private MessageWindow delConfirmWindow;
  	
  	/**
  	 * Creates a form pane for creating a new word.
  	 * 
  	 * @param type The type of the new word.
  	 * @param wordNumber The word number that should be used once the word is created.
  	 * @param window The parent window.
  	 * @param wiki The wiki object.
  	 * @param actionListener The action-listener.
  	 */
  	public FormPane(String type, int wordNumber, WindowPane window, Wiki wiki,
  			ActionListener actionListener) {
  		this(type, null, wordNumber, window, wiki, actionListener);
  	}
  	
  	/**
  	 * Creates a form pane for creating a new word.
  	 * 
  	 * @param type The type of the new word.
  	 * @param window The parent window.
  	 * @param wiki The wiki object.
  	 */
  	public FormPane(String type, WindowPane window, Wiki wiki) {
  		this(type, null, 0, window, wiki, wiki);
  	}
  	
  	/**
  	 * Creates a form pane for modifying an existing word.
  	 * 
  	 * @param element The ontology element that represents the word to be modified.
  	 * @param window The parent window.
  	 * @param wiki The wiki object.
  	 */
  	public FormPane(OntologyElement element, WindowPane window, Wiki wiki) {
  		this(element.getInternalType(), element, 0, window, wiki, wiki);
  	}
  	
  	private FormPane(String type, OntologyElement element, int wordNumber, WindowPane window,
  			Wiki wiki, ActionListener actionListener) {
  		super(window, actionListener);
  		this.wordNumber = wordNumber;
  		this.wiki = wiki;
  		if (element != null) {
  			locked = true;
  			if (wiki.getConfig().isReadOnly()) {
  				setButtons("general_action_close");
  			} else {
  				setButtons("general_action_unlock", "general_action_close");
  			}
  		} else {
  			element = wiki.getOntology().getEngine().createOntologyElement(type);
  			locked = false;
  			setButtons("general_action_ok", "general_action_cancel");
  		}
  		this.element = element;
  
  		lexiconChanger = wiki.getLanguageHandler().getLexiconChanger(type);
  		if (lexiconChanger == null) {
  			setHidden(true);
  			return;
  		}
  		setTitle(element.getType());
  		setExplanationComponent(lexiconChanger.getDescription());
  		
  		for (LexiconDetail d : lexiconChanger.getDetails(element)) {
  			Component formElement = null;
  			Object value = d.getValue();
  			boolean required = d.isRequired();
  			if (value instanceof String) {
  				TextField textField = new TextField();
  				textField.setText(LanguageUtils.getPrettyPrinted((String) value));
  				formElement = textField;
  			} else if (value instanceof Boolean) {
  				CheckBox checkBox = new CheckBox();
  				checkBox.setSelected((Boolean) value);
  				formElement = checkBox;
  				required = false;
  			} else {
  				throw new RuntimeException("invalid class: " + value.getClass());
  			}
  			formElement.setEnabled(!locked);
  			addRow(d.getName(), formElement, d.getDescription(), required);
  		}
  
  	}
  	
  	private void setExplanationComponent(String text) {
  		ImageReference imageRef = null;
  		if (getClass().getResource("img/" + element.getInternalType() + ".png") != null) {
  			// Image file exists that corresponds to internal type of element
  			imageRef = Wiki.getImage(element.getInternalType() + ".png");
  		} else if (element instanceof Individual) {
  			imageRef = Wiki.getImage("individual.png");
  		} else if (element instanceof Concept) {
  			imageRef = Wiki.getImage("concept.png");
  		} else if (element instanceof Relation) {
  			imageRef = Wiki.getImage("relation.png");
  		} else if (element instanceof TopicElement) {
  			imageRef = Wiki.getImage("topic.png");
  		}
  		Grid explanationComp = new Grid(2);
  		explanationComp.setRowHeight(0, new Extent(110));
  		explanationComp.setColumnWidth(0, new Extent(100));
  		explanationComp.setInsets(new Insets(0, 0, 10, 20));
  		if (imageRef != null) {
  			explanationComp.add(new Label(imageRef));
  		} else {
  			explanationComp.add(new Label(""));
  		}
  		Label explLabel = new Label(text, Font.ITALIC);
  		explLabel.setForeground(new Color(120, 120, 120));
  		explanationComp.add(explLabel);
  		setExplanationComponent(explanationComp);
  	}
  	
  	/**
  	 * Returns whether this form is locked or not.
  	 * 
  	 * @return true if this form is locked.
  	 */
  	public boolean isLocked() {
  		return locked;
  	}
  
  	private void unlock() {
  		setButtons(
  				"acewiki_wordeditor_deletebutton",
  				"acewiki_wordeditor_changebutton",
  				"general_action_cancel"
  			);
  		for (Component c : getFormElements()) {
  			c.setEnabled(true);
  		}
  		locked = false;
  		doFocus();
  	}
  	
  	private void prepareDelete() {
  		List<Sentence> references = wiki.getOntology().getReferences(element);
  		for (Sentence s : element.getArticle().getSentences()) {
  			references.remove(s);
  		}
  		if (!references.isEmpty()) {
  			wiki.log("page", "error: cannot delete article with references");
  			wiki.showWindow(new MessageWindow(
  					"acewiki_error_title",
  					"acewiki_error_delref",
  					getParentWindow(),
  					(ActionListener) null,
  					"general_action_ok"
  				));
  		} else {
  			wiki.log("page", "delete confirmation");
  			delConfirmWindow = new MessageWindow(
  					"acewiki_message_delwordtitle",
  					"acewiki_message_delword",
  					getParentWindow(),
  					this,
  					"general_action_yes", "general_action_no"
  				);
  			wiki.showWindow(delConfirmWindow);
  		}
  	}
  	
  	private void delete() {
  		wiki.log("page", "delete confirmed");
  		wiki.getOntology().remove(element);
  		wiki.showStartPage();
  	}
  	
  	private void saveOrShowError() {
  		try {
  			List<Object> newValues = new ArrayList<Object>();
  			for (Component c : getFormElements()) {
  				if (c instanceof TextField) {
  					newValues.add(((TextField) c).getText());
  				} else if (c instanceof CheckBox) {
  					newValues.add(((CheckBox) c).isSelected());
  				}
  			}
  			lexiconChanger.save(element, wordNumber, newValues, wiki.getOntology());
  			wiki.log("edit", element.toString());
  			if (element.getOntology() == null) {
  				wiki.getOntology().register(element);
  			}
  			wiki.removeWindow(getParentWindow());
  			
  			// a text element is used to store the ontology element and the word number in one object:
  			OntologyTextElement te = new OntologyTextElement(element, wordNumber);
  			getActionListener().actionPerformed(new ActionEvent(te, ""));
  		} catch (InvalidWordException ex) {
  			wiki.log("edit", "invalid word: " + ex.getMessage());
  			wiki.showWindow(new MessageWindow(
  					"acewiki_error_title",
  					ex.getMessage(),
  					getParentWindow(),
  					"general_action_ok"
  				));
  		}
  	}
  
  	public void actionPerformed(ActionEvent e) {
  		String c = e.getActionCommand();
  		if (e.getSource() == delConfirmWindow) {
  			if ("general_action_yes".equals(c)) {
  				delete();
  				wiki.removeWindow(getParentWindow());
  			}
  		} else if ("general_action_cancel".equals(c) || "general_action_close".equals(c)) {
  			wiki.removeWindow(getParentWindow());
  		} else if ("general_action_ok".equals(c) || "OK".equals(c)) {
  			saveOrShowError();
  		} else if ("general_action_unlock".equals(c)) {
  			if (!wiki.isEditable()) {
  				wiki.showLoginWindow();
  			} else {
  				unlock();
  			}
  		} else if ("acewiki_wordeditor_changebutton".equals(c)) {
  			saveOrShowError();
  		} else if ("acewiki_wordeditor_deletebutton".equals(c)) {
  			prepareDelete();
  		}
  	}
  
  }
  