package semorg.gui.util;

import java.sql.SQLException;
import java.util.Vector;

import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;

import semorg.gui.provider.DelayedPaymentItemTableProvider;
import semorg.sql.tables.AbstractTable;
import semorg.sql.tables.ClientBooking;
import semorg.sql.util.DBColumn;
import semorg.sql.util.DistinctVector;
import semorg.sql.util.Utility;

/**
 * This class provides a SWT control to view the delayed payments. It does not
 * provide any possibilities to change the displayed data records.
 */
public class DelayedPaymentViewerControl extends Composite {

    /** The wrapper for the GUI table. */
    private TableViewer mainTableViewer;

    /** The id of the actual client to get the related delayed payments. */
    private int referencedFK;

    /** The columns of the GUI table. */
    private Vector<DBColumn> columns;

    /**
     * These listeners react on changes in the database tables by updating the
     * GUI table.
     */
    private DistinctVector<DBTableChangedListener> updateListeners;

    /**
     * Creates an instance of this class.
     * 
     * @param parent
     *                the parent composite which includes this control.
     * @param parentShell
     *                the shell which includes this control, it is needed for
     *                removing the listeners when closing the window.
     */
    public DelayedPaymentViewerControl(Composite parent, Shell parentShell) {
	super(parent, SWT.NULL);

	FormLayout mainLayout = new FormLayout();
	this.setLayout(mainLayout);

	// creating the main table viewer and setup
	mainTableViewer = new TableViewer(this, SWT.BORDER | SWT.MULTI
		| SWT.FULL_SELECTION);
	mainTableViewer.getTable().setLayoutData(
		Utility.getFormData(parent, 2, 100, 0, 0, 0, 100, 0));
	mainTableViewer.setContentProvider(new ArrayContentProvider());

	mainTableViewer.setLabelProvider(new DelayedPaymentItemTableProvider());

	// setup the columns
	Vector<DBColumn> tmp = ClientBooking.getColumns();
	this.columns = new Vector<DBColumn>();
	this.columns.add(tmp.get(6));
	this.columns.add(tmp.get(3));
	this.columns
		.add(new DBColumn(
			"charge",
			Messages
				.getString("GUIText.DelayedPaymentViewerControlChargeColumnText"),
			Float.class));

	Table mainTable = mainTableViewer.getTable();

	final TableColumn[] tc = new TableColumn[columns.size()];

	mainTable.setHeaderVisible(true);
	for (int i = 0; i < tc.length; i++) {
	    tc[i] = new TableColumn(mainTable, SWT.LEFT);
	    tc[i].setWidth(110);
	    tc[i].setText(columns.get(i).getPublicColumnName());
	}

	// add some listeners
	updateListeners = new DistinctVector<DBTableChangedListener>();

	addUpdateListener(DBTableChangedListener.TYPE_CLIENTBOOKING);
	addUpdateListener(DBTableChangedListener.TYPE_SEMINARTYPE);

	// remove the listeners when the containing window is closed
	parentShell.addListener(SWT.Close, new Listener() {
	    public void handleEvent(Event event) {
		for (int i = 0; i < updateListeners.size(); i++) {
		    AbstractTable.removeDBTableChangedListener(updateListeners
			    .elementAt(i));
		}
	    }
	});

	/* TODO: implement sort ability, db functions are not applictable */
    }

    /**
     * Sets the new input of the GUI table containig all delayed payment.
     * 
     * @param referencedFK
     *                the id of client booking corresponding to the delayed
     *                payment.
     * @throws SQLException
     *                 If the creation, manipulation, execution or closing of a
     *                 PreparedStatement instance used for querying the database
     *                 fails.
     */
    public void setInput(int referencedFK) throws SQLException {

	this.referencedFK = referencedFK;
	DistinctVector<DelayedPaymentItem> input = new DistinctVector<DelayedPaymentItem>();
	ClientBooking tmpClientBooking = null;

	if (this.referencedFK == AbstractTable.NULL_ID) {
	    mainTableViewer.setInput(new DistinctVector<DelayedPaymentItem>());
	} else {
	    try {
		DistinctVector<ClientBooking> bookings = ClientBooking
			.getBookingsOfClient(this.referencedFK);

		for (int i = 0; i < bookings.size(); i++) {
		    tmpClientBooking = bookings.elementAt(i);
		    // add only elements where the client is a debtor
		    if (tmpClientBooking.getDebitorId() == this.referencedFK) {
			input.add(new DelayedPaymentItem(tmpClientBooking
				.getPresentationId(), tmpClientBooking
				.getBilled()));
		    }

		}
		mainTableViewer.setInput(input);
	    } catch (SQLException e) {
		mainTableViewer.setInput(null);
		throw e;
	    }

	}
    }

    /**
     * Adds a listener to the {@link #updateListeners} vector.
     * 
     * @param type
     *                the wanted type of the DBTableChangedListener
     */
    private void addUpdateListener(int type) {
	updateListeners.add(new DBTableChangedListener(type) {
	    public void dBTableChanged() {
		update();
	    }
	});

	AbstractTable.addDBTableChangedListener(updateListeners.lastElement());
    }

    /**
     * Updates the GUI table with the actual records from a database query. <br>
     * <br>
     * For example if the rows of the GUI table are sorted by a column or a
     * record has been deleted.
     */
    public void update() {
	try {
	    setInput(referencedFK);
	} catch (SQLException e) {
	    e.printStackTrace();
	}

    }

}
