package industries.doublehelix.conditionalfilter.gui.filtersettings;

import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

import javax.swing.Box;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;

import org.freixas.jcalendar.DateEvent;
import org.freixas.jcalendar.DateListener;
import org.freixas.jcalendar.JCalendar;
import org.freixas.jcalendar.JCalendarCombo;

import industries.doublehelix.conditionalfilter.filtertypes.flat.DateFilter.DateFilterMode;
import industries.doublehelix.conditionalfilter.filtertypes.flat.DateTimeFilter;

public class DateTimeFilterSettingsPanel extends FilterSettingsPanel implements ActionListener {
	private static final long serialVersionUID = -6614004532630323774L;
	
	JComboBox<DateFilterMode> filterMode = new JComboBox<>();
	JCalendarCombo date = new JCalendarCombo(JCalendar.DISPLAY_DATE | JCalendar.DISPLAY_TIME, false);
	JCalendarCombo secondDate = new JCalendarCombo(JCalendar.DISPLAY_DATE | JCalendar.DISPLAY_TIME, false);
	
	JLabel lblAnd = new JLabel("and");
	Component spacerForLabel = null;
	Component spacerForSecondDate = Box.createHorizontalGlue();
	
	public DateTimeFilterSettingsPanel(DateTimeFilter filter, int preferredContentHeight) {
		super(filter, preferredContentHeight);
		
		filterMode.setModel(new DefaultComboBoxModel<>(DateFilterMode.values()));
	//	filterMode.setMaximumSize(filterMode.getPreferredSize());
		filterMode.setSelectedItem(filter.getFilterMode());
		filterMode.addActionListener(this);
		
		date.setDate(Date.from(filter.getFirstDateTime().atZone(ZoneId.systemDefault()).toInstant()));
		// value of second number is set below via displaySecondNumber
		
		// getSource() of date event does not return the date combobox, so some rerouting is needed
		date.addDateListener(new DateListener() {
			@Override
			public void dateChanged(DateEvent arg0) {
				dateComboChanged(date);
			}
		});
		secondDate.addDateListener(new DateListener() {
			@Override
			public void dateChanged(DateEvent arg0) {
				dateComboChanged(secondDate);
			}
		});
		
		setPreferredHeightToComponents(date, secondDate, filterMode);
		//date.setPreferredSize(new Dimension(230, date.getPreferredSize().height));
		//secondDate.setPreferredSize(new Dimension(230, secondDate.getPreferredSize().height));
		
		this.add(filterMode);
		this.add(Box.createHorizontalStrut(5));
		GridBagConstraints c = new GridBagConstraints();
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 1.0;
		this.add(date, c);
		this.add(Box.createHorizontalStrut(5));
		
		// build second label
		spacerForLabel = Box.createHorizontalStrut(lblAnd.getPreferredSize().width + 2);
		displaySecondDate(filter);
		this.add(lblAnd);
		this.add(spacerForLabel);
		
		this.add(Box.createHorizontalStrut(5));
		this.add(secondDate, c);
		this.add(spacerForSecondDate, c);
		
		this.add(Box.createHorizontalStrut(5));
	}
	
	private void displaySecondDate(DateTimeFilter filter) {
		boolean twoDateFilter = filter.getFilterMode() == DateFilterMode.BETWEEN
				|| filter.getFilterMode() == DateFilterMode.NOTBETWEEN;
		
		if (twoDateFilter && secondDate.isVisible()) return;
		
		// changed from two numbers to one or vice versa
		spacerForLabel.setVisible(!twoDateFilter);
		spacerForSecondDate.setVisible(!twoDateFilter);
		lblAnd.setVisible(twoDateFilter);
		secondDate.setVisible(twoDateFilter);
		LocalDateTime secondDateTime = filter.getSecondDateTime();
		if (secondDateTime != null) {
			Date secDate = Date.from(secondDateTime.atZone(ZoneId.systemDefault()).toInstant());
			secondDate.setDate(secDate);
		}
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		Object source = e.getSource();
		if (source == filterMode) {
			DateTimeFilter castedFilter = (DateTimeFilter)this.filter;
			DateFilterMode selectedFilterMode = (DateFilterMode)filterMode.getSelectedItem();
			if (selectedFilterMode != castedFilter.getFilterMode()) {
				castedFilter.setFilterMode(selectedFilterMode);
				displaySecondDate(castedFilter);
			}
		}
	}

	private void dateComboChanged(JCalendarCombo source) {
		// determine which of the two date fields was the source. getSource() of date event does not return the
		// date combo box but something else
		DateTimeFilter castedFilter = (DateTimeFilter)this.filter;
		if (source == date) {
			LocalDateTime ldt = LocalDateTime.ofInstant(date.getDate().toInstant(), ZoneId.systemDefault());
			castedFilter.setFirstDateTime(ldt);
		} else if (source == secondDate) {
			LocalDateTime ldt = LocalDateTime.ofInstant(secondDate.getDate().toInstant(), ZoneId.systemDefault());
			castedFilter.setSecondDateTime(ldt);
		}
	}
}
