/* 
 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; version 2 of the
 * License.
 * 
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#ifndef _MFORMS_VIEW_H_
#define _MFORMS_VIEW_H_

#include <mforms/base.h>
#include <boost/signals2.hpp>

#include "base/geometry.h"
#include "base/trackable.h"
#include "base/drawing.h"

namespace mforms {

  class View;

  enum Alignment
  {
    NoAlign,
    BottomLeft,
    BottomCenter,
    BottomRight,
    MiddleLeft,
    MiddleCenter,
    MiddleRight,
    TopLeft,
    TopCenter,
    TopRight,
    
    //
    WizardLabelAlignment
  };
  
  struct TextAttributes
  {
#ifndef SWIG
    bool bold;
    bool italic;
    base::Color color;
    TextAttributes() : bold(false), italic(false), color(base::Color::Invalid()) {}
#endif
    TextAttributes(const std::string &c, bool b, bool i) : bold(b), italic(i), color(base::Color::parse(c)) {}
  };

  // Mouse button indicators for mouse handling routines.
  enum MouseButton {
    MouseButtonLeft = 0,
    MouseButtonRight = 1,
    MouseButtonMiddle = 2,
    
    MouseButtonNone = 0x80, // Sometimes the values for the mouse buttons are hardcoded, so better use a high value for this.
  };

#ifndef DOXYGEN_SHOULD_SKIP_THIS
#ifndef SWIG
  struct ViewImplPtrs
  {
    void (__stdcall *destroy)(View *self);

    int (__stdcall *get_width)(View *self);
    int (__stdcall *get_height)(View *self);
    int (__stdcall *get_preferred_width)(View *self);
    int (__stdcall *get_preferred_height)(View *self);
    void (__stdcall *set_size)(View *self, int, int);
    void (__stdcall *set_padding)(View *self, int, int, int, int); // left, top, right, bottom

    int (__stdcall *get_x)(View *self);
    int (__stdcall *get_y)(View *self);
    void (__stdcall *set_position)(View *self, int, int);
    void (__stdcall *client_to_screen)(View *self, int&, int&);

    void (__stdcall *show)(View *self, bool);
    bool (__stdcall *is_shown)(View *self);
    
    void (__stdcall *set_tooltip)(View *self, const std::string&);
    void (__stdcall *set_name)(View *self, const std::string&);
    void (__stdcall *set_font)(View *self, const std::string&);
    
    void (__stdcall *set_enabled)(View *self, bool);
    bool (__stdcall *is_enabled)(View *self);
    void (__stdcall *relayout)(View *self);
    void (__stdcall *set_needs_repaint)(View *self);

    void (__stdcall *suspend_layout)(View *self, bool);
    void (__stdcall *set_front_color)(View *self, const std::string&);
    std::string (__stdcall *get_front_color)(View *self);
    void (__stdcall *set_back_color)(View *self, const std::string&);
    std::string (__stdcall *get_back_color)(View *self);
    // for containers only
    void (__stdcall *set_back_image)(View *self, const std::string&, Alignment alignment);

    void (__stdcall *flush_events)(View *self);

    void (__stdcall *focus)(View *self);
  };
#endif
#endif
  
  class Form;

  class MFORMS_EXPORT View : public Object, public base::trackable
  {
    friend class ControlFactory;
    
  private:
    std::string _name;
    bool _layout_dirty;
    
    boost::signals2::signal<void ()> _signal_resized;

  protected:
    View();

    ViewImplPtrs *_view_impl;
    View *_parent;
    std::vector<std::pair<View*, bool> > _subviews;

    void cache_view(View *sv);
    virtual void remove_from_cache(View *sv);
    int get_subview_index(View *sv);
    View *get_subview_at_index(int index);
    
    // This works only for containers so is made public in the Container subclass
    virtual void set_back_image(const std::string& path, Alignment alignment);
  public:
    virtual ~View();
    
    virtual void set_managed();
    
    View *find_subview(const std::string &name);
    bool contains_subview(View* subview);
    void clear_subviews();
    
    void set_name(const std::string &name);
    void set_tooltip(const std::string &text);
    void set_font(const std::string &fontDescription); // e.g. "Trebuchet MS bold 9"
    std::string get_name();
    void set_parent(View *parent);
    View *get_parent() const;
    Form *get_parent_form() const;
    virtual int get_width();
    virtual int get_height();
    virtual int get_preferred_width();
    virtual int get_preferred_height();
    virtual int get_x();
    virtual int get_y();
    virtual void set_position(int x, int y);
    virtual void set_size(int width, int height);

    void client_to_screen(int& x, int& y);

    void show(bool flag= true);
    bool is_shown();
    void set_enabled(bool flag);
    bool is_enabled();
    void set_needs_repaint();

    virtual void relayout();
    virtual void set_layout_dirty(bool value);
    virtual bool is_layout_dirty();
    
    void suspend_layout();
    void resume_layout();
    void set_front_color(const std::string& color);
    std::string get_front_color();
    void set_back_color(const std::string& color);
    std::string get_back_color();
    
    void show_retain_counts(int depth=0);

    virtual std::string get_string_value() { return ""; }
    virtual int get_int_value() { return 0; }
    virtual bool get_bool_value() { return false; }

    virtual void flush_events();

    virtual void focus();
    void focus_changed();

    /** Triggered by the platform layers when the size of the view changes. */
    virtual void resize();

    boost::signals2::signal<void ()>* signal_resized() { return &_signal_resized; }
  };
};

#endif
