public class ConfirmEvent {
	
	public final UUID id;
	
	public final String caption;
	public final String message;
	public final String confirmCaption;
	public final String cancelCaption;
	private final Runnable confirmRunnable;
	private final Runnable cancelRunnable;
	
	private static final String DEFAULT_WINDOW_CAPTION = "Bestätigen";
	private static final String DEFAULT_CONFIRM_CAPTION = "Ok";
	private static final String DEFAULT_CANCEL_CAPTION = "Abbrechen";
	
	public void confirm() {
		if(confirmRunnable != null)
			confirmRunnable.run();
	}

	public void cancel() {
		if(cancelRunnable != null)
			cancelRunnable.run();
	}
	
	public static class Builder {
		private final String message;
		private String caption;
		private String confirmCaption;
		private String cancelCaption;
		private Runnable confirmRunnable;
		private Runnable cancelRunnable;
		
		public Builder(String message) {
			this.message = message;
			this.caption = DEFAULT_WINDOW_CAPTION;
			this.confirmCaption = DEFAULT_CONFIRM_CAPTION;
			this.cancelCaption = DEFAULT_CANCEL_CAPTION;
		}
		
		public Builder caption(String caption) {
			this.caption = caption;
			return this;
		}
		
		public Builder confirmCaption(String confirmCaption) {
			this.confirmCaption = confirmCaption;
			return this;
		}
		
		public Builder cancelCaption(String cancelCaption) {
			this.cancelCaption = cancelCaption;
			return this;
		}
		
		public Builder confirmRunnable(Runnable runnable) {
			this.confirmRunnable = runnable;
			return this;
		}
		
		public Builder cancelRunnable(Runnable runnable) {
			this.cancelRunnable = runnable;
			return this;
		}
		
		public ConfirmEvent build() {
			return new ConfirmEvent(this);
		}
	}
	
	private ConfirmEvent(Builder builder) {
		this.caption = builder.caption;
		this.message = builder.message;
		this.confirmCaption = builder.confirmCaption;
		this.cancelCaption = builder.cancelCaption;
		this.confirmRunnable = builder.confirmRunnable;
		this.cancelRunnable = builder.cancelRunnable;
		
		id = UUID.randomUUID();
	}
}
 public class MessageEvent {

	public final String caption;
	public final String message;
	public final Type type;

	public enum Type {
		INFO, TRAYINFO, WARNING, ERROR;
	}

	/**
	 * Creates an event with the specified caption and {@link Type}.INFO as
	 * standard type
	 * 
	 * @param message
	 *            {@link String} containing the message
	 */
	public MessageEvent(String caption) {
		this(caption, "", Type.INFO);
	}

	/**
	 * Creates an event with the specified caption, message and {@link Type}.INFO as
	 * standard type
	 * 
	 * @param caption
	 * 			  {@link String} containing the caption
	 * @param message
	 *            {@link String} containing the message
	 */
	public MessageEvent(String caption, String message) {
		this(caption, message, Type.INFO);
	}
	
	/**
	 * Creates an event with the specified caption, empty message and type
	 * 
	 * @param caption
	 * 			  {@link String} containing the caption
	 * @param message
	 *            {@link String} containing the message
	 */
	public MessageEvent(String caption, Type type) {
		this(caption, "", type);
	}
	
	/**
	 * Creates an event with the specified caption, message and type
	 * 
	 * @param caption
	 * 			  {@link String} containing the caption
	 * @param message
	 *            {@link String} containing the message
	 * @param type
	 *            {@link Type} defining the message type
	 */
	public MessageEvent(String caption, String message, Type type) {
		this.caption = caption;
		this.message = message;
		this.type = type;
	}
}
 @Entity
@Table(name="category")
public class Category implements de.dhbw.humbuch.model.entity.Entity, Serializable, Comparable<Category> {
	private static final long serialVersionUID = -1497919629033299136L;
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int id;
	private String name;
	private String description;
	
	@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, mappedBy="category", fetch=FetchType.LAZY)
	private List<TeachingMaterial> teachingMaterials = new ArrayList<>();
	
	/**
	 * Required by Hibernate.<p>
	 * Use the {@link Builder} instead.
	 * 
	 * @see Builder
	 */
	@Deprecated
	public Category() {}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public List<TeachingMaterial> getTeachingMaterials() {
		return teachingMaterials;
	}

	public void setTeachingMaterials(List<TeachingMaterial> teachingMaterials) {
		this.teachingMaterials = teachingMaterials;
	}

	public static class Builder {
		private final String name;
		
		private String description;
		
		public Builder(String name) {
			this.name = name;
		}
		
		public Builder description(String description) {
			this.description = description;
			return this;
		}
		
		public Category build() {
			return new Category(this);
		}
	}
	
	private Category(Builder builder) {
		this.name = builder.name;
		
		this.description = builder.description;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof Category))
			return false;
		Category other = (Category) obj;
		if (getId() != other.getId())
			return false;
		return true;
	}
	
	@Override
	public String toString() {
		return getName();
	}

	@Override
	public int compareTo(Category o) {
		int compareResult = getName().compareTo(o.getName());
		if(compareResult != 0) {
			return compareResult;
		}
		
		return Integer.compare(hashCode(), o.hashCode());
	}
} public enum Term {
	FIRST("1. Halbjahr"),
	SECOND("2. Halbjahr");
		
	private String value;
		
	private Term(String value) {
		this.value = value;
	}
		
	@Override
	public String toString() {
		return value;
	}
} public enum Subject {

	STANDARD("Standard"),
	FRENCH2("Französisch 2"),
	FRENCH3("Französisch 3"),
	LATIN("Latein"),
	SCIENCE("NWT"),
	
	EVANGELIC("Evangelisch"),
	ROMAN_CATHOLIC("Römisch-Katholisch"),
	ETHICS("Ethik");
	
	private String value;
	
	private Subject(String value) {
		this.value = value;
	}
	
	@Override
	public String toString() {
		return value;
	}
} @Entity
@Table(name="teachingMaterial")
public class TeachingMaterial implements de.dhbw.humbuch.model.entity.Entity, Serializable, Comparable<TeachingMaterial> {
	private static final long serialVersionUID = -6153270685462221761L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int id;
	
	@ManyToOne(fetch=FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
	@JoinColumn(name="categoryId", referencedColumnName="id")
	private Category category;
	
	@ElementCollection(targetClass=Subject.class)
	@Enumerated(EnumType.STRING)
	@CollectionTable(name="teachingMaterialSubject", joinColumns = @JoinColumn(name="teachingMaterialId"))
	@Column(name="subject")
	private Set<Subject> profile = EnumSet.noneOf(Subject.class);
	
	private String name;
	private String producer;
	private String identifyingNumber;
	private double price;
	private String comment;
	
	private int fromGrade;
	private int toGrade;
	
	@Enumerated(EnumType.ORDINAL)
	private Term fromTerm = Term.FIRST;
	
	@Enumerated(EnumType.ORDINAL)
	private Term toTerm = Term.SECOND;
	
	private Date validFrom;
	private Date validUntil;
	
	/**
	 * Required by Hibernate.<p>
	 * Use the {@link Builder} instead.
	 * 
	 * @see Builder
	 */
	@Deprecated
	public TeachingMaterial() {}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public Category getCategory() {
		return category;
	}

	public void setCategory(Category category) {
		this.category = category;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getProducer() {
		return producer;
	}

	public void setProducer(String producer) {
		this.producer = producer;
	}

	public String getIdentifyingNumber() {
		return identifyingNumber;
	}

	public void setIdentifyingNumber(String identifyingNumber) {
		this.identifyingNumber = identifyingNumber;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public String getComment() {
		return comment;
	}

	public void setComment(String comment) {
		this.comment = comment;
	}

	public int getFromGrade() {
		return fromGrade;
	}

	public void setFromGrade(int fromGrade) {
		this.fromGrade = fromGrade;
	}

	public int getToGrade() {
		return toGrade;
	}

	public void setToGrade(int toGrade) {
		this.toGrade = toGrade;
	}

	public Term getFromTerm() {
		return fromTerm;
	}

	public void setFromTerm(Term fromTerm) {
		this.fromTerm = fromTerm;
	}

	public Term getToTerm() {
		return toTerm;
	}

	public void setToTerm(Term toTerm) {
		this.toTerm = toTerm;
	}

	public Date getValidFrom() {
		return validFrom;
	}

	public void setValidFrom(Date validFrom) {
		this.validFrom = validFrom;
	}

	public Date getValidUntil() {
		return validUntil;
	}

	public void setValidUntil(Date validUntil) {
		this.validUntil = validUntil;
	}

	public Set<Subject> getProfile() {
		return profile;
	}

	public void setProfile(Set<Subject> profile) {
		this.profile = profile;
	}

	public void addSubject(Subject subject) {
		getProfile().add(subject);
	}
	
	public boolean hasSubject(Subject subject) {
		return getProfile().contains(subject);
	}
	
	public static class Builder {
		private final Category category;
		private final String name;
		private final String identifyingNumber;
		private final Date validFrom;
		
		private Set<Subject> profile;
		private String producer;
		private double price;
		private String comment;
		private int fromGrade;
		private int toGrade;
		private Term fromTerm;
		private Term toTerm;
		private Date validUntil;
		
		public Builder(Category category, String name, String identifyingNumber, Date validFrom) {
			this.category = category;
			this.name = name;
			this.identifyingNumber = identifyingNumber;
			this.validFrom = validFrom;
			this.fromTerm = Term.FIRST;
			this.toTerm = Term.SECOND;
		}
		
		public Builder profile(Set<Subject> profile) {
			this.profile = profile;
			return this;
		}
		
		public Builder producer(String producer) {
			this.producer = producer;
			return this;
		}
		
		public Builder price(double price) {
			this.price = price;
			return this;
		}
		
		public Builder comment(String comment) {
			this.comment = comment;
			return this;
		}
		
		public Builder fromGrade(int fromGrade) {
			this.fromGrade = fromGrade;
			return this;
		}
		
		public Builder toGrade(int toGrade) {
			this.toGrade = toGrade;
			return this;
		}
		
		public Builder fromTerm(Term fromTerm) {
			this.fromTerm = fromTerm;
			return this;
		}
		
		public Builder toTerm(Term toTerm) {
			this.toTerm = toTerm;
			return this;
		}
		
		public Builder validUntil(Date validUntil) {
			this.validUntil = validUntil;
			return this;
		}
		
		public TeachingMaterial build() {
			return new TeachingMaterial(this);
		}
	}
	
	private TeachingMaterial(Builder builder) {
		this.category = builder.category;
		this.name = builder.name;
		this.identifyingNumber = builder.identifyingNumber;
		this.validFrom = builder.validFrom;
		
		this.profile = builder.profile;
		this.producer = builder.producer;
		this.price = builder.price;
		this.comment = builder.comment;
		this.fromGrade = builder.fromGrade;
		this.toGrade = builder.toGrade;
		this.fromTerm = builder.fromTerm;
		this.toTerm = builder.toTerm;
		this.validUntil = builder.validUntil;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof TeachingMaterial))
			return false;
		TeachingMaterial other = (TeachingMaterial) obj;
		if (getId() != other.getId())
			return false;
		return true;
	}

	@Override
	public int compareTo(TeachingMaterial o) {
		int compareResult = getName().compareTo(o.getName());
		if(compareResult != 0) {
			return compareResult;
		}
		
		return Integer.compare(hashCode(), o.hashCode());
	}
	
} public class BookLookup {
	private final static String KEY = "CONBNUOZ";
	private final static String LOOKUP_URL = "http://isbndb.com/api/v2/xml/"
			+ KEY + "/book/";

	/**
	 * Look up a book by its ISBN
	 * 
	 * @param isbn
	 *            {@link String} containing the ISBN - all non-numerical
	 *            characters are ignored
	 * @return {@link Book} containing the book data
	 * @throws BookNotFoundException
	 *             when a book is not found
	 */
	public static Book lookup(String isbn) throws BookNotFoundException {
		Document document = retrieveDocument(buildLookupURL(processISBN(isbn)));
		validateDocument(document);
		return parseDocument(document);
	}

	/**
	 * Removes all non-numerical characters from the isbn
	 * 
	 * @param isbn
	 *            {@link String} containing the ISBN
	 * @return {@link String} without all non-numerical characters
	 */
	protected static String processISBN(String isbn) {
		return isbn.replaceAll("[^\\d]", "");
	}

	/**
	 * Builds the URI for the ISBN API
	 * 
	 * @param isbn
	 *            {@link String} containing the ISBN
	 * @return {@link String} containing the ISBN API URL
	 */
	protected static String buildLookupURL(String isbn) {
		return LOOKUP_URL + isbn;
	}

	/**
	 * Retrieve an document from a given URI
	 * 
	 * @param uri
	 *            {@link String} containing the URI
	 * @return {@link Document} retrieved from the URI
	 * @throws BookNotFoundException
	 *             thrown when an error occurs while retrieving the document
	 */
	protected static Document retrieveDocument(String uri)
			throws BookNotFoundException {
		try {
			DocumentBuilder documentBuilder = DocumentBuilderFactory
					.newInstance().newDocumentBuilder();
			Document document = documentBuilder.parse(uri);
			document.getDocumentElement().normalize();
			return document;
		} catch (ParserConfigurationException | SAXException | IOException e) {
			throw new BookNotFoundException(
					"Error during retrieving the XML document...", e);
		}
	}

	/**
	 * Checks if the document contains valid data for a book
	 * 
	 * @param document
	 *            {@link Document} to be validated
	 * @throws BookNotFoundException
	 *             thrown when the document contains no valid book data
	 */
	protected static void validateDocument(Document document)
			throws BookNotFoundException {
		Object error = getNodeValue(document, "error");
		if (error != null) {
			throw new BookNotFoundException("No book found...");
		}
	}

	/**
	 * Parse a document and extract the book data
	 * 
	 * @param document
	 *            {@link Document} containing the book data
	 * @return {@link Book} with the extracted data
	 */
	protected static Book parseDocument(Document document) {
		return new Book.Builder(getNodeValue(document, "title"))
				.author(getNodeValue(document, "name"))
				.isbn10(getNodeValue(document, "isbn10"))
				.isbn13(getNodeValue(document, "isbn13"))
				.publisher(getNodeValue(document, "publisher_name")).build();
	}

	/**
	 * Extract the value of the first node of an element
	 * 
	 * @param document
	 *            the {@link Document}
	 * @param elementName
	 *            name of the element of which the value should be extracted
	 * @return {@link String} containing the content of the element if it
	 *         exists, otherwise <code>null</code>
	 */
	private static String getNodeValue(Document document, String elementName) {
		NodeList data = document.getElementsByTagName(elementName);
		Element element = (Element) data.item(0);
		if (element != null) {
			Node node = element.getChildNodes().item(0);
			if (node != null) {
				return node.getNodeValue();
			}
		}
		return null;
	}

	/**
	 * Exception indicating a book was not found
	 */
	public static class BookNotFoundException extends Exception {
		private static final long serialVersionUID = -644882332116172763L;

		public BookNotFoundException() {
			super();
		}

		public BookNotFoundException(String message, Throwable cause,
				boolean enableSuppression, boolean writableStackTrace) {
			super(message, cause, enableSuppression, writableStackTrace);
		}

		public BookNotFoundException(String message, Throwable cause) {
			super(message, cause);
		}

		public BookNotFoundException(String message) {
			super(message);
		}

		public BookNotFoundException(Throwable cause) {
			super(cause);
		}
	}

	/**
	 * POJO holding information about the book
	 */
	public static class Book {
		public final String author;
		public final String isbn10;
		public final String isbn13;
		public final String publisher;
		public final String title;

		private Book(Builder builder) {
			this.author = builder.author;
			this.isbn10 = builder.isbn10;
			this.isbn13 = builder.isbn13;
			this.publisher = builder.publisher;
			this.title = builder.title;
		}

		public static class Builder {
			private String author;
			private String isbn10;
			private String isbn13;
			private String publisher;
			private String title;

			public Builder(String title) {
				this.title = title;
			}

			public Builder author(String author) {
				this.author = author;
				return this;
			}

			public Builder isbn10(String isbn10) {
				this.isbn10 = isbn10;
				return this;
			}

			public Builder isbn13(String isbn13) {
				this.isbn13 = isbn13;
				return this;
			}

			public Builder publisher(String publisher) {
				this.publisher = publisher;
				return this;
			}

			public Book build() {
				return new Book(this);
			}
		}
	}
} public static class Book {
	public final String author;
	public final String isbn10;
	public final String isbn13;
	public final String publisher;
	public final String title;

	private Book(Builder builder) {
		this.author = builder.author;
		this.isbn10 = builder.isbn10;
		this.isbn13 = builder.isbn13;
		this.publisher = builder.publisher;
		this.title = builder.title;
	}

	public static class Builder {
		private String author;
		private String isbn10;
		private String isbn13;
		private String publisher;
		private String title;

		public Builder(String title) {
			this.title = title;
		}

		public Builder author(String author) {
			this.author = author;
			return this;
		}

		public Builder isbn10(String isbn10) {
			this.isbn10 = isbn10;
			return this;
		}

		public Builder isbn13(String isbn13) {
			this.isbn13 = isbn13;
			return this;
		}

		public Builder publisher(String publisher) {
			this.publisher = publisher;
			return this;
		}

		public Book build() {
			return new Book(this);
		}
	}
} public static class BookNotFoundException extends Exception {
	private static final long serialVersionUID = -644882332116172763L;

	public BookNotFoundException() {
		super();
	}

	public BookNotFoundException(String message, Throwable cause,
			boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
	}

	public BookNotFoundException(String message, Throwable cause) {
		super(message, cause);
	}

	public BookNotFoundException(String message) {
		super(message);
	}

	public BookNotFoundException(Throwable cause) {
		super(cause);
	}
} public class TeachingMaterialViewModel {

	public interface TeachingMaterials extends State<Collection<TeachingMaterial>> {}
	public interface Categories extends State<Collection<Category>> {}
	public interface StandardCategory extends State<Category> {}

	public interface DoUpdateTeachingMaterial extends ActionHandler {}
	public interface DoFetchTeachingMaterial extends ActionHandler {}
	public interface DoDeleteTeachingMaterial extends ActionHandler {}
	public interface DoUpdateCategory extends ActionHandler {}

	@ProvidesState(TeachingMaterials.class)
	public final State<Collection<TeachingMaterial>> teachingMaterials = new BasicState<>(Collection.class);

	@ProvidesState(Categories.class)
	public final State<Collection<Category>> categories = new BasicState<>(Collection.class);
	
	@ProvidesState(StandardCategory.class)
	public final State<Category> standardCategory = new BasicState<>(Category.class);

	private DAO<TeachingMaterial> daoTeachingMaterial;
	private DAO<Category> daoCategory;
	private DAO<BorrowedMaterial> daoBorrowedMaterial;
	private EventBus eventBus;

	/**
	 * Constructor
	 * 
	 * @param daoTeachingMaterial
	 *            DAO implementation to access TeachingMaterial entities
	 */
	@Inject
	public TeachingMaterialViewModel(DAO<TeachingMaterial> daoTeachingMaterial,
			DAO<Category> daoCategory,
			DAO<BorrowedMaterial> daoBorrowedMaterial, EventBus eventBus) {
		this.daoTeachingMaterial = daoTeachingMaterial;
		this.daoCategory = daoCategory;
		this.daoBorrowedMaterial = daoBorrowedMaterial;
		this.eventBus = eventBus;
	}

	@AfterVMBinding
	public void initialiseStates() {
		teachingMaterials.set(new ArrayList<TeachingMaterial>());
		categories.set(new ArrayList<Category>());
		standardCategory.set(null);
	}
	
	public void refresh() {
		updateTeachingMaterials();
		updateCategories();
	}

	private void updateTeachingMaterials() {
		teachingMaterials.set(daoTeachingMaterial.findAll());
	}

	private void updateCategories() {
		categories.set(daoCategory.findAll());
		standardCategory.set(daoCategory.findSingleWithCriteria(Restrictions.ilike("name", "B%ch%")));
	}

	/**
	 * Either persist a newly created TeachingMaterial or update an existing one
	 * 
	 * @param teachingMaterial
	 *            a TeachingMaterial to be persisted or updated
	 */
	@HandlesAction(DoUpdateTeachingMaterial.class)
	public void doUpdateTeachingMaterial(TeachingMaterial teachingMaterial) {
		if (teachingMaterial == null) {
			return;
		}
		
		daoTeachingMaterial.update(teachingMaterial);
		updateTeachingMaterials();
	}

	/**
	 * Deletes the teaching material or sets the validUntil date to the current
	 * Date. This decision depends on whether the teaching material is borrowed
	 * by a student.
	 * 
	 * @param teachingMaterial
	 *            the teaching material to be updated or deleted
	 */
	@HandlesAction(DoDeleteTeachingMaterial.class)
	public void doDeleteTeachingMaterial(TeachingMaterial teachingMaterial) {
		Collection<BorrowedMaterial> borrowedMaterial = daoBorrowedMaterial
				.findAllWithCriteria(
						Restrictions.eq("teachingMaterial", teachingMaterial),
						Restrictions.eq("received", true));
		if (borrowedMaterial.isEmpty()) {
			daoTeachingMaterial.delete(teachingMaterial);
			updateTeachingMaterials();
			eventBus.post(new MessageEvent("Löschen erfolgreich",
					"Das Lehrmittel wurde gelöscht.", Type.INFO));
		} else {
			teachingMaterial.setValidUntil(new Date());
			daoTeachingMaterial.update(teachingMaterial);
			updateTeachingMaterials();
			eventBus.post(new MessageEvent(
					"Löschen nicht möglich",
					"Das Lehrmittel ist noch ausgeliehen. \n Das Gültigkeitsdatum wurde jedoch auf das heutige Datum gesetzt.",
					Type.INFO));
		}
	}
} public interface Categories extends State<Collection<Category>> {} public interface StandardCategory extends State<Category> {} public interface TeachingMaterials extends State<Collection<TeachingMaterial>> {}
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.Set;
import com.google.common.eventbus.EventBus;
import com.google.inject.Inject;
import com.vaadin.data.Container.Filter;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.Validator.InvalidValueException;
import com.vaadin.data.fieldgroup.BeanFieldGroup;
import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.data.util.filter.Or;
import com.vaadin.data.util.filter.SimpleStringFilter;
import com.vaadin.event.FieldEvents.TextChangeEvent;
import com.vaadin.event.FieldEvents.TextChangeListener;
import com.vaadin.event.ItemClickEvent;
import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.event.ShortcutListener;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
import com.vaadin.ui.AbstractTextField.TextChangeEventMode;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.DateField;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Table;
import com.vaadin.ui.Table.ColumnGenerator;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import de.davherrmann.mvvm.BasicState;
import de.davherrmann.mvvm.State;
import de.davherrmann.mvvm.StateChangeListener;
import de.davherrmann.mvvm.ViewModelComposer;
import de.davherrmann.mvvm.annotations.BindState;
import de.dhbw.humbuch.event.ConfirmEvent;
import de.dhbw.humbuch.event.MessageEvent;
import de.dhbw.humbuch.model.entity.Category;
import de.dhbw.humbuch.model.entity.SchoolYear.Term;
import de.dhbw.humbuch.model.entity.Subject;
import de.dhbw.humbuch.model.entity.TeachingMaterial;
import de.dhbw.humbuch.util.BookLookup;
import de.dhbw.humbuch.util.BookLookup.Book;
import de.dhbw.humbuch.util.BookLookup.BookNotFoundException;
import de.dhbw.humbuch.viewmodel.TeachingMaterialViewModel;
import de.dhbw.humbuch.viewmodel.TeachingMaterialViewModel.Categories;
import de.dhbw.humbuch.viewmodel.TeachingMaterialViewModel.StandardCategory;
import de.dhbw.humbuch.viewmodel.TeachingMaterialViewModel.TeachingMaterials;
		// Set Form options
		cbCategory.setNullSelectionAllowed(false);
		cbProfiles.setNullSelectionAllowed(false);
		cbFromTerm.setNullSelectionAllowed(false);
		cbToTerm.setNullSelectionAllowed(false);
		txtTmName.setRequired(true);
		cbCategory.setRequired(true);
		cbProfiles.setRequired(true);
		dfValidFrom.setRequired(true);
		dfValidUntil.setDescription("Leer für unbestimmtes Gültigkeitsdatum");

		// Input prompts
		txtIdentNr.setInputPrompt("ISBN");
		txtTmName.setInputPrompt("Titel oder Name");
		txtProducer.setInputPrompt("z.B. Klett");
		txtFromGrade.setInputPrompt("z.B. 5");
		txtToGrade.setInputPrompt("z.B. 7");
		textAreaComment.setInputPrompt("Zusätzliche Informationen");

		// NullRepresentation
		txtIdentNr.setNullRepresentation("");
		txtTmName.setNullRepresentation("");
		txtProducer.setNullRepresentation("");
		txtFromGrade.setNullRepresentation("");
		txtToGrade.setNullRepresentation("");
		textAreaComment.setNullRepresentation("");

		// Bind to FieldGroup
		binder.bind(txtTmName, TABLE_NAME);
		binder.bind(txtIdentNr, TABLE_IDENTNR);
		binder.bind(cbCategory, TABLE_CATEGORY);
		binder.bind(txtProducer, TABLE_PRODUCER);
		binder.bind(cbProfiles, TABLE_PROFILE);
		binder.bind(txtFromGrade, TABLE_FROMGRADE);
		binder.bind(cbFromTerm, TABLE_FROMTERM);
		binder.bind(txtToGrade, TABLE_TOGRADE);
		binder.bind(cbToTerm, TABLE_TOTERM);
		binder.bind(dfValidFrom, TABLE_VALIDFROM);
		binder.bind(dfValidUntil, TABLE_VALIDUNTIL);
		binder.bind(textAreaComment, TABLE_COMMENT);

		// Add all components
		windowContent.addComponent(txtTmName);
		windowContent.addComponent(new HorizontalLayout(){
			{
				setSpacing(true);
				setCaption("ISBN/Nummer");
				setStyleName("required");
				addComponent(txtIdentNr);
				addComponent(btnISBNImport);
			}
		});
		windowContent.addComponent(cbCategory);
		windowContent.addComponent(txtProducer);
		windowContent.addComponent(cbProfiles);
		windowContent.addComponent(new HorizontalLayout() {
			{
				setSpacing(true);
				setCaption("Von Klassenstufe");
				txtFromGrade.setWidth("80px");
				addComponent(txtFromGrade);
				addComponent(cbFromTerm);
			}
		});
		windowContent.addComponent(new HorizontalLayout() {
			{
				setSpacing(true);
				setCaption("Bis Klassenstufe");
				txtToGrade.setWidth("80px");
				addComponent(txtToGrade);
				addComponent(cbToTerm);
			}
		});
		windowContent.addComponent(dfValidFrom);
		windowContent.addComponent(dfValidUntil);
		windowContent.addComponent(textAreaComment);

		windowButtons.addComponent(btnWindowCancel);
		windowButtons.addComponent(btnWindowSave);
		windowContent.addComponent(windowButtons);
		windowEditTeachingMaterial.setContent(windowContent);

		windowEditTeachingMaterial.setCaption("Lehrmittel bearbeiten");
		windowEditTeachingMaterial.setCloseShortcut(KeyCode.ESCAPE, null);
	}

	/**
	 * Adds all listener to their corresponding components.
	 * 
	 */
	@SuppressWarnings("serial")
	private void addListener() {

		/**
		 * Fetches the book data by using a given ISBN. After fetching the data
		 * it is inserted into the corresponding fields.
		 */
		btnISBNImport.addClickListener(new ClickListener() {

			@Override
			public void buttonClick(ClickEvent event) {
				//Check if empty
				if (txtIdentNr.getValue() == null) {
					eventBus.post(new MessageEvent("Bitte geben Sie eine ISBN an."));
					return;
				}
				
				Runnable confirmRunnable = new Runnable() {
					@Override
					public void run() {
						try {
							Book book = BookLookup.lookup(txtIdentNr.getValue());
							txtTmName.setValue(book.title);
							txtProducer.setValue(book.publisher);
							textAreaComment.setValue(book.publisher);
						} catch (BookNotFoundException e) {
							eventBus.post(new MessageEvent("Es konnte kein Buch zu der ISBN gefunden werden."));
						}
					}
				};
				eventBus.post(new ConfirmEvent.Builder("Alle bereits eingegebenen Daten des Lehrmittels werden überschrieben.<br>Wollen Sie wirklich fortfahren?")