/*
Storybook: Open Source software for novelists and authors.
Copyright (C) 2015 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.hbn.entity;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import storybook.model.DB.DATA;
import storybook.model.EntityUtil;
import storybook.model.book.Book;
import storybook.tools.ListUtil;
import storybook.tools.Period;
import storybook.tools.xml.XmlKey.XK;
import storybook.tools.xml.XmlUtil;

public class Relationship extends AbstractEntity {

	private Person person1 = null;
	private Person person2 = null;
	//String description = "";
	Scene startScene = null;
	Scene endScene = null;
	private List<Person> persons = new ArrayList<>();
	private List<Item> items = new ArrayList<>();
	private List<Location> locations = new ArrayList<>();

	public Relationship() {
		super(Book.TYPE.RELATION, "110");
	}

	@SuppressWarnings("unchecked")
	public Relationship(ResultSet rs) {
		super(Book.TYPE.RELATION, "110", rs);
		try {
			person1 = rs.getObject("person1", Person.class);
			person2 = rs.getObject("person2", Person.class);
			startScene = rs.getObject("startScene", Scene.class);
			endScene = rs.getObject("endScene", Scene.class);
			persons = (List<Person>) rs.getObject("persons", ArrayList.class);
			items = (List<Item>) rs.getObject("items", ArrayList.class);
			locations = (List<Location>) rs.getObject("locations", ArrayList.class);
		} catch (SQLException ex) {
			//empty
		}
	}

	public Relationship(Person person1, Person person2, String description, Scene startScene, Scene endScene, String notes) {
		this();
		this.person1 = person1;
		this.person2 = person2;
		this.startScene = startScene;
		this.endScene = endScene;
		setDescription(description);
		setNotes(notes);
	}

	/*@Override
	public String getName() {
		if (super.getName().isEmpty()) {
			return (description);
		}
		return name;
	}*/
	public boolean hasPersons() {
		if (hasPerson1()) {
			return (true);
		}
		if (hasPerson2()) {
			return (true);
		}
		return (!getPersons().isEmpty());
	}

	public Person getPerson1() {
		return this.person1;
	}

	public boolean hasPerson1() {
		return person1 != null;
	}

	public void setPerson1(Person person) {
		this.person1 = person;
	}

	public void setPerson1() {
		this.person1 = null;
	}

	public Person getPerson2() {
		return this.person2;
	}

	public boolean hasPerson2() {
		return person2 != null;
	}

	public void setPerson2(Person person) {
		this.person2 = person;
	}

	public void setPerson2() {
		this.person2 = null;
	}

	public Scene getStartScene() {
		return this.startScene;
	}

	public boolean hasStartScene() {
		return this.startScene != null;
	}

	public void setStartScene(Scene startScene) {
		this.startScene = startScene;
	}

	public Scene getEndScene() {
		return this.endScene;
	}

	public boolean hasEndScene() {
		return endScene != null;
	}

	public void setEndScene(Scene endScene) {
		this.endScene = endScene;
	}

	public List<Person> getPersons() {
		List<Person> lst = new ArrayList<>();
		lst.addAll(persons);
		if (hasPerson1() && !persons.contains(person1)) {
			lst.add(person1);
		}
		if (hasPerson2() && !persons.contains(person2)) {
			lst.add(person2);
		}
		return lst;
	}

	public String getPersonList() {
		List<String> lst = new ArrayList<>();
		if (getPerson1() != null) {
			lst.add(getPerson1().getName());
		}
		if (getPerson2() != null) {
			lst.add(getPerson2().getName());
		}
		for (Person p : persons) {
			lst.add(p.getName());
		}
		return (ListUtil.join(lst));
	}

	public void setPersons(List<Person> persons) {
		this.persons = persons;
	}

	public int numberOfPersons() {
		return (persons.size());
	}

	public boolean hasItems() {
		if (items == null) {
			return (false);
		}
		return (!items.isEmpty());
	}

	public List<Item> getItems() {
		return items;
	}

	public String getItemList() {
		StringBuilder list = new StringBuilder();
		for (Item item : items) {
			list.append(item.getName()).append(",");
		}
		return (list.toString());
	}

	public void setItems(List<Item> items) {
		this.items = items;
	}

	public int numberOfItems() {
		return (items.size());
	}

	public boolean hasLocations() {
		if (locations == null) {
			return (false);
		}
		return (!locations.isEmpty());
	}

	public List<Location> getLocations() {
		return locations;
	}

	public String getLocationList() {
		StringBuilder list = new StringBuilder();
		for (Location loc : locations) {
			list.append(loc.getName()).append(",");
		}
		return (list.toString());
	}

	public void setLocations(List<Location> locations) {
		this.locations = locations;
	}

	public int numberOfLocations() {
		return (locations.size());
	}

	public boolean hasPeriod() {
		return (this.getStartScene() != null && this.getEndScene() != null);
	}

	public Period getPeriod() {
		if (hasPeriod()) {
			return new Period(getStartScene().getScenets(), getEndScene().getScenets());
		}
		if (hasStartScene()) {
			return new Period(getStartScene().getScenets(), getStartScene().getScenets());
		}
		return null;
	}

	@Override
	public String toCsv(String quoteStart, String quoteEnd, String separator) {
		StringBuilder b = new StringBuilder();
		b.append(quoteStart).append(getClean(this)).append(quoteEnd).append(separator);
		b.append(quoteStart).append(getClean(getName())).append(quoteEnd).append(separator);
		b.append(quoteStart).append(getClean(person1)).append(quoteEnd).append(separator);
		b.append(quoteStart).append(getClean(person2)).append(quoteEnd).append(separator);
		b.append(quoteStart).append(getClean(startScene)).append(quoteEnd).append(separator);
		b.append(quoteStart).append(getClean(endScene)).append(quoteEnd).append(separator);
		b.append(quoteStart);
		for (Person p : getPersons()) {
			b.append(p.getId().toString()).append("/");
		}
		b.append(quoteEnd).append(separator);
		b.append(quoteStart);
		for (Item p : getItems()) {
			b.append(p.getId().toString()).append("/");
		}
		b.append(quoteEnd).append(separator);
		b.append(quoteStart);
		for (Location p : getLocations()) {
			b.append(p.getId().toString()).append("/");
		}
		b.append(quoteEnd).append(separator);
		b.append(quoteStart).append(getClean(getDescription())).append(quoteEnd).append(separator);
		b.append(quoteStart).append(getClean(getNotes())).append(quoteEnd).append("\n");
		return (b.toString());
	}

	@Override
	public String toHtml() {
		return (toCsv("<td>", "</td>", "\n"));
	}

	@Override
	public String toText() {
		return (toCsv("", "", "\t"));
	}

	@Override
	public String toDetail(Integer detailed) {
		StringBuilder b = new StringBuilder();
		b.append(toDetailHeader(detailed));
		b.append(getInfo(detailed, DATA.SCENE_START, getStartScene()));
		b.append(getInfo(detailed, DATA.SCENE_END, getEndScene()));
		b.append(getInfo(detailed, DATA.PERSONS, EntityUtil.getNames(persons)));
		b.append(getInfo(detailed, DATA.LOCATIONS, EntityUtil.getNames(locations)));
		b.append(getInfo(detailed, DATA.ITEMS, EntityUtil.getNames(items)));
		b.append(toDetailFooter(detailed));
		return (b.toString());
	}

	@Override
	public String toXml() {
		StringBuilder b = new StringBuilder(toXmlBeg());
		List<String> list = new ArrayList<>();
		if (getPerson1() != null) {
			list.add(getClean(getPerson1().getId()));
		}
		if (getPerson2() != null) {
			list.add(getClean(getPerson2().getId()));
		}
		if (startScene != null) {
			b.append(XmlUtil.setAttribute(2, XK.START, getClean(startScene.getId())));
		}
		if (endScene != null) {
			b.append(XmlUtil.setAttribute(0, XK.END, getClean(endScene.getId())));
		}
		b.append(XmlUtil.setAttribute(2, XK.PERSONS, EntityUtil.getIds(persons)));
		b.append(XmlUtil.setAttribute(2, XK.LOCATIONS, EntityUtil.getIds(locations)));
		b.append(XmlUtil.setAttribute(2, XK.ITEMS, EntityUtil.getIds(items)));
		b.append(">\n");
		b.append(toXmlEnd());
		return b.toString();
	}

	@Override
	@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
	public boolean equals(Object obj) {
		if (!super.equals(obj)) {
			return false;
		}
		return (this.toXml().equals(((Relationship) obj).toXml()));
	}

	@Override
	public int hashCode() {
		return hashPlus(super.hashCode(),
		   startScene,
		   endScene,
		   person1,
		   person2,
		   persons,
		   items,
		   locations);
	}

	public static Relationship find(List<Relationship> list, String str) {
		for (Relationship elem : list) {
			if (elem.getName().equals(str)) {
				return (elem);
			}
		}
		return (null);
	}

	public static Relationship find(List<Relationship> list, Long id) {
		for (Relationship elem : list) {
			if (elem.id.equals(id)) {
				return (elem);
			}
		}
		return (null);
	}

	public static List<String> getDefColumns() {
		List<String> list = AbstractEntity.getDefColumns(Book.TYPE.RELATION);
		return (list);
	}

	public static List<String> getTable() {
		List<String> ls = new ArrayList<>();
		String tableName = "relationship";
		AbstractEntity.getTable(tableName, ls);
		ls.add(tableName + ",person1_id,Integer,0");
		ls.add(tableName + ",person2_id,Integer,0");
		ls.add(tableName + ",start_scene_id,Integer,0");
		ls.add(tableName + ",end_scene_id,Integer,0");
		ls.add(tableName + ",persons,Table.Person,0");
		ls.add(tableName + ",locations,Table.Location,0");
		ls.add(tableName + ",items,Table.Item,0");
		return (ls);
	}

}
