/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          ccontrol.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 __CCONTROL_H__
#define __CCONTROL_H__

#include <FL/Fl_Group.H>
#include <FL/Fl_Menu_Button.H>
#include <sptk3/CEvent.h>

#include <sptk3/CQuery.h>
#include <sptk3/CLayoutClient.h>
#include <sptk3/cxml>

#include <string>

namespace sptk {

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

   /// @brief Control kind is the constant to report the internal SPTK RTTI.
	enum CControlKind {
		DCV_UNKNOWN,                 ///< Control kind is unknown
		DCV_BOX=1,                   ///< Control is a box of plain text
		DCV_HTMLBOX=2,               ///< Control is a box of HTML text
		DCV_STRING=4,                ///< Control is a text input (single line)
		DCV_MEMO=8,                  ///< Control is a text input (multiple lines)
		DCV_INTEGER=16,              ///< Control is an integer value input
		DCV_FLOAT=32,                ///< Control is an integer value input
		DCV_DATE=64,                 ///< Control is a date input
		DCV_TIME=128,                ///< Control is a time input
		DCV_DATETIME=256,            ///< Control is a date and time input
		DCV_DATEINTERVAL=512,        ///< Control is a date interval input
		DCV_COMBO=1024,              ///< Control is a combobox
		DCV_INTVALUECOMBO=2048,      ///< Control is a combobox with int key value
		DCV_LISTBOX=4096,            ///< Control is a listbox
		DCV_CHECKBUTTONS=8192,       ///< Control is a set of check buttons
		DCV_RADIOBUTTONS=16384,      ///< Control is a set of radio buttons
		DCV_PHONE=32768,             ///< Control is a phone number input
		DCV_TREEVIEW=65536,          ///< Control is a tree widget
		DCV_GROUP=131072             ///< Control is a group
	};

   /// @brief Special control flags (used as bit combination)
	enum FGENTRYFLAGS {
		FGE_NONE,					///< No flags
		FGE_SPELLCHECK=1,			///< Requires spell checking
		FGE_MANDATORY=2,			///< Must have some value
		FGE_CFIELD=4,				///< Is a custom field
		FGE_SINGLELINEENTRY=256,///< Is a single-line entry
		FGE_MULTILINEENTRY=512	///< Is a multi-line entry
	};

   /// @brief Default height for the single-row edit control
#define SINGLE_EDIT_ENTRY_HEIGHT 23

	class CDBDropDownList;
	class CPackedStrings;
	class CColumnList;
	class CStrings;

   /// @brief Internal field name validation
	SP_EXPORT bool checkFieldName(std::string fldName);

   /// @brief Base class for most of SPTK widgets.
   ///
   /// It is a group used as a container for the widget(s) inside.
   /// Every CControl has a field name, and it can be a layout client.
	class SP_EXPORT CControl : public ::Fl_Group, public CLayoutClient {
		friend class CInternalComboBoxPanel;
		friend class CEditor;
		friend class CBaseButton;
		friend class CRadioButton;
		friend class CCheckButton;
		friend class CInput_;

      /// Constructor initializer
		void ctor_init(const char *);

	protected:

		bool              m_limited;     ///< Control has the defined min and max values
		std::string       m_label;       ///< Control label
		unsigned          m_labelWidth;  ///< Control label width (on the left)
		Fl_Color          m_labelColor;  ///< Control label color
		Fl_Color          m_textColor;   ///< Control text color
		Fl_Font           m_textFont;    ///< Control text font
		uchar             m_textSize;    ///< Control text font size
		std::string       m_fieldName;   ///< Field name for the universal data connection
		Fl_Widget*        m_control;     ///< The main widget inside the control.
		int               m_tag;         ///< Control's special data tag
      /// @brief Control's special flags (a bit combination of FGENTRYFLAGS). 
      /// @see FGENTRYFLAGS for details.   
		unsigned          m_controlFlags;
		Fl_Menu_Button   *m_menuButton;  ///< Control's menu button - to show right-mouse click menu
		CEventInfo        m_event;       ///< The last SPTK event inside this control.
		bool              m_hasFocus;    ///< Does the control have focus?

	protected:

      /// @brief Does the control contain focus?
		bool containsFocus() const;

      /// @brief Internal focus notification on focus change
		void notifyFocus(bool gotFocus=true);

      /// @brief Internal focus notification on focus change
		virtual void     onEnter();

      /// @brief Internal focus notification on focus change
		virtual void     onExit();

      /// @brief Computes the label height based on the labelFont() and labelWidth()
		unsigned         labelHeight() const;

      /// @brief Special handle() method
		int              handle(int);

      /// @brief Internal callback function
		static void internalCallback(Fl_Widget *internalWidget,void *data);

	public:   

      /// @brief Constructor in SPTK style 
      /// @param label const char *, label
      /// @param layoutSize int, widget align in layout
      /// @param layoutAlign CLayoutAlign, widget align in layout
		CControl(const char *label,int layoutSize=20,CLayoutAlign layoutAlign=SP_ALIGN_TOP);

#ifdef __COMPATIBILITY_MODE__    
      /// @brief 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
		CControl(int,int,int,int,const char * = 0);
#endif    

	public:

      /// @brief 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);

      /// @brief Draws the control
		virtual void     draw();

      /// @brief Returns the control's user data tag
		virtual int      tag() const { return m_tag; }

      /// @brief Sets the control's user data tag
		virtual void     tag(int t)  { m_tag = t; }

      /// @brief Returns the control's text font
#if FL_MAJOR_VERSION < 2
		virtual Fl_Font  textFont() const;

      /// @brief Sets the control's text font
		virtual void     textFont(Fl_Font);
#else
		virtual Font    *textFont() const;

      /// @brief Sets the control's text font
		virtual void     textFont(Font *);
#endif

      /// @brief Returns the control's text font size
		virtual uchar    textSize() const;

      /// @brief Sets the control's text font size
		virtual void     textSize(uchar);

      /// @brief Returns the control's text color
		virtual Fl_Color textColor() const;

      /// @brief Sets the control's text color
		virtual void     textColor(Fl_Color);

      /// @brief Returns the control's label color
		virtual Fl_Color labelColor() const;

      /// @brief Sets the control's label color
		virtual void     labelColor(Fl_Color);

      /// @brief Returns the control's background color
		virtual Fl_Color color() const;

      /// @brief Sets the control's background color
		virtual void     color(Fl_Color);

      /// @brief Returns the control's flags
		unsigned flags() const { return m_controlFlags; }

      /// @brief Sets the control's flags
		void flags(unsigned flags);

      /// @brief Returns main widget inside the container
		Fl_Widget*       control() const { return m_control; }

      /// @brief Returns controls' label
		const std::string& label() const { return m_label; }

      /// @brief Sets controls' label
		void             label(const std::string);

      /// @brief Returns controls' menu
		Fl_Menu_*        menu() const;

      /// @brief Sets controls' menu
		void             menu(const Fl_Menu_Item*);

      /// @brief Returns controls' label font
		Fl_Font          labelFont() const { return labelfont(); }

      /// @brief Sets controls' label font 
		void             labelSize(Fl_Font f) { labelfont(f); }

      /// @brief Returns controls' label font size
		uchar            labelSize() const;

      /// @brief Sets controls' label font size
		void             labelSize(uchar);

      /// @brief Returns controls' label width
		unsigned         labelWidth() const { return m_labelWidth; }

      /// @brief Sets controls' label width
		void             labelWidth(unsigned);

      /// @brief Returns controls' max input length, if applicable
		virtual int      maxLength() const { return 0; }

      /// @brief Sets controls' max input length, if applicable
		virtual void     maxLength(int) {}

      /// @brief Returns controls' field name for universal data connection
		virtual const std::string& fieldName() const { return m_fieldName; }

      /// @brief Sets controls' field name for universal data connection
		virtual void     fieldName(const std::string&);

      /// @brief Returns controls' kind (internal SPTK RTTI).
		virtual CControlKind kind() const = 0;

      /// @brief Returns controls' class name (internal SPTK RTTI).
		virtual std::string className() const { return "CControl"; }

      /// @brief Sets the control to empty text (for the input entries)
      ///
      /// Also sets no selection state / default selection (for the lists)
		virtual void     reset() { data(""); }

      /// @brief Loads control data from query fields
		virtual void     load(CQuery *) = 0;

      /// @brief Saves control data to query params
		virtual void     save(CQuery *) = 0;

      /// @brief Loads control data from XML
		virtual void     load(const CXmlNode& node);

      /// @brief Loads control data from XML
		virtual void     load(const CXmlNode* node) { load(*node); }

	   /// @brief Saves control data to XML
		virtual void     save(CXmlNode& node) const;

	   /// @brief Saves control data to XML
		virtual void     save(CXmlNode* node) const { save(*node); }

      /// @brief Returns true if the control state is valid, and the data is inside the limits (if applicable)
		virtual bool     valid() const = 0;

      /// @brief The universal data connector
      /// @returns control data
		virtual CVariant data() const { return CVariant(""); }

      /// @brief The universal data connector, sets control data
		virtual void     data(const CVariant v) {}

      /// @brief Fires the event generated by this control
		void             fireEvent(CEvent ev,long arg);

      /// @brief Returns the last event fired by this control
		const CEventInfo& event() const { return m_event; }

      /// @brief Returns the event type for the last fired by this control
		CEvent           eventType() const { return m_event.type(); }

      /// @brief Returns the event argument for the last fired by this control
		int              eventArgument() const { return m_event.argument(); }

      /// @brief Converts control name to control kind
		static  CControlKind controlNameToType(std::string typeName,int& maxLength,std::string values="");

      /// @brief Control data assignment
		CControl& operator = (const std::string& str) { data(str); return *this; }

      /// @brief Control data assignment
		CControl& operator = (const char *str)    { data(str); return *this; }

      /// @brief Control data assignment
		CControl& operator = (int v)              { data(v); return *this;   }

      /// @brief Control data assignment
		CControl& operator = (unsigned v)         { data(v); return *this;   }

      /// @brief Control data assignment
		CControl& operator = (float v)            { data(v); return *this;   }

      /// @brief Control data assignment
		CControl& operator = (double v)           { data(v); return *this;   }

      /// @brief Control data assignment
		CControl& operator = (CDateTime& dt)      { data(dt); return *this;  }

      /// @brief Control data assignment
		CControl& operator = (CField& fld)        { data(fld); return *this; }

      /// @brief Control data conversion
		operator std::string () const   { return data(); }

      /// @brief Control data conversion
		operator int () const       { return data(); }

      /// @brief Control data conversion
		operator unsigned () const  { return data(); }

      /// @brief Control data conversion
		operator float () const     { return data(); }

      /// @brief Control data conversion
		operator double () const    { return data(); }

      /// @brief Control data conversion
		operator CDateTime () const { return data(); }

	public:   
      /// @brief Default callback function to support CControl default menu item 'Copy'
		static void defaultControlMenuCopy(Fl_Widget *,void *);

      /// @brief Default callback function to support CControl default menu item 'Delete'
		static void defaultControlMenuCut(Fl_Widget *,void *);

      /// @brief Default callback function to support CControl default menu item 'Paste'
		static void defaultControlMenuPaste(Fl_Widget *,void *);

      /// @brief Default callback function to support CControl default menu item 'Clear'
		static void defaultControlMenuClear(Fl_Widget *,void *);

      /// @brief CControl default menu 
		static const Fl_Menu_Item defaultControlMenu[];
	};

   /// @brief Creates a single control
   ///
   /// The utility function that allows to create a control with one step
   /// @param controlKind int, a control kind
   /// @param label std::string, a control label
   /// @param fieldName std::string, a control field name
   /// @param layoutSize int, a control layout size
	CControl *createControl(int controlKind,std::string label,std::string fieldName,int layoutSize);

   /// @brief Create a control or a group of controls
   ///
   /// Every XML node in xmlControls should be CONTROL node
   /// and may contain the following elements:
   ///   type       a control type, one of the
   ///      { 
   ///        AREA CODE, CURRENCY, CREDIT CARD, COMBO, CHOICE, CHECK BUTTONS,
   ///        DATE, DATE AND TIME, FLOAT, GROUP, HTML, INTEGER, LABEL, LONG ZIP CODE,
   ///        MASK, MULTIPLE CHOICE, MONEY, PHONE, PHONE EXT, PLAIN TEXT,
   ///        PHONE NUMBER, PHONE EXTENSION, SIMPLE, STRING, SSN, TIME, ZIP CODE
   ///      }
   ///   label      a label, optional
   ///   fieldName  a field name, optional
   ///   values     a list of values separated with '|' for list-based controls, string, optional
   ///   sqlValues  an SQL query to build the list values, string, optional, presented as a sub-node with CDATA
   ///   visible    visibility flag, optional, true or false (1/0)
   ///   enable     enable flage, optional, true or false (1/0)
   ///   align      layout align, optional, one of { top,bottom,left,right,client}, the default is top
   ///   size       layout size in pixels, optional
   ///
   /// The group node may contain other controls. If the control type or parameter is not recognized,
   /// the exception is thrown.
   /// @param xmlControls const CXmlNodeList&, the controls description in XML
	void createControls(const CXmlNodeList& xmlControls) throw(std::exception);

   /// @}
}
#endif
