/* 
 * © 2008-2009 Sun Microsystems, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser 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.
 */

#ifndef _WF_VIEW_H_
#define _WF_VIEW_H_

#include <mforms/mforms.h>


#include "wf_base.h"
#include "wf_mforms.h"

using namespace System;
using namespace Drawing;

using namespace Windows::Forms;


namespace MySQL {
  namespace Forms {

    public ref class ViewImpl : public ObjectImpl
    {
    private:
      // CommonDialog and Control don't have a common ancestor which has a window handle and a Tag property.
      // Thus we have to keep dialogs in a separate variable, which is only queried if the inner control
      // is not assigned.
      Windows::Forms::Control^ inner; 
      Windows::Forms::CommonDialog^ dialog;
      bool layoutDirty;
      ToolTip^ tooltip;
    protected:
      ViewImpl(::mforms::View *view)
        : ObjectImpl(view)
      {
        layoutDirty= true;
        tooltip= nullptr;
        inner= nullptr;
      }

      /**
       * Creates a new instance of a control of type T for the given backend View control and returns it.
       * The backend view pointer is stored in the front end control's Tag property for later back reference
       * and the new native control reference for the front end is also stored.
       */
      template<class T>
      static T^ create(::mforms::View *be_view, ViewImpl ^fe_view)
      {
        T^ control= gcnew T();
        control->Tag= gcnew IntPtr(be_view);
        fe_view->inner= control;

        // Do some common setup for the control.
        control->AutoSize= false;
        control->Size= control->MinimumSize;

        return control;
      }

      /**
       * Creates a new instance of a common dialog of type T for the given backend View and returns it.
       * The backend view pointer is stored in the front end dialog's Tag property for later back reference
       * and the new native dialog reference for the front end is also stored.
       */
      template<class T>
      static T^ create_dialog(::mforms::View *be_view, ViewImpl ^fe_view)
      {
        T^ dialog= gcnew T();
        dialog->Tag= gcnew IntPtr(be_view);
        fe_view->dialog= dialog;

        return dialog;
      }

      static void show(::mforms::View *self, bool show);      
      static int get_width(::mforms::View *self);
      static int get_height(::mforms::View *self);
      static int get_preferred_width(::mforms::View *self);
      static int get_preferred_height(::mforms::View *self);
      static int get_x(::mforms::View *self);
      static int get_y(::mforms::View *self);
      static void set_size(::mforms::View *self, int w, int h);
      static void set_position(::mforms::View *self, int x, int y);
      static void set_enabled(::mforms::View *self, bool flag);
      static View *find_subview(::mforms::View *self, std::string &name);
      static void set_name(::mforms::View *self, const std::string& text);
      static void relayout(::mforms::View *self);
      static void set_tooltip(::mforms::View *self, const std::string& text);
      static bool is_shown(::mforms::View *self);
      static void set_layout_dirty(::mforms::View *self);

      virtual void set_size(int width, int height);
      virtual void set_position(int x, int y);
      virtual void set_tooltip(const std::string& text);
      virtual ViewImpl^ get_parent();
      virtual void relayout();
    public:

      static void init(Manager ^mgr)
      {
        ::mforms::ControlFactory *f= ::mforms::ControlFactory::get_instance();

        DEF_CALLBACK1(int, ::mforms::View*, mgr, f->_view_impl, ViewImpl, get_x);
        DEF_CALLBACK1(int, ::mforms::View*, mgr, f->_view_impl, ViewImpl, get_y);
        DEF_CALLBACK1(int, ::mforms::View*, mgr, f->_view_impl, ViewImpl, get_width);
        DEF_CALLBACK1(int, ::mforms::View*, mgr, f->_view_impl, ViewImpl, get_height);
        DEF_CALLBACK1(int, ::mforms::View*, mgr, f->_view_impl, ViewImpl, get_preferred_width);
        DEF_CALLBACK1(int, ::mforms::View*, mgr, f->_view_impl, ViewImpl, get_preferred_height);
        DEF_CALLBACK3(void, ::mforms::View*, int, int, mgr, f->_view_impl, ViewImpl, set_position);
        DEF_CALLBACK3(void, ::mforms::View*, int, int, mgr, f->_view_impl, ViewImpl, set_size);
        DEF_CALLBACK2(void, ::mforms::View*, bool, mgr, f->_view_impl, ViewImpl, show);
        DEF_CALLBACK2(void, ::mforms::View*, bool, mgr, f->_view_impl, ViewImpl, set_enabled);
        DEF_CALLBACK2(void, ::mforms::View*, const std::string&, mgr, f->_view_impl, ViewImpl, set_name);
        DEF_CALLBACK1(void, ::mforms::View*, mgr, f->_view_impl, ViewImpl, relayout);
        DEF_CALLBACK2(void, ::mforms::View*, const std::string&, mgr, f->_view_impl, ViewImpl, set_tooltip);
        DEF_CALLBACK1(bool, ::mforms::View*, mgr, f->_view_impl, ViewImpl, is_shown);
        DEF_CALLBACK1(void, ::mforms::View*, mgr, f->_view_impl, ViewImpl, set_layout_dirty);
      }

      template<class T>
      T^ get_control()
      {
        if (inner != nullptr)
          return dynamic_cast<T^>(inner);
        else
          return dynamic_cast<T^>(dialog);
      }

      template<class T>
      static T* get_backend_control(Control^ control)
      {
        return reinterpret_cast<T*>(((IntPtr^)control->Tag)->ToPointer());
      }

      virtual property bool LayoutDirty
      {
        bool get() { return layoutDirty; }
        void set(bool value) 
        {
          layoutDirty= value;
          if (value)
          {
            ViewImpl^ parent= get_parent();
            if (parent != nullptr)
              parent->LayoutDirty= value;
          }
        }
      }

      // Some utility functions.
      static bool use_min_size_for_layout(Control^ control);
      static void remove_auto_resize(Control^ control, mforms::AutoResizeMode mode);
      static bool can_auto_resize_vertically(Control^ control);
      static void set_full_auto_resize(Control^ control);
      static bool can_auto_resize_horizontally(Control^ control);
      static mforms::AutoResizeMode get_auto_resize(Control^ control);
      static void set_auto_resize(Control^ control, mforms::AutoResizeMode mode);
      static bool is_layout_dirty(Control^ control);
      static void set_layout_dirty(Control^ control, bool value);
    };

  };
};

#endif
