package com.sap.dbmtk.demo;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;

import net.miginfocom.swing.MigLayout;

import org.jdesktop.swingx.JXDatePicker;
import org.jdesktop.swingx.JXTable;

import com.sap.dbmtk.demo.SqlStatement.Type;
import com.sap.dbmtk.demo.ui.GTable;
import com.sap.dbmtk.demo.utils.DbUtils;
import com.sap.dbmtk.demo.utils.StringUtil;
import com.sap.dbmtk.demo.utils.SwingUtils;

public class AddOrChangeOrder
extends AddOrChangeAbstract
implements ActionListener, KeyListener, FocusListener
{
	private static final long serialVersionUID = 1L;

	private static final String NAME = "Order";

	private static final Color  DEFAULT_BG_COLOR = (new JTextField()).getBackground();

	private int                 _order_id         = -1;
	private JLabel              _order_id_lbl     = new JLabel("order_id");
	private JTextField          _order_id_txt     = new JTextField();

	private JLabel              _store_lbl        = new JLabel("Store Name");
	private JTextField          _store_txt        = new JTextField();
//	private JComboBox           _store_cbx        = new JComboBox();
	private JButton             _store_but        = new JButton("...");
	
	private JLabel              _orderdate_lbl    = new JLabel("Order Date");
//	private JXDateTimePicker    _orderdate_dtp    = new JXDateTimePicker();
	private JXDatePicker        _orderdate_dtp    = new JXDatePicker(new java.util.Date(System.currentTimeMillis()));


	
	
	private OrderDetailsModel   _orderDetails_mod = new OrderDetailsModel();
	private OrderDetailsTable   _orderDetails_tab = new OrderDetailsTable(_orderDetails_mod);

	private JLabel              _title_lbl        = new JLabel("Title");
	private JTextField          _title_txt        = new JTextField();
//	private JComboBox           _title_cbx        = new JComboBox();
	private JButton             _title_but        = new JButton("...");
	
	private JLabel              _isbn_lbl         = new JLabel("ISBN");
	private JTextField          _isbn_txt         = new JTextField();
//	private JComboBox           _isbn_cbx         = new JComboBox();
	private JButton             _isbn_but         = new JButton("...");

	private JLabel              _quantity_lbl     = new JLabel("Quantity");
//	private JFormattedTextField _quantity_txt     = new JFormattedTextField(NumberFormat.getNumberInstance());
	private JTextField          _quantity_txt     = new JTextField();

	private JLabel              _discount_lbl     = new JLabel("Discount");
//	private JFormattedTextField _discount_txt     = new JFormattedTextField(NumberFormat.getNumberInstance());
	private JTextField          _discount_txt     = new JTextField();

	private JButton             _od_add           = new JButton("Add/Change");
//	private JButton             _od_change        = new JButton("Change");
	private JButton             _od_remove        = new JButton("Remove");
	private JLabel              _od_problemDesc   = new JLabel("", SwingConstants.RIGHT);
	private String              _od_validateWarn  = null;
	
//	private final static String NO_ROW_SELECTED = "<none>";

//	private HashMap<String, Integer> _titlesMap = new LinkedHashMap<String, Integer>();
//	private HashMap<String, Integer> _storesMap = new LinkedHashMap<String, Integer>();

	public AddOrChangeOrder(Window owner, ConnectionProvider connProvider, OpType opType)
	{
		super(NAME, owner, connProvider, opType);
		super.init();
	}

	@Override
	public JPanel createPanel()
	{
		JPanel panel = new JPanel();
		panel.setLayout(new MigLayout("", "[][grow]"));

		if ( isUpdate() || isDelete() )
		{
			_order_id_txt.setEnabled(false);
			panel.add(_order_id_lbl,  "");
			panel.add(_order_id_txt,  "growx, pushx, wrap 20");
		}

		panel.add(_store_lbl,       "");
//		panel.add(_store_cbx,       "growx, pushx, wrap");
		panel.add(_store_txt,       "split, growx, pushx");
		panel.add(_store_but,        "wrap");
		
		panel.add(_orderdate_lbl,   "");
		panel.add(_orderdate_dtp,   "growx, pushx, wrap 20");


		
		JPanel p2 = SwingUtils.createPanel("Order Details", true, new MigLayout("", "[][grow]"));

		JScrollPane scroll = new JScrollPane(_orderDetails_tab);
		scroll.setPreferredSize(new Dimension(570, 250));

		p2.add(scroll,            "span, split, grow, push, wrap");

		if ( isInsert() || isUpdate() )
		{
			_od_problemDesc.setForeground(Color.RED);

    		p2.add(_title_lbl,        "");
    		p2.add(_title_txt,        "split, growx, pushx");
    		p2.add(_title_but,        "wrap");
    
    		p2.add(_isbn_lbl,         "");
    		p2.add(_isbn_txt,         "split, growx, pushx");
    		p2.add(_isbn_but,         "wrap");
    
    		p2.add(_quantity_lbl,     "");
    		p2.add(_quantity_txt,     "growx, pushx, wrap");
    
    		p2.add(_discount_lbl,     "");
    		p2.add(_discount_txt,     "growx, pushx, wrap");
    
//    		add(new JLabel(),         "span, split, growx, pushx"); // dummy label to push everything to the right
    		p2.add(_od_problemDesc,   "span, split, growx, pushx");
    		p2.add(_od_add,           "");
//    		p2.add(_od_change,        "");
    		p2.add(_od_remove,        "wrap");
    		
    		setDefaultOrderDetails();
		}

		panel.add(p2, "span, grow, push, wrap");

		if ( isDelete() || isUpdate())
		{
//			_store_cbx       .setEnabled(false);
			_store_txt       .setEnabled(false);
			_store_but       .setEnabled(false);
			_orderdate_dtp   .setEnabled(false);

			if (isDelete())
			{
				_orderDetails_tab.setEnabled(false);
			}
		}

//		_store_cbx.addActionListener(this);
		_store_txt.addActionListener(this);
		_store_but.addActionListener(this);
		_title_txt.addActionListener(this);
		_title_but.addActionListener(this);
		_isbn_txt .addActionListener(this);
		_isbn_but .addActionListener(this);
		_od_add   .addActionListener(this);
//		_od_change.addActionListener(this);
		_od_remove.addActionListener(this);

		_title_txt   .addKeyListener(this);
		_isbn_txt    .addKeyListener(this);
		_quantity_txt.addKeyListener(this);
		_discount_txt.addKeyListener(this);

//		_store_cbx    .addFocusListener(this);
		_store_txt    .addFocusListener(this);
		_orderdate_dtp.addFocusListener(this);
		_title_txt    .addFocusListener(this);
		_isbn_txt     .addFocusListener(this);
		_quantity_txt .addFocusListener(this);
		_discount_txt .addFocusListener(this);
		
		// Add selection 
		_orderDetails_tab.getSelectionModel().addListSelectionListener(new ListSelectionListener()
		{
			@Override
			public void valueChanged(ListSelectionEvent e)
			{
				if (e.getValueIsAdjusting())
					return;

				int selRows = _orderDetails_tab.getSelectedRowCount();
				_od_remove.setEnabled(selRows == 1);
				
				if (selRows == 1)
				{
					int vrow = _orderDetails_tab.getSelectedRow();
					_title_txt   .setText( _orderDetails_tab.getValueAt(vrow, OD_TAB_POS_TITLE)    + "" );
					_isbn_txt    .setText( _orderDetails_tab.getValueAt(vrow, OD_TAB_POS_ISBN)     + "" );
					_quantity_txt.setText( _orderDetails_tab.getValueAt(vrow, OD_TAB_POS_QUANTITY) + "" );
					_discount_txt.setText( _orderDetails_tab.getValueAt(vrow, OD_TAB_POS_DISCOUNT) + "" );

					validateContent();
				}
			}
		});
		
		
//		_storesMap = AddOrChangeStore.getStoresLookup(_owner, getConnectionProvider());

//		_store_cbx.addItem(NO_ROW_SELECTED);
//		for (String key : _storesMap.keySet())
//			_store_cbx.addItem(key);

		return panel;
	}
	
	//-------------------------------------------------
	// BEGIN: Implementing: ActionListener
	//-------------------------------------------------
	@Override
	public void actionPerformed(ActionEvent e)
	{
		Object source = e.getSource();
		
		if (_store_txt.equals(source) || _store_but.equals(source))
		{
			showStorePickTable();
		}

		if (_title_txt.equals(source) || _title_but.equals(source))
		{
			showTitlePickTable();
		}

		if (_isbn_txt.equals(source) || _isbn_but.equals(source))
		{
			showTitlePickTable();
		}

		if (_od_add.equals(source))
		{
			addOrChangeOrderDetails();
		}

		if (_od_remove.equals(source))
		{
			int vrow = _orderDetails_tab.getSelectedRow();
			if (vrow != -1)
			{
				int mrow = _orderDetails_tab.convertRowIndexToModel(vrow);
				_orderDetails_mod.removeRow(mrow);
			}
		}

		validateContent();
	}
	//-------------------------------------------------
	// END: Implementing: ActionListener
	//-------------------------------------------------

	//-------------------------------------------------
	// BEGIN: Implementing: KeyListener
	//-------------------------------------------------
	@Override
	public void keyTyped(KeyEvent e)
	{
	}
	
	@Override
	public void keyReleased(KeyEvent e)
	{
		validateContent();
	}
	
	@Override
	public void keyPressed(KeyEvent e)
	{
	}
	//-------------------------------------------------
	// END: Implementing: KeyListener
	//-------------------------------------------------

	//-------------------------------------------------
	// BEGIN: Implementing: FocusListener
	//-------------------------------------------------
	@Override
	public void focusLost(FocusEvent e)
	{
//		if (_store_cbx.equals(e.getSource()))
//			_title_txt.requestFocus();

		validateContent();
	}
	
	@Override
	public void focusGained(FocusEvent e)
	{
		Object source = e.getSource();

		if (   _store_txt   .equals(source)
		    || _title_txt   .equals(source)
		    || _isbn_txt    .equals(source)
		    || _quantity_txt.equals(source)
		    || _discount_txt.equals(source)
		    || _store_txt   .equals(source)
		   )
		{
			JTextField field = (JTextField)e.getSource();
			field.selectAll();
		}
	}
	//-------------------------------------------------
	// END: Implementing: FocusListener
	//-------------------------------------------------

	private void showStorePickTable()
	{
		String store = _store_txt.getText();

		// Get Order Details (if its Delete or Update)
		SqlStatement stmnt = new SqlStatement(Type.CALLABLE, "{call get_stores_lookup(?,?)}");
//		SqlStatement stmnt = new SqlStatement(Type.LANGUAGE, "select store_name from stores where store_name like '"+store+"%' order by store_name");
		stmnt.addParam( SqlStatementParam.createInParam("store_name", Types.VARCHAR, store) );
		stmnt.addParam( SqlStatementParam.createOracleResultSetParam("a_cursor") );

		SqlPickList pickList = new SqlPickList(this, getConnectionProvider(), stmnt, "order-StoreName");

		boolean setValues = false;
		if (pickList.getRowCount() == 1)
			setValues = true;
		else
		{
			pickList.setVisible(true);
			if (pickList.wasOkPressed())
				setValues = true;
		}
		if (setValues)
		{
			_store_txt.setText(pickList.getSelectedValuesAsString("store_name"));
			
			// FOCUS: Next field 
			_title_txt.requestFocus();
		}
	}
	
	private void showTitlePickTable()
	{
		String title = _title_txt.getText();
		String isbn  = _isbn_txt .getText();

		// Get Order Details (if its Delete or Update)
		SqlStatement stmnt = new SqlStatement(Type.CALLABLE, "{call ${PKG:titles_pkg}get_titles_lookup(?,?,?)}");
//		SqlStatement stmnt = new SqlStatement(Type.LANGUAGE, "select title, isbn from titles where title like '"+title+"%' and isbn like '"+isbn+"%' order by title");
		stmnt.addParam( SqlStatementParam.createInParam("title", Types.VARCHAR, title) );
		stmnt.addParam( SqlStatementParam.createInParam("isbn",  Types.VARCHAR, isbn) );
		stmnt.addParam( SqlStatementParam.createOracleResultSetParam("a_cursor") );

		SqlPickList pickList = new SqlPickList(this, getConnectionProvider(), stmnt, "orderDetailes-TitlesIsbn");

		boolean setValues = false;
		if (pickList.getRowCount() == 1)
			setValues = true;
		else
		{
			pickList.setVisible(true);
			if (pickList.wasOkPressed())
				setValues = true;
		}
		if (setValues)
		{
			_title_txt.setText(pickList.getSelectedValuesAsString("title"));
			_isbn_txt .setText(pickList.getSelectedValuesAsString("isbn"));
			
			// FOCUS: Next field 
			_quantity_txt.requestFocus();
		}
	}

	private void setDefaultOrderDetails()
	{
		_title_txt   .setText("");
		_isbn_txt    .setText("");
		_quantity_txt.setText("1");
		_discount_txt.setText("0");

		_title_txt.setBackground(DEFAULT_BG_COLOR);
		_isbn_txt .setBackground(DEFAULT_BG_COLOR);
	}

	private void addOrChangeOrderDetails()
	{
		String     title    = _title_txt.getText(); 
		String     isbn     = _isbn_txt.getText(); 
		Integer    quantity = new Integer(_quantity_txt.getText()); 
		BigDecimal discount = new BigDecimal(_discount_txt.getText());

		_od_validateWarn = validateOrderDetails(title, isbn, quantity, discount);

		if (StringUtil.isNullOrBlank(_od_validateWarn))
		{
    		_orderDetails_mod.addOrChangeRecord(title, isbn, quantity, discount);
    
    		_orderDetails_tab.packAll(); 
    
    		setDefaultOrderDetails();
    		_title_txt.requestFocus();
		}
	}

	@Override
	public void validateContent()
	{
		super.validateContent();

		// Local validations for the Order Details
		String problem = getOrderDetailsProblemText();
		if (problem == null)
		{
			_od_add.setEnabled(true);
			_od_problemDesc.setText("");
		}
		else
		{
			_od_add.setEnabled(false);
			_od_problemDesc.setText(problem);
		}
		
		if (StringUtil.hasValue(_od_validateWarn))
		{
			_od_add.setEnabled(false);
			_od_problemDesc.setText(_od_validateWarn);

			_od_validateWarn = null;
		}
	}

	public String getOrderDetailsProblemText()
	{
		_title_txt.setBackground(DEFAULT_BG_COLOR);
		if (_orderDetails_mod.existsTitle(_title_txt.getText()))
			_title_txt.setBackground(Color.ORANGE);

		_isbn_txt.setBackground(DEFAULT_BG_COLOR);
		if (_orderDetails_mod.existsIsbn(_isbn_txt.getText()))
			_isbn_txt.setBackground(Color.ORANGE);
		
		// Title Name must be given
		if (_title_txt.getText().trim().length() == 0)
			return "Title Name must be given"; 

		// Quantity must be a Number
		try { new Integer(_quantity_txt.getText()); }
		catch(NumberFormatException nfe) { return "Quantity must be a Integer"; }

		// Discount must be a Number
		try { new BigDecimal(_discount_txt.getText()); }
		catch(NumberFormatException nfe) { return "Discount must be a Number"; }

		return null;
	}

	@Override
	public String getProblemText()
	{
		if ( isInsert() )
		{
			// Select a Store Name
//			if ( NO_ROW_SELECTED.equals(_store_cbx.getSelectedItem()) )
//			{
//				_store_cbx.requestFocus();
//				return "Select a Store Name"; 
//			}
			if ( _store_txt.getText().trim().length() == 0 )
			{
//				_store_txt.requestFocus();
				return "Select a Store Name"; 
			}

			// No order details has yet been added
			if (_orderDetails_tab.getRowCount() == 0)
			{
//				_title_txt.requestFocus();
				return "No order details has yet been added"; 
			}
		}
		return null;
	}

//	private String getStoreNameForId(int id)
//	{
//		for (String key : _storesMap.keySet())
//		{
//			if (_storesMap.get(key) == id)
//				return key;
//		}
//		return "not found id="+id;
//	}

	@Override
	public void setFields(GTable table, int vrow)
	{
		_order_id       = table.getValueAsInteger(vrow, "order_id", false);
		_order_id_txt   .setText(""+_order_id);

//		_store_cbx      .setSelectedItem(table.getValueAsString    (vrow, "store_name",  false));
		_store_txt      .setText        (table.getValueAsString    (vrow, "store_name",  false));
//		_orderdate_dtp  .setTimestamp   (table.getValueAsTimestamp (vrow, "order_date",  false));
		_orderdate_dtp  .setDate        (table.getValueAsTimestamp (vrow, "order_date",  false));

		// Get Order Details (if its Delete or Update)
		SqlStatement stmnt = new SqlStatement(Type.CALLABLE, "{call get_order_details(?,?)}");
		stmnt.addParam( SqlStatementParam.createInParam("order_id_list", Types.VARCHAR, _order_id+"") );
		stmnt.addParam( SqlStatementParam.createOracleResultSetParam("a_cursor") );

		try
		{
			ResultSet rs = stmnt.executeQuery(getConnectionProvider());
			int rowc = 0;
			while(rs.next())
			{
				rowc++;
				String     title    = rs.getString    (4);
				String     isbn     = rs.getString    (5);
				Integer    quantity = rs.getInt       (2);
				BigDecimal discount = rs.getBigDecimal(3);

				_orderDetails_mod.addOrChangeRecord(title, isbn, quantity, discount);
			}
			SqlTraceWindow.getInstance().addRowcount( rowc );

			SqlStatement.putWarningMessages(getConnectionProvider(), null, rs);
			rs.close();
			
			_orderDetails_tab.packAll();
		}
		catch (SQLException e)
		{
			SqlStatement.showErrorMessage(e, stmnt, this, "Getting Order Information for Order ID '"+_order_id+"' <b>failed.</b>");
		}

	}


	public String     getStoreName()   { return getStringValue    (_store_txt      ); }
//	public Timestamp  getOrderDate()     { return                    _orderdate_dtp.getTimestamp(); }
	public Timestamp  getOrderDate()     { return _orderdate_dtp.getDate()==null ? null : new Timestamp(_orderdate_dtp.getDate().getTime()); }

//	public Integer getStoreId() 
//	{ 
//		String name = _store_cbx.getSelectedItem() + "";
//		if (NO_ROW_SELECTED.equals(name))
//			return null;
//		return _storesMap.get(name);
//	}
//
//	public String getStoreName()   
//	{ 
//		String name = _store_cbx.getSelectedItem() + "";
//		if (NO_ROW_SELECTED.equals(name))
//			return null;
//		return name;
//	}

	@Override
	public boolean doInsert()
	{
		SqlStatement stmnt = null;
		Connection conn = null;

		String errAt = "start";

		try
		{
			conn = getConnection();

			// Set to "MANUAL" transaction mode, If we are in AutoCommit COMMIT at start
			if (getConnectionProvider().isAutoCommitEnabledAtConnect())
				DbUtils.setAutoCommit(conn, null, getOwner(), false, "Add Order Dialog"); //conn.setAutoCommit(false);

			//----------------------------------------------
			// FIRST do NORMAL DATA
			errAt = "insert_order";
			stmnt = new SqlStatement(Type.CALLABLE, "{call insert_order(?, ?, ?)}");
		    
			stmnt.addParam( SqlStatementParam.createInParam ("store_name",  Types.VARCHAR,   getStoreName()   ) );
			stmnt.addParam( SqlStatementParam.createInParam ("order_date",  Types.TIMESTAMP, getOrderDate()   ) );
			stmnt.addParam( SqlStatementParam.createOutParam("order_id",    Types.INTEGER));
	
//			stmnt.execute(getConnectionProvider());
			stmnt.executeWithGuiProgress( getConnectionProvider(), getOwner() );

			Integer orderId = (Integer) stmnt.getParameterValue("order_id");
			
			//----------------------------------------------
			// THEN DO ORDER DETAILS
			for (int r=0; r<_orderDetails_mod.getRowCount(); r++)
			{
				String     isbn     = (String)     _orderDetails_mod.getValueAt(r, OD_TAB_POS_ISBN);
				Integer    quantity = (Integer)    _orderDetails_mod.getValueAt(r, OD_TAB_POS_QUANTITY);
				BigDecimal discount = (BigDecimal) _orderDetails_mod.getValueAt(r, OD_TAB_POS_DISCOUNT);
				
				errAt = "insert_order_detail:row="+(r+1);

				stmnt = new SqlStatement(Type.CALLABLE, "{call insert_order_detail(?, ?, ?, ?)}");

				stmnt.addParam( SqlStatementParam.createInParam("order_id",   Types.INTEGER, orderId  ) );
				stmnt.addParam( SqlStatementParam.createInParam("isbn",       Types.VARCHAR, isbn     ) );
				stmnt.addParam( SqlStatementParam.createInParam("quantity",   Types.INTEGER, quantity ) );
				stmnt.addParam( SqlStatementParam.createInParam("discount",   Types.NUMERIC, discount ) );

//				stmnt.execute(getConnectionProvider());
    			stmnt.executeWithGuiProgress( getConnectionProvider(), getOwner() );
			}

			// Now COMMIT the above
			conn.commit();

			return true;
		}
		catch (Throwable ex)
		{
			SqlStatement.showErrorMessage(ex, stmnt, _owner, "Add "+NAME+" information (at: "+errAt+") <b>failed.</b>");

			// ROLLBACK
			if (conn != null)
			{
				try { conn.rollback();	}
				catch (SQLException ex2) { SqlStatement.showErrorMessage(ex2, stmnt, _owner, "Error when rolling back the executed statements"); }
			}

			return false;
		}
		finally
		{
			// RESTORE AUTOCOMMIT, If we are in AutoCommit COMMIT at start
			if ( conn != null && getConnectionProvider().isAutoCommitEnabledAtConnect() )
			{
				DbUtils.setAutoCommit(conn, null, getOwner(), true, "Add or Change Title Dialog");
			}
		}
	}

	@Override
	public boolean doUpdate()
	{
//		throw new RuntimeException("NOT YET IMPLEMENTED");
		SqlStatement stmnt = null;
		Connection conn = null;

		String errAt = "start";

		try
		{
			conn = getConnection();

			// Set to "MANUAL" transaction mode, If we are in AutoCommit COMMIT at start
			if (getConnectionProvider().isAutoCommitEnabledAtConnect())
				DbUtils.setAutoCommit(conn, null, getOwner(), false, "Change Order Dialog"); //conn.setAutoCommit(false);

			//----------------------------------------------
			// FIRST do NORMAL DATA
			errAt = "delete_order_details";
			stmnt = new SqlStatement(Type.CALLABLE, "{call delete_order_details(?)}");
			stmnt.addParam( SqlStatementParam.createInParam ("order_id",  Types.INTEGER, _order_id) );
	
//			stmnt.execute(getConnectionProvider());
			stmnt.executeWithGuiProgress( getConnectionProvider(), getOwner() );

			//----------------------------------------------
			// THEN DO ORDER DETAILS
			for (int r=0; r<_orderDetails_mod.getRowCount(); r++)
			{
				String     isbn     = (String)     _orderDetails_mod.getValueAt(r, OD_TAB_POS_ISBN);
				Integer    quantity = (Integer)    _orderDetails_mod.getValueAt(r, OD_TAB_POS_QUANTITY);
				BigDecimal discount = (BigDecimal) _orderDetails_mod.getValueAt(r, OD_TAB_POS_DISCOUNT);
				
				errAt = "insert_order_detail:row="+(r+1);

				stmnt = new SqlStatement(Type.CALLABLE, "{call insert_order_detail(?, ?, ?, ?)}");

				stmnt.addParam( SqlStatementParam.createInParam("order_id",   Types.INTEGER, _order_id) );
				stmnt.addParam( SqlStatementParam.createInParam("isbn",       Types.VARCHAR, isbn     ) );
				stmnt.addParam( SqlStatementParam.createInParam("quantity",   Types.INTEGER, quantity ) );
				stmnt.addParam( SqlStatementParam.createInParam("discount",   Types.NUMERIC, discount ) );

//				stmnt.execute(getConnectionProvider());
    			stmnt.executeWithGuiProgress( getConnectionProvider(), getOwner() );
			}

			// Now COMMIT the above
			conn.commit();

			return true;
		}
		catch (Throwable ex)
		{
			SqlStatement.showErrorMessage(ex, stmnt, _owner, "Add "+NAME+" information (at: "+errAt+") <b>failed.</b>");

			// ROLLBACK
			if (conn != null)
			{
				try { conn.rollback();	}
				catch (SQLException ex2) { SqlStatement.showErrorMessage(ex2, stmnt, _owner, "Error when rolling back the executed statements"); }
			}

			return false;
		}
		finally
		{
			// RESTORE AUTOCOMMIT, If we are in AutoCommit COMMIT at start
			if ( conn != null && getConnectionProvider().isAutoCommitEnabledAtConnect() )
			{
				DbUtils.setAutoCommit(conn, null, getOwner(), true, "Add or Change Title Dialog");
			}
		}
	}

	@Override
	public boolean doDelete()
	{
		SqlStatement stmnt = new SqlStatement(Type.CALLABLE, "{call delete_order(?)}");
	    
		stmnt.addParam( SqlStatementParam.createInParam("order_id",    Types.INTEGER,   _order_id) );

		return stmnt.execute(getConnectionProvider(), _owner, "Deleting "+NAME+" information <b>failed.</b>");
	}
	
	
	private String validateOrderDetails(String title, String isbn, Integer quantity, BigDecimal discount)
	{
		SqlStatement stmnt = new SqlStatement(Type.CALLABLE, "{call validate_order_detail(?, ?, ?, ?, ?)}");

		stmnt.addParam( SqlStatementParam.createInParam ("title",       Types.VARCHAR, title    ) );
		stmnt.addParam( SqlStatementParam.createInParam ("isbn",        Types.VARCHAR, isbn     ) );
		stmnt.addParam( SqlStatementParam.createInParam ("quantity",    Types.INTEGER, quantity ) );
		stmnt.addParam( SqlStatementParam.createInParam ("discount",    Types.NUMERIC, discount ) );
		stmnt.addParam( SqlStatementParam.createOutParam("warning_txt", Types.VARCHAR));

		stmnt.execute(getConnectionProvider(), _owner, "Validating Order Detail information <b>failed.</b>");

		String warning = (String) stmnt.getParameterValue("warning_txt");
		if (StringUtil.isNullOrBlank(warning))
			warning = null;

		return warning;
	}
	
	
	/*---------------------------------------------------
	** BEGIN: subclasses for PCS Table
	**---------------------------------------------------
	*/
	private static final String[] OD_TAB_HEADER = {"Title", "ISBN", "Quantity", "Discount"};
	private static final int OD_TAB_POS_TITLE       = 0;
	private static final int OD_TAB_POS_ISBN        = 1; //fix OD_TAB_POS_GROUP_NAME or use TcpConfigDialog
	private static final int OD_TAB_POS_QUANTITY    = 2; 
	private static final int OD_TAB_POS_DISCOUNT    = 3;

	/** PcsTable */
	private class OrderDetailsTable
	extends JXTable
	{
		private static final long	serialVersionUID	= 1L;

		OrderDetailsTable(OrderDetailsModel model)
		{
			super();
			if (model != null)
				setModel( model );

			setShowGrid(false);
			setSortable(true);
			setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
			setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
			packAll(); // set size so that all content in all cells are visible
			setColumnControlVisible(true);

			// Populate the table
//			refreshTable();
			
			// make this low, otherwise it will grow to much because of any outer JScrollPane
			setPreferredScrollableViewportSize(new Dimension(400, 100));


			// key: DELETE
			getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "DELETE_CURRENT_ROW");
			getActionMap().put("DELETE_CURRENT_ROW", new AbstractAction("DELETE_CURRENT_ROW")
			{
				private static final long serialVersionUID = 1L;
				@Override
				public void actionPerformed(ActionEvent e)
				{
					_od_remove.doClick();
				}
			});

		}
	}

	/** PcsTableModel */
	private class OrderDetailsModel 
	extends DefaultTableModel
	{
		static final long serialVersionUID = 1L;

		OrderDetailsModel()
		{
			super();
			setColumnIdentifiers(OD_TAB_HEADER);
		}

		public void addOrChangeRecord(String title, String isbn, Integer quantity, BigDecimal discount )
		{
			int pkRow = getRowForPk(title, isbn);
			
			if (pkRow >= 0)
			{
				setValueAt(title,    pkRow, OD_TAB_POS_TITLE);
				setValueAt(isbn,     pkRow, OD_TAB_POS_ISBN);
				setValueAt(quantity, pkRow, OD_TAB_POS_QUANTITY);
				setValueAt(discount, pkRow, OD_TAB_POS_DISCOUNT);
			}
			else
			{
    			Vector<Object> row = new Vector<Object>(OD_TAB_HEADER.length);
    			row.setSize(OD_TAB_HEADER.length);
    
    			row.set(OD_TAB_POS_TITLE,    title);
    			row.set(OD_TAB_POS_ISBN,     isbn);
    			row.set(OD_TAB_POS_QUANTITY, quantity);
    			row.set(OD_TAB_POS_DISCOUNT, discount);
    
    			addRow(row);
			}
		}

		public boolean existsTitle(String title)
		{
			for (int r=0; r<getRowCount(); r++)
			{
				String r_title = getValueAt(r, OD_TAB_POS_TITLE) + "";
				
				if ( title.equals(r_title))
					return true;
			}
			return false;
		}

		public boolean existsIsbn(String isbn)
		{
			for (int r=0; r<getRowCount(); r++)
			{
				String r_isbn  = getValueAt(r, OD_TAB_POS_ISBN)  + "";
				
				if ( isbn.equals(r_isbn) )
					return true;
			}
			return false;
		}

//		public boolean exists(String title, String isbn)
//		{
//			return getRowForPk(title, isbn) > 0;
//		}

		public int getRowForPk(String title, String isbn)
		{
			for (int r=0; r<getRowCount(); r++)
			{
				String r_title = getValueAt(r, OD_TAB_POS_TITLE) + "";
				String r_isbn  = getValueAt(r, OD_TAB_POS_ISBN)  + "";
				
				if ( title.equals(r_title) && isbn.equals(r_isbn) )
					return r;
			}
			return -1;
		}

		@Override
		public Class<?> getColumnClass(int column) 
		{
			if (column == OD_TAB_POS_TITLE)      return String.class;
			if (column == OD_TAB_POS_ISBN)       return String.class;
			if (column == OD_TAB_POS_QUANTITY)   return Number.class;
			if (column == OD_TAB_POS_DISCOUNT)   return Number.class;
			return Object.class;
		}

		@Override
		public boolean isCellEditable(int row, int col)
		{
			return false;
		}
	}
	/*---------------------------------------------------
	** END: subclasses for PCS Table
	**---------------------------------------------------
	*/
}
