/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          cdialog.h  -  description
                             -------------------
    begin                : Fri Mar 31 2000
    copyright            : (C) 2000-2005 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 __CDIALOG_H__
#define __CDIALOG_H__

#include <sptk3/CButton.h>
#include <sptk3/CTabs.h>
#include <sptk3/CStrings.h>
#include <sptk3/CDataControl.h>
#include <sptk3/CGroup.h>
#include <sptk3/CScroll.h>
#include <sptk3/CWindow.h>
#include <sptk3/CControlList.h>

#include <string>

class Fl_Group;
class CQuery;
class CDatabase;
class CButton;
class CControl;
class CRegistry;
class CDlgControls;

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

/// @brief The closing dialog result value. 
///
/// You can check it after the dialog exits the modal state, using modalResult() method.
/// If the Ok button was pressed, it would return DMR_OK. 
/// For Cancel button it would return DMR_CANCEL. And, for user buttons, it would be DMR_USER.
enum CDialogModalResult { 
   DMR_NONE,      ///< Modal result undefined
   DMR_OK,        ///< Ok button pressed
   DMR_CANCEL,    ///< Cancel button pressed
   DMR_USER       ///< User-added button pressed
};

/// @brief Extended CTabs for dialog. 
///
/// The main difference is - it hides the tab label
/// and the border when there is only one tab.
class CDialogTabs : public CTabs {

   /// Sets the proper box type for the widget and for the group depending on the number of tabs
   /// @param page Fl_Group *, newly added tab page
   /// @returns same page
   Fl_Group *adjustPage(Fl_Group *page);
public:

   /// Default constructor
   CDialogTabs() : CTabs("",10,SP_ALIGN_CLIENT) {}

   /// Creates a new page as CGroup
   /// @param label const char *, page label
   /// @param autoColor bool, if true the page color is assigned automatically
   /// @returns created group
   virtual Fl_Group* newPage(const char *label,bool autoColor=false);

   /// Creates a new page as CGroup
   /// @param label const char *, page label
   /// @param color Fl_Color, page color
   /// @returns created group
   virtual Fl_Group* newPage(const char *label,Fl_Color color);

   /// Creates a new page as CScroll
   /// @param label const char *, page label
   /// @param autoColor bool, if true the page color is assigned automatically
   /// @returns created group
   virtual Fl_Group* newScroll(const char *label,bool autoColor=false);

   /// Creates a new page as CScroll
   /// @param label const char *, page label
   /// @param color Fl_Color, page color
   /// @returns created group
   virtual Fl_Group* newScroll(const char *label,Fl_Color color);
};

/// @brief Dialog window.
///
/// Shows a modal window on the screen.
/// CDialog has support for the database data exchange to edit a database record.
/// The required SQL queries in this case are created on the fly, from the list
/// of controls inside the dialog. Controls should have the field names defined, though.
/// And don't forget to define a table name and key field name.
class SP_EXPORT CDialog : public CWindow {
protected:
   CButton      *m_okButton;           ///< Standard Ok button
   CButton      *m_cancelButton;       ///< Standard Cancel button
   CButton      *m_defaultButton;      ///< Pointer to the default button
   std::string   m_tableName;          ///< Database interface: table name
   std::string   m_keyField;           ///< Database interface: table key field name
   int           m_keyValue;           ///< Database interface: table key field value for the record to edit
   CControlList  m_defaultFields;      ///< Database interface: The list of controls for standard processing
   CControlList  m_allFields;          ///< The list of all controls (CControl-descendants)
   CGroup       *m_buttonGroup;        ///< The group buttons are placed on.
   CDialogTabs  *m_pages;              ///< The tabs
   CQuery       *m_selectQuery;        ///< Database interface: The query to select a database record
   CQuery       *m_updateQuery;        ///< Database interface: The query to update a database record
   CQuery       *m_insertQuery;        ///< Database interface: The query to insert a new database record
   bool          m_queriesBuilt;       ///< Database interface: The flag indicating if queries are created from available controls.
   bool          m_controlsScanned;	   ///< Database interface: The flag indicating if available controls were scanned for field names.
   CControlList  m_specialProcessingControls; ///< Database interface: The list of the controls to exclude from standard database queries.
   CDialogModalResult	m_modalResult;  ///< The result of exiting the modal mode.

   /// Ok button callback. If it returns true the dialog closes. 
   /// False indicates an error and dialog stays open.
   virtual bool okPressed();

   /// Ok button callback. If it returns true the dialog closes. 
   /// False indicates an error and dialog stays open.
   virtual bool cancelPressed();

   /// Scans dialog controls. If m_controlsScanned is already true, does nothing.
   virtual void scanControls();

   /// Builds database interface queries using table(), keyField(), and control field names.
   /// If m_queriesBuilt is already true, does nothing.
   virtual bool buildQueries();

   /// Loads data into dialog. Returns true upon success.
   /// If you're overwriting this method make sure you're calling
   /// the original CDialog::load() and use the result of it.
   virtual bool load();

   /// Save data from dialog. Returns true upon success.
   /// If you're overwriting this method make sure you're calling
   /// the original CDialog::save() and use the result of it.
   virtual bool save();

public:

   /// Constructor
   /// @param w int, dialog width
   /// @param h int, dialog height
   /// @param label const char *, dialog caption
   CDialog(int w, int h, const char *label = 0);

   /// Destructor
   ~CDialog();

   /// Resets all the controls inside the dialog tabs by calling reset() for
   /// every control
   virtual bool reset();

   /// Own handle() method to process dialog events the special way
   /// @param event int, an FLTK event
   /// @returns true if event was processed
   int        handle(int event);

   /// Shows modal dialog
   /// @returns true if Ok button was used to close the dialog
   bool       showModal();

   /// Shows an alert box
   void       alert(std::string s) const;

   /// Defines the default button
   /// @param btn CButton *, button in dialog to become the default button
   void       defaultButton(CButton *btn);

   /// Sets the database connection 
   /// @param db CDatabase *, the database connection
   virtual void database(CDatabase *db);

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

   /// Defines database table to use
   /// @param tableName std::string, the name of the database table
   void       table(std::string tableName);

   /// Returnes used database table
   std::string table() const { return m_tableName; }

   /// Fast setup of the database connection
   /// @param db CDatabase *, the database connection
   /// @param tableName std::string, the name of the database table
   /// @param keyFieldName std::string, the name of the key field in the database table
   void       table(CDatabase *db,std::string tableName,const std::string keyFieldName);

   /// Sets the key field name for the database table. The key field contains the
   /// unique value to find the database record.
   /// @param keyFieldName std::string, the name of the key field in the database table
   void       keyField(std::string keyFieldName);

   /// Returns the key field name for the database table. 
   std::string keyField() const { return m_keyField; }

   /// Finds the database record by the value in previously defined key field.
   void       keyValue(int val);

   /// Returns the current database record key value.
   int        keyValue() const;

   /// Creates a new page as CGroup
   /// @param label const char *, page label
   /// @param autoColor bool, if true the page color is assigned automatically
   /// @returns created group
   virtual Fl_Group* newPage(const char *label,bool autoColor=false);

   /// Creates a new page as CGroup
   /// @param label const char *, page label
   /// @param color Fl_Color, page color
   /// @returns created group
   virtual Fl_Group* newPage(const char *label,Fl_Color color);

   /// Creates a new page as CScroll
   /// @param label const char *, page label
   /// @param autoColor bool, if true the page color is assigned automatically
   /// @returns created group
   virtual Fl_Group* newScroll(const char *label,bool autoColor=false);

   /// Creates a new page as CScroll
   /// @param label const char *, page label
   /// @param color Fl_Color, page color
   /// @returns created group
   virtual Fl_Group* newScroll(const char *label,Fl_Color color);

   /// Adds a user-defined button to the dialog. User-defined buttons
   /// usually do something in the dialog without closing the dialog.
   CButton   *addExtraButton(CButtonKind buttonKind,const char *label,Fl_Callback_p callback);

   /// Returns the number of controls inside the dialog with defined field names
   unsigned fieldCount() const { return m_allFields.size(); }

   /// Index operator to access controls with defined field name
   /// @param fieldName std::string, the control field name
   CControl& operator [] (std::string fieldName);

   /// Makes dialog to scan the widgets inside
   void rescan() { m_queriesBuilt = false; m_controlsScanned = false; }

   /// Loads the dialog controls from the registry. 
   /// @param registry CRegistry *, the registry object, should be loaded already
   /// @param section const char *, the section name
   /// @see CRegistry
   virtual bool loadFromRegistry(CRegistry *registry,const char *section);

   /// Saves the dialog controls to the registry. If the topic doesn't exist yet 
   /// it will be created.
   /// @param registry CRegistry *, the registry object
   /// @param section const char *, the section name
   /// @see CRegistry
   virtual bool saveToRegistry(CRegistry *registry,const char *section);

   /// Returns the modal result of the dialog. 
   /// @see CDialogModalResult for more information.
   /// @returns modal result
   CDialogModalResult modalResult() const { return m_modalResult; }
};

/// @}

#endif
