/*
 * Copyright (C) 2018 FaVdB
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */
package storybook.model.book;

import java.beans.PropertyChangeEvent;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.swing.Icon;
import org.hibernate.Session;
import resources.icons.IconUtil;
import storybook.Const.STORYBOOK;
import storybook.model.EntityUtil;
import storybook.model.Model;
import storybook.model.hbn.dao.ChapterDAO;
import storybook.model.hbn.dao.InternalDAO;
import storybook.model.hbn.dao.PartDAO;
import storybook.model.hbn.dao.SceneDAO;
import storybook.model.hbn.dao.StrandDAO;
import storybook.model.hbn.entity.AbstractEntity;
import storybook.model.hbn.entity.Chapter;
import storybook.model.hbn.entity.Internal;
import storybook.model.hbn.entity.Part;
import storybook.model.hbn.entity.Scene;
import storybook.tools.LOG;
import storybook.tools.calendar.SbCalendar;
import storybook.ui.MainFrame;
import storybook.ui.dialog.preferences.PropertiesDlg;

/**
 *
 * @author FaVdB
 */
public class Book {

	private static final String TT = "Book";

	public int nbParts() {
		return EntityUtil.findEntities(mainFrame, Book.TYPE.PART).size();
	}

	@SuppressWarnings("unchecked")
	public int nbChapters(Part... part) {
		int nb = 0;
		for (Chapter chapter : (List<Chapter>) EntityUtil.findEntities(mainFrame, Book.TYPE.CHAPTER)) {
			if (chapter.hasPart()) {
				if (part != null && part.equals(chapter.getPart())) {
					nb++;
				} else {
					nb++;
				}
			}
		}
		return nb;
	}

	@SuppressWarnings("unchecked")
	public int nbScenes() {
		int nb = 0;
		for (Scene scene : (List<Scene>) EntityUtil.findEntities(mainFrame, Book.TYPE.SCENE)) {
			if (!scene.getInformative()) {
				nb++;
			}
		}
		return nb;
	}

	/**
	 * datas for identitying the type of DB object
	 */
	public enum TYPE {
		INTERNAL,// internal data may be String, Boolean, Integer or Bytes
		ATTRIBUTE,// Person Attribute (in development)
		CATEGORY,
		CHALLENGE,
		CHAPTER,
		ENDNOTE,
		EPISODE,
		EVENT,
		GENDER,
		IDEA,
		IDEABOX,
		ITEM,
		ITEMLINK,
		LOCATION,
		MEMO,
		PART,
		PERSON,
		PLOT,
		RELATION,
		SCENE,
		STRAND,
		TAG,
		TAGLINK,
		// these are plurials
		INTERNALS,
		ATTRIBUTES,
		CATEGORIES,
		CHAPTERS,
		ENDNOTES,
		EPISODES,
		EVENTS,
		GENDERS,
		IDEAS,
		ITEMS,
		ITEMLINKS,
		LOCATIONS,
		MEMOS,
		PARTS,
		PERSONS,
		PLOTS,
		RELATIONS,
		SCENES,
		STRANDS,
		TAGS,
		TAGLINKS,
		//not realy entities
		SCENARIO,
		SCENARIOS,
		STATUS,
		ALL,// all types for selection purpose
		NONE;

		private TYPE() {
		}

		@Override
		public String toString() {
			return this.name().toLowerCase();
		}

		public boolean compare(String str) {
			return this.name().toLowerCase().equals(str.toLowerCase());
		}

		public boolean isPart() {
			return this.name().equals("PART");
		}

		public boolean isChapter() {
			return this.name().equals("CHAPTER");
		}

		public boolean isScene() {
			return this.name().equals("SCENE");
		}
	}

	public static TYPE getTYPE(PropertyChangeEvent evt) {
		String prop = evt.getPropertyName();
		if (prop.contains("_")) {
			String v[] = prop.split("_");
			return (getTYPE(v[0]));
		}
		return (TYPE.NONE);

	}

	public static TYPE getTYPE(AbstractEntity entity) {
		if (entity == null) {
			return (TYPE.NONE);
		}
		return entity.getObjType();
	}

	public static TYPE getTYPE(String str) {
		if (str != null && !str.isEmpty()) {
			for (TYPE id : TYPE.values()) {
				if (id.compare(str)) {
					return (id);
				}
			}
		}
		return (TYPE.NONE);
	}

	public static Icon getIcon(TYPE type) {
		return IconUtil.getIconSmall("ent_" + type.toString());
	}

	/**
	 * KEY determining data associated with the Book like Title, Author, and so on
	 */
	public enum INFO {
		ASSISTANT("Assistant"),//Boolean
		AUTHOR("Author"),// String
		BLURB("Blurb"),// String
		COPYRIGHT("Copyright"),// String
		CREATION("BookCreationDate"),// String date formated
		UPDATE("BookUpdate"),// String date formated
		MARKDOWN("Markdown"),// Boolean
		NOTES("Notes"),// String
		DEDICATION("Dedication"),// String
		SCENARIO("Scenario"),// Boolean
		SUBTITLE("SubTitle"),// String
		TITLE("Title"),// String
		UUID("UUID"),// String
		ISBN("ISBN"),// String
		LANG("Language"),// String
		DB_VERSION("dbversion"),// String
		NATURE("Nature"),// Integer
		REVIEW("Review"),// boolean
		NONE("none");
		final private String text;

		private INFO(String text) {
			this.text = text;
		}

		@Override
		public String toString() {
			return text;
		}
	}

	/**
	 * Specific parameters for the Book
	 */
	public enum PARAM {
		BACKUP_AUTO,// Boolean
		BACKUP_DIR,// String
		BACKUP_INCREMENT,// Integer
		CALENDAR_DAYS,// String
		CALENDAR_HOURS,// Integer
		CALENDAR_MONTHS,// Integer
		CALENDAR_STARTDAY,// Integer
		CALENDAR_USE,// Boolean
		CALENDAR_YEARDAYS,// Integer
		EDITOR_EXTENSION,// String
		EDITOR_MODLESS,// Boolean
		EDITOR_NAME,// String
		EDITOR_TEMPLATE,// String
		EDITOR_USE,// Boolean
		EPUB_COVER,// String
		EPUB_COVER_NOTEXT,// Boolean
		EXPORT_CHAPTER_BOOKTITLE,// Boolean
		EXPORT_CHAPTER_BREAKPAGE,// Boolean
		EXPORT_CSV_COMMA,// String
		EXPORT_CSV_QUOTE,// String
		EXPORT_DIR,// String
		EXPORT_FORMAT,// String
		EXPORT_HIGHLIGHT,//Integer
		EXPORT_HTML_CSS,// Boolean
		EXPORT_HTML_MULTICHAPTER,// Boolean
		EXPORT_HTML_MULTI,// Boolean
		EXPORT_HTML_MULTISCENE,// Boolean
		EXPORT_HTML_NAV,// Boolean
		EXPORT_HTML_NAVIMAGE,// Boolean
		EXPORT_PDF_LANDSCAPE,// Boolean
		EXPORT_PDF_SIZE,// Integer
		EXPORT_TXT_SEPARATOR,// String
		EXPORT_TXT_TAB,// Boolean
		IMAGE_DIR,// String
		IMPORT_DIRECTORY,// String
		IMPORT_FILE,// String
		LAYOUT_BOOK,// String
		LAYOUT_SCENE_SEPARATOR,// String
		LAYOUT_SHOW_REVIEW,// Boolean
		SCENE_DATE_INIT,// Integer
		NONE;

		@Override
		public String toString() {
			return name();
		}
	}

	/**
	 * check if a key exists in KEY or PARAM
	 *
	 * @param key
	 * @return
	 */
	public static boolean checkKey(String key) {
		for (INFO k : INFO.values()) {
			if (key.equals(k.toString())) {
				return true;
			}
		}
		for (PARAM k : PARAM.values()) {
			if (key.equals(k.toString())) {
				return true;
			}
		}
		return false;
	}

	public MainFrame mainFrame;
	public BookInfo info;
	public BookParam param;

	public boolean getBoolean(INFO param) {
		return (getBoolean(param.toString()));
	}

	public boolean getBoolean(PARAM param) {
		return (getBoolean(param.toString()));
	}

	public boolean getBoolean(String param) {
		return (Book.getBoolean(mainFrame, param));
	}

	public void setBoolean(INFO param, boolean value) {
		setBoolean(param.toString(), value);
	}

	public void setBoolean(PARAM param, boolean value) {
		setBoolean(param.toString(), value);
	}

	public void setBoolean(String param, boolean value) {
		Book.setBoolean(mainFrame, param, value);
	}

	public int getInteger(INFO param) {
		return getInteger(param.toString(), 0);
	}

	public int getInteger(PARAM param, int... def) {
		if (def == null || def.length < 1) {
			return getInteger(param.toString(), 0);
		}
		return getInteger(param.toString(), def[0]);
	}

	public int getInteger(String param, int def) {
		return Book.getInteger(mainFrame, param, def);
	}

	public void setInteger(INFO param, int value) {
		setInteger(param.toString(), value);
	}

	public void setInteger(PARAM param, int value) {
		setInteger(param.toString(), value);
	}

	public void setInteger(String param, int value) {
		Book.setInteger(mainFrame, param, value);
	}

	public static int checkInteger(int value, int min, int max) {
		if (value < min) {
			return min;
		} else if (value > max) {
			return max;
		} else {
			return value;
		}
	}

	public void setLong(String param, Long value) {
		Book.setLong(mainFrame, param, value);
	}

	public String getString(INFO param) {
		return getString(mainFrame, param.toString());
	}

	public String getString(PARAM param) {
		return getString(mainFrame, param.toString());
	}

	public String getString(String param) {
		return Book.getString(mainFrame, param);
	}

	public void setString(INFO param, String value) {
		setString(param.toString(), value);
	}

	public void setString(PARAM param, String value) {
		setString(param.toString(), value);
	}

	public void setString(String param, String value) {
		Book.setString(mainFrame, param, value);
	}

	public Book(MainFrame mainFrame) {
		this.mainFrame = mainFrame;
		init();
	}

	public void init() {
		info = new BookInfo(this);
		param = new BookParam(this);
		if (mainFrame != null) {
			setProperties();
		}
	}

	public String getDbVersion() {
		return (getString(mainFrame, INFO.DB_VERSION));
	}

	public void setDbVersion() {
		setString(mainFrame, INFO.DB_VERSION, STORYBOOK.DB_VERSION.toString());
	}

	public void save() {
		//LOG.trace(TT + ".save()");
		int hsh = param.getParamLayout().getHashCode();
		info.save();
		param.save();
		if (hsh != param.getParamLayout().getHashCode()) {
			param.book.mainFrame.getBookModel().fireAgainReading();
		}
	}

	public void setCreation() {
		info.setCreation();
	}

	public void setCreation(String val) {
		info.setCreation(val);
	}

	public String getCreation() {
		return (info.getCreation());
	}

	public void setMaj() {
		info.setMaj();
	}

	public String getMaj() {
		return info.getMaj();
	}

	public Date getMajDate() {
		return info.getMajDate();
	}

	public void setMaj(String c) {
		info.setMaj(c);
	}

	public void setProperties() {
		setProperties(mainFrame);
	}

	public void setProperties(MainFrame m) {
		setCreation(getString(m, INFO.CREATION));
		setMaj(getString(m, INFO.UPDATE));
		setTitle(getString(m, INFO.TITLE));
		setSubtitle(getString(m, INFO.SUBTITLE));
		setAuthor(getString(m, INFO.AUTHOR));
		setCopyright(getString(m, INFO.COPYRIGHT));
		setBlurb(getString(m, INFO.BLURB));
		setNotes(getString(m, INFO.NOTES));
		setScenario(getBoolean(m, INFO.SCENARIO));
		setMarkdown(getBoolean(m, INFO.MARKDOWN));
		setUUID(getString(m, INFO.UUID));
		setISBN(getString(m, INFO.ISBN));
	}

	public void setProperties(PropertiesDlg dlg) {
		//App.trace("Book.setProperties(dlg)");
		setMaj();
		setTitle(dlg.tfTitle.getText());
		setSubtitle(dlg.tfSubtitle.getText());
		setAuthor(dlg.tfAuthor.getText());
		setCopyright(dlg.tfCopyright.getText());
		setBlurb(dlg.taBlurb.getText());
		setNotes(dlg.taNotes.getText());
		setScenario(dlg.ckScenario.isSelected());
		setMarkdown(dlg.ckMarkdown.isSelected());
	}

	public String getTitle() {
		return (info.getTitle());
	}

	public void setTitle(String value) {
		info.setTitle(value);
	}

	public String getSubtitle() {
		return (info.getSubtitle());
	}

	public void setSubtitle(String value) {
		info.setSubtitle(value);
	}

	public String getAuthor() {
		return (info.getAuthor());
	}

	public void setAuthor(String value) {
		info.setAuthor(value);
	}

	public String getCopyright() {
		return (info.getCopyright());
	}

	public void setCopyright(String value) {
		info.setCopyright(value);
	}

	public String getBlurb() {
		return (info.getBlurb());
	}

	public void setBlurb(String value) {
		info.setBlurb(value);
	}

	public String getNotes() {
		return info.getNotes();
	}

	public void setNotes(String val) {
		info.setNotes(val);
	}

	public String getDedication() {
		return info.getDedication();
	}

	public void setDedication(String val) {
		info.setDedication(val);
	}

	public boolean getMarkdown() {
		return info.getMarkdown();
	}

	public void setMarkdown(boolean val) {
		info.setMarkdown(val);
	}

	public boolean getScenario() {
		return info.scenarioGet();
	}

	public void setScenario(boolean val) {
		info.scenarioSet(val);
	}

	public String getISBN() {
		return info.getISBN();
	}

	public void setISBN(String val) {
		info.setISBN(val);
	}

	public String getUUID() {
		return info.getUUID();
	}

	public void setUUID(String str) {
		info.setUUID(str);
	}

	public String getLanguage() {
		return info.getLanguage();
	}

	public void setLanguage(String str) {
		info.setLanguage(str);
	}

	public boolean getReview() {
		return info.getReview();
	}

	public void setReview(boolean val) {
		info.setReview(val);
	}

	public static boolean isUseCalendar(MainFrame mainFrame) {
		return getBoolean(mainFrame, Book.PARAM.CALENDAR_USE);
	}

	public static SbCalendar getCalendar(MainFrame m) {
		SbCalendar c = new SbCalendar();
		if (m == null) {
			return (c);
		}
		c.setUse(getBoolean(m, Book.PARAM.CALENDAR_USE));
		if (c.getUse()) {
			c.yeardays = getInteger(m, PARAM.CALENDAR_YEARDAYS.toString(), 365);
			c.setHours(getString(m, PARAM.CALENDAR_HOURS.toString()));
			c.setDays(getString(m, PARAM.CALENDAR_DAYS.toString()));
			c.setMonths(getString(m, PARAM.CALENDAR_MONTHS.toString()));
			c.setStartday(getInteger(m, PARAM.CALENDAR_STARTDAY.toString(), 0));
		}
		return (c);
	}

	public static void storeCalendar(MainFrame m, SbCalendar c) {
		if (m == null) {
			return;
		}
		setBoolean(m, PARAM.CALENDAR_USE, c.getUse());
		setInteger(m, PARAM.CALENDAR_YEARDAYS.toString(), c.yeardays);
		setString(m, PARAM.CALENDAR_HOURS.toString(), c.getListHours());
		setString(m, PARAM.CALENDAR_DAYS.toString(), c.getListDays());
		setString(m, PARAM.CALENDAR_MONTHS.toString(), c.getListMonths());
		setInteger(m, PARAM.CALENDAR_STARTDAY.toString(), c.startday);
	}

	public static boolean getBoolean(MainFrame mainFrame, INFO key) {
		return (getBoolean(mainFrame, key.toString()));
	}

	public static boolean getBoolean(MainFrame mainFrame, PARAM key) {
		return (getBoolean(mainFrame, key.toString()));
	}

	public static boolean getBoolean(MainFrame mainFrame, String key) {
		String val = getString(mainFrame, key);
		if (val != null && (val.equals("true") || val.equals("1"))) {
			return (true);
		}
		return (false);
	}

	public static Integer getInteger(MainFrame mainFrame, INFO key, Integer def) {
		return (getInteger(mainFrame, key.toString(), def));
	}

	public static Integer getInteger(MainFrame mainFrame, PARAM key, Integer def) {
		return (getInteger(mainFrame, key.toString(), def));
	}

	public static Integer getInteger(MainFrame mainFrame, String key, Integer def) {
		String val = getString(mainFrame, key);
		if (val != null && !val.isEmpty()) {
			return (Integer.valueOf(val));
		}
		return (def);
	}

	public static Long getLong(MainFrame mainFrame, String key, Long def) {
		String val = getString(mainFrame, key);
		if (val != null && !val.isEmpty()) {
			return (Long.valueOf(val));
		}
		return (def);
	}

	public static String getString(MainFrame mainFrame, INFO key) {
		return (getString(mainFrame, key.toString()));
	}

	public static String getString(MainFrame mainFrame, PARAM key) {
		return (getString(mainFrame, key.toString()));
	}

	public static String getString(MainFrame mainFrame, String key) {
		if (mainFrame == null) {
			return ("");
		}
		if (key == null || key.isEmpty()) {
			return ("");
		}
		Model model = mainFrame.getBookModel();
		if (model == null) {
			LOG.err(TT + ".getString(mainframe," + key + ") error model=null");
			return ("");
		}
		@SuppressWarnings("null")
		Session session = model.beginTransaction();
		InternalDAO dao = new InternalDAO(session);
		Internal internal = dao.findByKey(key);
		if (internal == null) {
			internal = new Internal(key, "");
			session.save(internal);
		}
		model.commit();
		return (internal.getStringValue());
	}

	public Internal get(MainFrame mainFrame, INFO key) {
		return (get(mainFrame, key.toString(), ""));
	}

	public Internal get(MainFrame mainFrame, PARAM key) {
		return (get(mainFrame, key.toString(), ""));
	}

	public Internal get(MainFrame mainFrame, String strKey, Object val) {
		Model model = mainFrame.getBookModel();
		if (model == null) {
			LOG.err(TT + ".get(mainframe," + strKey + ", " + (val == null ? "null" : val.toString()) + ") error model=null");
		}
		@SuppressWarnings("null")
		Session session = model.beginTransaction();
		InternalDAO dao = new InternalDAO(session);
		Internal internal = dao.findByKey(strKey);
		if (internal == null) {
			internal = new Internal(strKey, val);
			session.save(internal);
		}
		model.commit();
		return internal;
	}

	public static void setString(MainFrame mainFrame, INFO key, String val) {
		setString(mainFrame, key.toString(), val);
	}

	public static void setString(MainFrame mainFrame, PARAM key, String val) {
		setString(mainFrame, key.toString(), val);
	}

	public static void setString(MainFrame mainFrame, String strKey, Object val) {
		if (mainFrame == null) {
			return;
		}
		Model model = mainFrame.getBookModel();
		Session session = model.beginTransaction();
		InternalDAO dao = new InternalDAO(session);
		dao.saveOrUpdate(strKey, val);
		model.commit();
	}

	public static void setBoolean(MainFrame mainFrame, INFO key, boolean val) {
		setBoolean(mainFrame, key.toString(), val);
	}

	public static void setBoolean(MainFrame mainFrame, PARAM key, boolean val) {
		setBoolean(mainFrame, key.toString(), val);
	}

	public static void setBoolean(MainFrame mainFrame, String key, boolean val) {
		setString(mainFrame, key, (val ? "1" : "0"));
	}

	public static void setInteger(MainFrame mainFrame, INFO key, Integer val) {
		setInteger(mainFrame, key.toString(), val);
	}

	public static void setInteger(MainFrame mainFrame, PARAM key, Integer val) {
		setInteger(mainFrame, key.toString(), val);
	}

	public static void setInteger(MainFrame mainFrame, String key, Integer val) {
		setString(mainFrame, key, val.toString());
	}

	public static void setLong(MainFrame mainFrame, INFO key, Long val) {
		setLong(mainFrame, key.toString(), val);
	}

	public static void setLong(MainFrame mainFrame, PARAM key, Long val) {
		setLong(mainFrame, key.toString(), val);
	}

	public static void setLong(MainFrame mainFrame, String key, Long val) {
		setString(mainFrame, key, val.toString());
	}

	public boolean isScenario() {
		return getBoolean(INFO.SCENARIO);
	}

	public boolean isMarkdown() {
		return getBoolean(INFO.MARKDOWN);
	}

	/**
	 * get number of Strands
	 *
	 * @param m
	 * @return
	 */
	public static int getNbStrands(MainFrame m) {
		Model model = m.getBookModel();
		Session session = model.beginTransaction();
		StrandDAO dao = new StrandDAO(session);
		return dao.findAll().size();
	}

	/**
	 * get number of Parts
	 *
	 * @param m
	 * @return
	 */
	public static int getNbParts(MainFrame m) {
		Model model = m.getBookModel();
		Session session = model.beginTransaction();
		PartDAO dao = new PartDAO(session);
		return dao.findAll().size();
	}

	/**
	 * get nummber of Chapters
	 *
	 * @param m
	 * @return
	 */
	public static int getNbChapters(MainFrame m) {
		Model model = m.getBookModel();
		Session session = model.beginTransaction();
		ChapterDAO dao = new ChapterDAO(session);
		return dao.findAll().size();
	}

	/**
	 * get number of Scenes
	 *
	 * @param m
	 * @return
	 */
	public static int getNbScenes(MainFrame m) {
		Model model = m.getBookModel();
		Session session = model.beginTransaction();
		SceneDAO dao = new SceneDAO(session);
		return dao.findAll().size();
	}

	/**
	 * get number of Scenes in the given Chapter
	 *
	 * @param mainFrame
	 * @param chapter
	 * @return
	 */
	public static int getNbScenesInChapter(MainFrame mainFrame, Chapter chapter) {
		if (chapter == null) {
			return (0);
		}
		Model model = mainFrame.getBookModel();
		Session session = model.beginTransaction();
		ChapterDAO dao = new ChapterDAO(session);
		List<Scene> scenes = dao.findScenes(chapter);
		return scenes.size();
	}

	/**
	 * get number of Persons
	 *
	 * @param mainFrame
	 * @return
	 */
	public static int getNbPersons(MainFrame mainFrame) {
		return EntityUtil.findEntities(mainFrame, TYPE.PERSON).size();
	}

	/**
	 * get number of Locations
	 *
	 * @param mainFrame
	 * @return
	 */
	public static int getNbLocations(MainFrame mainFrame) {
		return EntityUtil.findEntities(mainFrame, TYPE.LOCATION).size();
	}

	/**
	 * get number of Items
	 *
	 * @param mainFrame
	 * @return
	 */
	public static int getNbItems(MainFrame mainFrame) {
		return EntityUtil.findEntities(mainFrame, TYPE.ITEM).size();
	}

	/**
	 * remove a Table key
	 *
	 * @param mainFrame
	 * @param prefix
	 */
	public static void removeTableKey(MainFrame mainFrame, String prefix) {
		Model model = mainFrame.getBookModel();
		Session session = model.beginTransaction();
		String sql = "DELETE FROM Internal WHERE key LIKE '" + prefix + "%'";
		org.hibernate.Query stmt = session.createQuery(sql);
		stmt.executeUpdate();
		model.commit();
	}

	/**
	 * check for the key exists
	 *
	 * @param mainFrame
	 * @param strKey
	 * @return
	 */
	public static boolean isKeyExist(MainFrame mainFrame, String strKey) {
		Model model = mainFrame.getBookModel();
		Session session = model.beginTransaction();
		InternalDAO dao = new InternalDAO(session);
		Internal internal = dao.findByKey(strKey);
		boolean b = internal != null;
		model.commit();
		return b;
	}

	/**
	 * get the param for backup
	 *
	 * @return
	 */
	public BookParamBackup getParamBackup() {
		return param.getParamBackup();
	}

	/**
	 * get the param
	 *
	 * @return
	 */
	public BookParam getParam() {
		return param;
	}

	/**
	 * check for using an external editor (like MSWord or LibreOffice Writer)
	 *
	 * @return
	 */
	public boolean isUseXeditor() {
		return param.getParamEditor().getUse();
	}

	/**
	 * get all existing types of Entity
	 *
	 * @return
	 */
	public static List<Book.TYPE> getTypes() {
		List<Book.TYPE> list = new ArrayList<>();
		list.add(Book.TYPE.ATTRIBUTE);
		list.add(Book.TYPE.CHAPTER);
		list.add(Book.TYPE.CATEGORY);
		list.add(Book.TYPE.ENDNOTE);
		list.add(Book.TYPE.EVENT);
		list.add(Book.TYPE.GENDER);
		list.add(Book.TYPE.IDEA);
		list.add(Book.TYPE.INTERNAL);
		list.add(Book.TYPE.ITEM);
		list.add(Book.TYPE.ITEMLINK);
		list.add(Book.TYPE.LOCATION);
		list.add(Book.TYPE.MEMO);
		list.add(Book.TYPE.PART);
		list.add(Book.TYPE.PERSON);
		list.add(Book.TYPE.PLOT);
		list.add(Book.TYPE.RELATION);
		list.add(Book.TYPE.SCENE);
		list.add(Book.TYPE.STRAND);
		list.add(Book.TYPE.TAG);
		list.add(Book.TYPE.TAGLINK);
		return list;
	}

}
