/*
Storybook: Open Source software for novelists and authors.
Copyright (C) 2008 - 2012 Martin Mustun

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.ui.table;

import api.mig.swing.MigLayout;
import i18n.I18N;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import org.hibernate.Session;
import resources.icons.ICONS;
import storybook.App;
import storybook.ctrl.ActKey;
import storybook.ctrl.Ctrl.PROPS;
import storybook.exim.exporter.ExportToPhpBB;
import storybook.model.EntityUtil;
import storybook.model.Model;
import storybook.model.book.Book;
import storybook.model.hbn.dao.SceneDAO;
import storybook.model.hbn.entity.AbstractEntity;
import storybook.model.hbn.entity.Chapter;
import storybook.model.DB;
import storybook.model.hbn.entity.Part;
import storybook.model.hbn.entity.Person;
import storybook.model.hbn.entity.Scene;
import storybook.model.hbn.entity.Status;
import storybook.model.hbn.entity.Status.STATUS;
import storybook.model.hbn.entity.Strand;
import storybook.model.state.SceneStatus;
import storybook.tools.DateUtil;
import storybook.tools.LOG;
import storybook.tools.SbDuration;
import storybook.tools.TextUtil;
import storybook.tools.comparator.ObjectComparator;
import storybook.tools.html.Html;
import storybook.ui.MainFrame;
import storybook.ui.Ui;
import static storybook.ui.Ui.*;
import storybook.ui.renderer.lcr.LCRStatus;
import static storybook.ui.table.AbsColumn.*;

/**
 * @author martin
 *
 */
public class SceneTable extends AbstractTable implements ActionListener {

	private static final String TT = "SceneTable";

	private JPanel pStrand;
	private JPanel pNarrator;

	public enum ACT {
		CB_STATUS,
		CB_STRAND,
		CB_NARRATOR,
		NONE;
	}

	public ACT getACT(String act) {
		for (ACT a : ACT.values()) {
			if (a.name().equals(act)) {
				return (a);
			}
		}
		return (ACT.NONE);
	}

	private static final String BT_EXTERNAL = "BtEXTERNAL";

	private JComboBox cbStatus;
	private JComboBox cbStrand;
	private JComboBox cbNarrator;

	public SceneTable(MainFrame mainFrame) {
		super(mainFrame, Book.TYPE.SCENE);
	}

	@Override
	public void init() {
		withPart = true;
	}

	@SuppressWarnings({"unchecked"})
	@Override
	public List<AbstractEntity> getAllEntities() {
		//LOG.trace(TT + ".getAllEntities()");
		int fStatus = cbStatus.getSelectedIndex();
		Part fPart = null;
		if (cbPartFilter != null && cbPartFilter.getSelectedIndex() > 0) {
			fPart = (Part) cbPartFilter.getSelectedItem();
		}
		Strand fStrand = null;
		if (cbStrand.getSelectedIndex() > 0) {
			fStrand = (Strand) cbStrand.getSelectedItem();
		}
		Person fNarrator = null;
		if (cbNarrator.getSelectedIndex() > 0) {
			fNarrator = (Person) cbNarrator.getSelectedItem();
		}
		List<AbstractEntity> entities = EntityUtil.findEntities(mainFrame, getType());
		List<AbstractEntity> scenes = new ArrayList<>();
		for (AbstractEntity e : entities) {
			Scene s = (Scene) e;
			if (fPart != null && s.hasChapter()) {
				Chapter chapter = s.getChapter();
				if (chapter.hasPart() && !chapter.getPart().equals(fPart)) {
					continue;
				}
			}
			boolean b = true;
			if (fStatus < STATUS.values().length && s.getStatus() != fStatus) {
				b = false;
			}
			if (cbNarrator.getSelectedIndex() > 0 && fNarrator != null && !fNarrator.equals(s.getNarrator())) {
				b = false;
			}
			if (cbStrand.getSelectedIndex() > 0) {
				if (fStrand != null && !fStrand.equals(s.getStrand())
					&& (s.getStrands() != null && !s.getStrands().contains(fStrand))) {
					b = false;
				}
			}
			if (b) {
				scenes.add(s);
			}
		}
		return (scenes);
	}

	@Override
	@SuppressWarnings("unchecked")
	public JToolBar initToolbar() {
		//LOG.trace(TT + ".initToolbar(withPart=" + (withPart ? "true" : "false") + ")");
		super.initToolbar();
		//todo à remplcer par un bouton de filtrage
		toolbar.add(new JLabel(I18N.getColonMsg("status")));
		cbStatus = initCbStatus();
		toolbar.add(cbStatus);

		pStrand = new JPanel(new MigLayout());
		pStrand.setOpaque(false);
		pStrand.add(new JLabel(I18N.getColonMsg("strand")));
		cbStrand = new JComboBox();
		cbStrand.setName(ACT.CB_STRAND.toString());
		Ui.fillCB(cbStrand, EntityUtil.findEntities(mainFrame, Book.TYPE.STRAND), BALL, this);
		cbStrand.setSelectedIndex(0);
		cbStrand.addActionListener(this);
		pStrand.add(cbStrand);
		toolbar.add(pStrand);

		pNarrator = new JPanel(new MigLayout());
		pNarrator.setOpaque(false);
		pNarrator.add(new JLabel(I18N.getColonMsg("scene.narrator")));
		cbNarrator = new JComboBox();
		cbNarrator.setName(ACT.CB_NARRATOR.toString());
		Ui.fillCB(cbNarrator, SceneDAO.findNarrators(mainFrame), BALL, this);
		cbNarrator.setSelectedIndex(0);
		cbNarrator.addActionListener(this);
		pNarrator.add(cbNarrator);
		toolbar.add(pNarrator);

		return toolbar;
	}

	@SuppressWarnings("unchecked")
	private JComboBox initCbStatus() {
		JComboBox cb = new JComboBox();
		cb.setName("cbStatus");
		for (Status.STATUS st : Status.STATUS.values()) {
			cb.addItem(st.ordinal());
		}
		cb.addItem(I18N.getMsg("status.all"));
		cb.setSelectedIndex(cb.getItemCount() - 1);
		cb.setRenderer(new LCRStatus());
		cb.addActionListener(this);
		return (cb);
	}

	/**
	 * initialize the footer
	 *
	 * @return
	 */
	@Override
	public JToolBar initFooter() {
		JToolBar footer = super.initFooter();
		if (mainFrame.getBook().isUseXeditor()) {
			btExternal = Ui.initButton(BT_EXTERNAL, "", ICONS.K.LIBREOFFICE,
				"", e -> sendSetExternal(table.getSelectedRow()));
			//btExternal.setText(book.getParamEditor().getName());
			btExternal.setToolTipText(I18N.getMsg("xeditor.launching")
				+ " " + book.getParam().getParamEditor().getName());
			btExternal.setEnabled(false);
			footer.add(btExternal);
		}
		return footer;
	}

	@Override
	public void fillTable() {
		super.fillTable();
		if (pStrand != null) {
			pStrand.setVisible(EntityUtil.findEntities(mainFrame, Book.TYPE.STRAND).size() > 1);
		}
		if (pNarrator != null) {
			pNarrator.setVisible(EntityUtil.findEntities(mainFrame, Book.TYPE.PERSON).size() > 1);
		}
	}

	@Override
	public synchronized void actionPerformed(ActionEvent e) {
		//LOG.trace(TT + ".actionPerformed(" + e.toString() + ")");
		if (e.getSource() instanceof JComboBox) {
			fillTable();
			return;
		}
		super.actionPerformed(e);
	}

	@Override
	protected void modelPropertyChangeLocal(PropertyChangeEvent evt) {
		//LOG.trace(TT + ".modelPropertyChangeLocal(evt=" + evt.toString() + ")");
		try {
			String propName = evt.getPropertyName();
			Object newValue = evt.getNewValue();
			ActKey act = new ActKey(evt);
			if (isInit(act)) {
				return;
			}
			if ("UPDATE".equals(act.getCmd())) {
				fillTable();
				return;
			}
			switch (Book.getTYPE(act.type)) {
				case PART:
					if (isChange(act)) {
						Ui.fillCB(cbPartFilter, EntityUtil.findEntities(mainFrame, getType()), "", this);
					}
					break;
				case SCENE:
					if (PROPS.SCENE_FILTER_STATUS.check(propName)) {
						initTableModel(evt);
						if (newValue instanceof SceneStatus) {
							cbStatus.setSelectedItem((SceneStatus) newValue);
						}
					} else if (PROPS.SCENE_FILTER_NARRATOR.check(propName)) {
						initTableModel(evt);
						if (newValue instanceof String) {
							cbNarrator.setSelectedItem((String) newValue);
						}
					} else if (PROPS.SCENE_FILTER_STRAND.check(propName)) {
						initTableModel(evt);
						if (newValue instanceof String) {
							cbStrand.setSelectedItem((String) newValue);
						}
					}
					break;
				case STRAND:
					if (isChange(act)) {
						int nx = cbStrand.getSelectedIndex();
						Strand os = (Strand) cbStrand.getSelectedItem();
						Ui.fillCB(cbStrand, EntityUtil.findEntities(mainFrame, Book.TYPE.STRAND), "");
						if (nx != 0 && os != null) {
							cbStrand.setSelectedItem(os);
						}
					}
					break;
				default:
					break;
			}
		} catch (Exception e) {
		}
	}

	@Override
	protected AbstractEntity getEntity(Long id) {
		Model model = mainFrame.getBookModel();
		Session session = model.beginTransaction();
		SceneDAO dao = new SceneDAO(session);
		Scene scene = dao.find(id);
		model.commit();
		return scene;
	}

	@Override
	public void updateRow(AbstractEntity entity) {
		// refresh for chapter, item, location, person, scenario, scene, strand, photo
		switch (Book.getTYPE(entity)) {
			case CHAPTER:
			case ITEM:
			case LOCATION:
			case PLOT:
			//case SCENARIO:
			case SCENE:
				fillTable();
				break;
			case STRAND:
				Ui.fillCB(cbStrand, EntityUtil.findEntities(mainFrame, Book.TYPE.STRAND), BALL, this);
				fillTable();
				break;
			case PERSON:
				Ui.fillCB(cbNarrator, SceneDAO.findNarrators(mainFrame), BALL, this);
				fillTable();
			default:
				break;
		}
	}

	@Override
	public List<AbsColumn> getColumns(AbstractEntity entity) {
		List<AbsColumn> cols = super.getColumns(entity);
		AbsColumn col;
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.INFORMATIVE, TCR_HIDE, AL_CENTER, TCR_BOOLEAN));
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.NUMBER, NUMERIC, TCR_HIDE, AL_CENTER));
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.STATUS, AL_CENTER, TCR_STATUS));
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.INTENSITY, AL_CENTER, TCR_HIDE, TCR_COLOR, AL_CENTER));
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.CCSS, TCR_HIDE, AL_CENTER));
		col = new AbsColumn(mainFrame, cols, DB.DATA.SCENE_CHAPTER, TCR_ENTITY);
		col.setComparator(new ObjectComparator());
		cols.add(col);
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.WORDS, NUMERIC_RENDERER, AL_CENTER));
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.CHARACTERS, NUMERIC_RENDERER, AL_CENTER));
		if (App.getAssistant().isExists(book, "stage")) {
			cols.add(new AbsColumn(mainFrame, cols, DB.DATA.SCENARIO_STAGE, TCR_HIDE));
		}
		col = new AbsColumn(mainFrame, cols, DB.DATA.SCENE_SCENETS, TCR_DATE, TCR_HIDE, AL_CENTER);
		col.setMsgKey("date");
		col.setShowDateTime(true);
		cols.add(col);
		col = new AbsColumn(mainFrame, cols, DB.DATA.SCENE_RELATIVESCENEID, TCR_HIDE, AL_CENTER, TCR_SCENEID);
		col.setMsgKey("scene.relativedate.after");
		cols.add(col);
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.SCENE_RELATIVETIME, TCR_HIDE, AL_CENTER));
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.DURATION, TCR_HIDE, AL_CENTER));
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.SCENE_STRAND, TCR_ENTITY, AL_CENTER));
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.STRANDS, TCR_HIDE, TCR_ENTITIES, AL_CENTER));
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.SCENE_NARRATOR, TCR_HIDE, AL_CENTER, TCR_ENTITY));
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.SCENE_SUMMARY, TCR_HIDE));
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.PERSONS, TCR_HIDE, AL_CENTER, TCR_ENTITIES));
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.LOCATIONS, TCR_HIDE, AL_CENTER, TCR_ENTITIES));
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.ITEMS, TCR_HIDE, AL_CENTER, TCR_ENTITIES));
		cols.add(new AbsColumn(mainFrame, cols, DB.DATA.PLOTS, TCR_HIDE, AL_CENTER, TCR_ENTITIES));
		if (book.isScenario()) {
			cols.add(new AbsColumn(mainFrame, cols, DB.DATA.SCENARIO_PITCH, TCR_HIDE));
			cols.add(new AbsColumn(mainFrame, cols, DB.DATA.SCENARIO_LOC, AL_CENTER, TCR_HIDE));
			cols.add(new AbsColumn(mainFrame, cols, DB.DATA.SCENARIO_MOMENT, AL_CENTER, TCR_HIDE));
			cols.add(new AbsColumn(mainFrame, cols, DB.DATA.SCENARIO_START, AL_CENTER, TCR_HIDE));
			cols.add(new AbsColumn(mainFrame, cols, DB.DATA.SCENARIO_END, AL_CENTER, TCR_HIDE));
		}
		getColumnsEnd(cols, entity);
		return cols;
	}

	@Override
	public List<Object> getRow(AbstractEntity entity) {
		List<Object> cols = super.getRow(entity);
		Scene e = (Scene) entity;
		cols.add(e.getInformative());
		cols.add(e.getSceneno());
		cols.add(e.getStatus());
		cols.add(e.getIntensity());
		cols.add(e.getCCSS());
		cols.add(e.getChapter());
		cols.add(e.getWords());
		cols.add(e.getChars());
		if (App.getAssistant().isExists(book, "stage")) {
			cols.add(e.getScenariostage());
		}
		if (e.hasScenets()) {// fixed date
			cols.add(e.getDate());
			cols.add(-1L);
			cols.add(" ");
		} else if (e.hasRelativescene()) {// no fixed date compute the relative date
			Scene sx = (Scene) EntityUtil.findEntityById(mainFrame, Book.TYPE.SCENE, e.getRelativesceneid());
			if (sx != null && sx.getDate() != null) {
				//LOG.trace("relative=" + e.getRelativetime());
				Date dx = DateUtil.addDateTime(sx.getDate(), e.getRelativetime());
				cols.add(dx);
			} else {
				cols.add(" ");
			}
			cols.add(e.getRelativesceneid());
			SbDuration dur;
			if (e.getRelativetime().isEmpty()) {
				dur = new SbDuration(SbDuration.computeFromWords(e.getSummary()));
			} else {
				dur = new SbDuration(e.getRelativetime());
			}
			cols.add(dur.toText(I18N.getMsg("duration.initiales")));
		} else {
			cols.add("");
			cols.add(-1L);
			cols.add(" ");
		}
		cols.add(e.getDurationToText());
		cols.add(e.getStrand());
		cols.add(e.getStrands());
		cols.add(e.getNarrator());
		cols.add(TextUtil.ellipsize(Html.htmlToText(e.getSummary()), 128));
		cols.add(e.getPersons());
		cols.add(e.getLocations());
		cols.add(e.getItems());
		cols.add(e.getPlots());
		// scenario data
		if (book.isScenario()) {
			cols.add(e.getScenariopitch());
			cols.add(e.getScenarioloc());
			cols.add(e.getScenariomoment());
			cols.add(e.getScenariostart());
			cols.add(e.getScenarioend());
		}
		getRowEnd(cols, entity);
		return cols;
	}

	protected synchronized void copyToPhpBB(int row) {
		LOG.trace(TT + ".copyToPhpBB(r=" + row + ")");
		Scene scene = (Scene) getEntityFromRow(row);
		if (scene != null) {
			ExportToPhpBB.getScene(mainFrame, scene);
			JOptionPane.showMessageDialog(mainFrame,
				I18N.getMsg("copied.title"),
				I18N.getMsg(scene.getObjType().toString()), 1);
		}
	}

}
