/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          CDataControl.h  -  description
                             -------------------
    begin                : Tue Apr 4 2000
    copyright            : (C) 2000-2006 by Alexey S.Parshin
    email                : alexeyp@gmail.com
 ***************************************************************************/

/***************************************************************************
   This library is free software; you can redistribute it and/or modify it 
   under the terms of the GNU Library General Public License as published by
   the Free Software Foundation; either version 2 of the License, or (at 
   your option) any later version.

   This library 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 Library
   General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; if not, write to the Free Software Foundation, 
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.

   Please report all bugs and problems to "alexeyp@gmail.com"
 ***************************************************************************/

#ifndef __CCOMBOBOX_H__
#define __CCOMBOBOX_H__

#include <FL/Fl_Box.H>
#include <FL/Fl_Button.H>

#include <sptk3/CDatabase.h>
#include <sptk3/CQuery.h>
#include <sptk3/CControl.h>
#include <sptk3/CDBListView.h>

namespace sptk {

   /// @addtogroup gui GUI Classes
   /// @{

	class CInternalComboBoxPanel;
	class CDBListView;

   /// @brief Base list box widget
   ///
   /// A base class for CListBox and CComboBox.
   /// Implements most of the common methods for these two classes.
	class SP_EXPORT CBaseListBox : public CControl {
		friend class CInternalComboBoxPanel;
	private:

		Fl_Callback_p     m_buttonClicked;  ///< Internal button callback
		Fl_Button*        m_buttons[5];     ///< The list of buttons
		bool              m_droppedDown;    ///< Is the list dropped down (shown)?
		unsigned          m_buttonSet;      ///< The bit-combination of button IDs

      /// The internal function to process data changes
		void              changeControlData(int changeType,int intData=0,std::string stringData="");
      /// The constructor initializer
		void              ctor_init(const char *label,int _mode);

      /// Internal buttons callback function.
		static void comboButtonPressed(Fl_Widget *btn,void *data);

	protected:
		int               m_mode;           ///< Control mode - CListBox or CComboBox
		CDBDropDownList  *m_dropDownWindow; ///< Drop down window - CComboBox only
		CDBListView      *m_list;           ///< Internal CDBListView widget
		int               m_buttonSpace;    ///< The width of space taken by buttons

      /// Drops down the window with the List View. CComboBox only.
		virtual void dropDownList();

      /// Loads data from the Query
		void load(CQuery *);

      /// Saves data to the Query
		void save(CQuery *);

      /// Returns true, if the data is valid.
		bool valid() const { return true; }

	protected:

      /// Constructor in SPTK style 
      /// @param label const char *, label
      /// @param layoutSize int, widget align in layout
      /// @param layoutAlign CLayoutAlign, widget align in layout
      /// @param mode int, IS_COMBO_BOX or IS_LIST_BOX - internal
		CBaseListBox(const char *label,int layoutSize,CLayoutAlign layoutAlign,int mode);

#ifdef __COMPATIBILITY_MODE__    
      /// Constructor in FLTK style 
      /// @param x int, x-position
      /// @param y int, y-position
      /// @param w int, width
      /// @param h int, height
      /// @param label, const char * label
      /// @param mode int, IS_COMBO_BOX or IS_LIST_BOX - internal
		CBaseListBox(int x,int y,int w,int h,const char *label,int mode);
#endif

      /// Destructor
		~CBaseListBox();

      /// Internal buttons callback function
		virtual void button_handle(long buttonKind);

	public:

      /// Clears the list view inside
		virtual void clear();

      /// Returns the bitmask of visible buttons' IDs
		unsigned buttons() { return m_buttonSet; }

      /// Sets the bitmask for visible buttons' IDs
		void buttons(unsigned);

      /// Returns buttons' callback function
		Fl_Callback_p buttonClicked() const { return m_buttonClicked; }

      /// Sets buttons' callback function
		void buttonClicked(Fl_Callback* c) { m_buttonClicked=c; }

      /// Sets the internal list view columns from the column list. The old column list is destroyed
      /// and replaced with a copy of columnList.
      /// @param columnList CColumnList&, new column list
		void columns(const CColumnList& columnList);

      /// Returns current column list of the internal list view.
      /// @returns the column list reference
		CColumnList& columns();

      /// Adds a new column to the internal list view.
      /// @param cname std::string, column name
      /// @param type CVariantType, column data type
      /// @param cwidth short, column width
      /// @param cvisible bool, is the column visible?
		void addColumn(std::string cname,CVariantType type=VAR_STRING,short cwidth=70,bool cvisible=true);

      /// Adds a new row to the internal list view. Doesn't make a copy - just
      /// inserts the pointer. The row will be destroyed in CCombo destructor.
      /// The row ID may be defined inside CPackedStrings object.
      /// @param row CPackedStrings *, new row
		void addRow(CPackedStrings *row);

      /// Adds a new row to the internal list view. Makes a copy of data in rowStrings.
      /// The row ID may be defined inside CStrings object, or with rowID parameter.
      /// @param rowStrings const CStrings&, new row
      /// @param rowId int, optional row ID
		void addRow(const CStrings& rowStrings,int rowId=0);

      /// Adds new row to the internal list view.
      /// @param rowId int, row argument (key value)
      /// @param s1 const char *, text data for the column 1
      /// @param s2 const char *, text data for the column 2
      /// @param s3 const char *, text data for the column 3
      /// @param s4 const char *, text data for the column 4
      /// @param s5 const char *, text data for the column 5
		void addRow(int rowId,const char *s1,const char *s2=NULL,const char *s3=NULL,const char *s4=NULL,const char *s5=NULL);

      /// Creates the column as columnName and adds rows to the internal list view. If the column with such name
      /// already exists, it will be used. The method is good the a very simple cases of one-column
      /// combo boxes. The row IDs may be defined inside CStrings object strings.
      /// @param columnName std::string, new columnName
      /// @param rows CStrings, new rows
		void addRows(std::string columnName,CStrings rows);

      /// Resizes the control and inside widgets. 
      /// @param x int, x-position
      /// @param y int, y-position
      /// @param w int, width
      /// @param h int, height
		virtual void resize(int x,int y,int w,int h);

      /// Universal data connection. Operates with selected list view item's ID.
		virtual CVariant data() const;

      /// Universal data connection. Operates with selected list view item's ID.
		virtual void     data(const CVariant v);

      /// Sets data mode for the data() methods. 
      /// Defines which information list view are working with in data() method - key value, item index, or item caption.
      /// @see CListViewDataMode for more information
		void dataMode(CListViewDataMode dm) { m_list->dataMode(dm); }

      /// Returns data mode as LVDM_KEY, LVDM_INDEX, or LVDM_TEXT.
      /// @see CListViewDataMode for more information
		CListViewDataMode dataMode() { return m_list->dataMode(); }

      /// Finds an item with the caption (a string in the first column).
      /// @param caption std::string, the caption to find and select.
      /// @returns an item, or NULL if item caption is not found
		CPackedStrings *findCaption(std::string caption) { return m_list->findCaption(caption); }

      /// Finds an item with the key (an integer associated with the item - argument()).
      /// @param keyValue int, the caption to find and select.
      /// @returns an item, or NULL if item caption is not found
		CPackedStrings *findKey(int keyValue) { return m_list->findKey(keyValue); }

      /// Returns database connection pointer
		CDatabase  *database() const;

      /// Defines database connection
		void        database(CDatabase *db);

      /// Returns SQL query text
		std::string sql() const;

      /// Defines SQL query text
      /// @param s std::string, SQL text
		void        sql(std::string s);

      /// Returns SQL query field name that contains unique row IDS, preferrably - integers.
		std::string keyField() const;

      /// Sets SQL query field name that contains unique row IDS, preferrably - integers.
      /// @param keyFieldName std::string, a name of the key field
		void        keyField(std::string keyFieldName);

      /// Returns sortColumn
		int         sortColumn() const;

      /// Sorts the list
		void        sort() { m_list->sort(); }

      /// Defines sortColumn. 
      /// @param sortColumn int, sort column number. -1 means don't sort.
		void        sortColumn(int sortColumn);

      /// The fast way to define a database connection.
      /// @param db CDatabase *, a pointer to the database
      /// @param sql std::string, a SQL query text
      /// @param keyField std::string, a name of the query field with unique row IDs
		void        setup(CDatabase *db,std::string sql,std::string keyField);

      /// Returns the SQL query parameter reference for the parameter name. It is 
      /// typical to call:
      ///   myCombo.param("customer_id") = 1234;
      /// @param paramName const char *, parameter name.
      /// @returns the parameter reference, if found, or throws an excception.
		CParam&     param(const char *paramName);

      /// Reloads data from the database if database connection is defined.
      /// Throws an exception if any error.
		void        refreshData();

      /// Finds a string in the sort column of list view defined with sortColumn()
      /// @param str std::string, string to find
      /// @param select bool, true if we want to select the found row
      /// @param startRow unsigned, the row number to start
      /// @param endRow unsigned, the row number to finish
      /// @returns the row number, or -1 if not found
		int         findString(std::string str,bool select=true,unsigned startRow=0,unsigned endRow=0);

      /// Returns the currently selected row, or reference to NULL if not selected
		CPackedStrings& selectedRow () const;

      /// Selects a row 
      /// @param rowNumber unsigned, row number 
		void selectRow(unsigned rowNumber);

      /// Shows column headers in the list
		void showHeaders();

      /// Hides column headers in the list
		void hideHeaders();

      /// Returns the number of rows in list view
		unsigned size() const;

      /// Computes the optimal widgets size
      /// @param w int&, input - width offered by the program, output - width required by widget
      /// @param h int&, input - height offered by the program, output - height required by widget
		void preferredSize(int& w,int& h);
	};

   /// @brief Combo box widget
   ///
   /// The extended version of standard combo box that exists in any OS.
   /// It may include up to four special buttons to insert, edit, delete, refresh data inside
   /// the drop down list besides the standard button to show the drop down list
	class SP_EXPORT CComboBox : public CBaseListBox {
	public:
      /// Constructor in SPTK style 
      /// @param label const char *, label
      /// @param layoutSize int, widget align in layout
      /// @param layoutAlign CLayoutAlign, widget align in layout
		CComboBox(const char * label=0,int layoutSize=10,CLayoutAlign layoutAlign=SP_ALIGN_TOP);

#ifdef __COMPATIBILITY_MODE__    
      /// Constructor in FLTK style 
      /// @param x int, x-position
      /// @param y int, y-position
      /// @param w int, width
      /// @param h int, height
      /// @param label, const char * label
		CComboBox(int x,int y,int w,int h,const char *label = 0);
#endif
      /// Destructor
		~CComboBox();    

      /// SPTK RTTI information
      /// @returns control type as CControlKind
      /// @see CControlKind
		virtual CControlKind kind() const;

      /// SPTK RTTI information
      /// @returns control type name
		virtual std::string className() const { return "CComboBox"; }
	};

   /// @brief List Box widget
   ///
   /// The extended version of standard list box that exists in any OS.
   /// It may include up to four special buttons to insert, edit, delete, refresh data inside
   /// the list.
	class SP_EXPORT CListBox : public CBaseListBox {
	public:
      /// Constructor in SPTK style 
      /// @param label const char *, label
      /// @param layoutSize int, widget align in layout
      /// @param layoutAlign CLayoutAlign, widget align in layout
		CListBox(const char * label=0,int layoutSize=10,CLayoutAlign layoutAlign=SP_ALIGN_TOP);

#ifdef __COMPATIBILITY_MODE__    
      /// Constructor in FLTK style 
      /// @param x int, x-position
      /// @param y int, y-position
      /// @param w int, width
      /// @param h int, height
      /// @param label, const char * label
		CListBox(int,int,int,int,const char * = 0);
#endif

      /// SPTK RTTI information
      /// @returns control type as CControlKind
      /// @see CControlKind
		virtual CControlKind kind() const { return DCV_LISTBOX; }

      /// SPTK RTTI information
      /// @returns control type name
		virtual std::string className() const { return "CListBox"; }
	};
   /// @}
}
#endif
