/*
* Copyright(c) 2017 dragon jiang<jianlinlong@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files(the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#ifndef _BASE_WIDGET_H_
#define _BASE_WIDGET_H_

#include <QtWidgets/QtWidgets>
#include <QWidget>
#include <QDialog>

#include "Skin.h"
#include "Title_Bar.h"

//class Title_Bar;
//class Skin;
class NcFramelessHelper;


class Base_Widget_Imp
{
public:
    Base_Widget_Imp(QWidget *owner, Skin *skin = NULL, bool is_dialog = false);
    ~Base_Widget_Imp();

public:
    //Ƿͨı䴰ڴС
    bool get_resizable() const {return resizable_;}
    void set_resizable(bool b);

    //overwrite
    bool isMaximized() const;
    QString windowTitle() const;
    void setWindowTitle(const QString &);

    //skin
    void load_skin(Skin* skin=NULL);

    //ʾһWidget, WidgetΪ
    void setup_widget(QWidget *content);

    //Իλ, 0ɹֵʧ
    int save_geometry(const QString& name);
    int save_geometry();

    //ָԻλ, 0ɹֵʧ
    int load_geometry(const QString& name);

    //Ļ
    void move_center();

    //ȥ߿Ŀͻrect
    QRect client_rect() const;

    //õıͼƬ
    const QPixmap* bg_pixmap() const;

    //һͻ
    QPoint window_to_client(const QPoint& pt);
    QRect  window_to_client(const QRect& rt);

    //һͻ
    QPoint client_to_window(const QPoint& pt);
    QRect  client_to_window(const QRect& rt);

    //¼ˣpaintEvent, ӴڶԱͼalpha͸
    bool eventFilter( QObject *o, QEvent *e );

    //Ӵڱalpha, 0-255(0:ȫ͸255-͸)
    inline int child_bkg_alpha() const {return child_bkg_alpha_;}
    void set_child_bkg_alpha(int alpha); 

    //޸
    void set_bg_changed() {
        recreate_bg_pixmap_ = true;
    }

public:
    void resizeEvent(QResizeEvent *);
    void paintEvent(QPaintEvent *);

private:
    void load_skin_internal();

    //ͼ, Ͻǻԭʼͼ½
    void draw_bg_topleft(QPainter *painter, const QRect& r, const QPixmap& img);

    //ͼ, Ͻǻԭʼͼ½
    void draw_bg_topright(QPainter *painter, const QRect& r, const QPixmap& img);

protected:
    int  init(bool is_dialog);    //ʼ

public:
    QVBoxLayout  *layout_;                      //parentɾ
    Title_Bar    *title_bar_;                   //parentɾ
    Skin         *skin_;                        //ɾ

private:
    bool               resize_temp_disabled_;   //󻯺ֹ϶ıС
    bool               resizable_;              //Ƿı䴰ڵĴС
    bool               recreate_bg_pixmap_;     //ǷҪ´ͻͼ
    QPixmap           *bg_pixmap_;              //õıͼ
    NcFramelessHelper *resize_helper_;
    QString            save_object_name_;       //ڽڴСλñ
    int                child_bkg_alpha_;         //Ӵڱalpha
    QHash<QObject*, QPixmap*> alpha_cache_;      //ӿؼalpha͸ıͼ

private:
    QWidget *q;                                 //owner
};

//T can be QWidget or QDialog, 
//template class can not have Q_OBJECT, so this class can not have signal/slot
template<class T>
class Base_Widget: public T
{
public:
    Base_Widget(QWidget* parent=NULL, Skin* skin=NULL)
        :T(parent)
    {
        p = new Base_Widget_Imp(this, skin, inherits("QDialog")/*typeid(T) == typeid(QDialog)*/);
    }

    ~Base_Widget()
    {
        delete p;
    }

    typedef typename Base_Widget<T> BaseClass;

public:
    //Ƿͨı䴰ڴС
    bool get_resizable() const {return p->resizable_;}
    void set_resizable(bool b) {p->set_resizable(b);}

    //overwrite
    bool isMaximized() const {return p->isMaximized();}
    QString windowTitle() const {return p->windowTitle();}
    void setWindowTitle(const QString &s) {p->setWindowTitle(s);}

    //skin
    virtual void load_skin(Skin* skin=NULL) {p->load_skin(skin);}

    //ʾ. Qt DesignerƶԻ, Ȼô˷뵽layout_
    template<typename UI>
    QWidget* setup_UI(UI* ui)
    {
        QWidget *content = new QWidget(this);   //parentɾ
        ui->setupUi(content);
        setup_widget(content);
        return content;
    }

    //ʾһWidget, WidgetΪ
    void setup_widget(QWidget *content) {p->setup_widget(content);}

    //Իλ, 0ɹֵʧ
    int save_geometry(const QString& name) {return p->save_geometry(name);}
    int save_geometry() {return p->save_geometry();}

    //ָԻλ, 0ɹֵʧ
    int load_geometry(const QString& name) {return p->load_geometry(name);}

    //Ļ
    void move_center() {p->move_center();}

    //ȥ߿Ŀͻrect
    QRect client_rect() const {return p->client_rect();}

    //ͼƬ
    const QPixmap* bg_pixmap() const {return p->bg_pixmap();}

    //һͻ
    QPoint window_to_client(const QPoint& pt) {return p->window_to_client(pt);}
    QRect  window_to_client(const QRect& rt) {return p->window_to_client(rt);}

    //һͻ
    QPoint client_to_window(const QPoint& pt) {return p->client_to_window(pt);}
    QRect  client_to_window(const QRect& rt) {return p->client_to_window(rt);}

    /*
    ¼ˣpaintEvent, ӴڱͼƬalpha͸
    Ӵһ͸ıͼinstallEventFilter(w), Ȼ󴰿ڼɵӴڱ͸
    */
    bool eventFilter( QObject *o, QEvent *e )
    {
        if (alpha_children_.contains(o)) {
            if (p->eventFilter(o, e)) {
                return true;
            }
        }
        return T::eventFilter(o, e);
    }

    //Ӵڱalpha, 0-255(0:ȫ͸255-͸)
    inline int child_bkg_alpha() const {p->child_bkg_alpha();}
    inline void set_child_bkg_alpha(int alpha) {p->set_child_bkg_alpha(alpha);}

    //ӿؼ@childıalpha͸. qssΪ@childһ͸border-image
    void make_bkg_alpha(QWidget *child) 
    {
        alpha_children_.insert(child); 
        child->installEventFilter(this);
    }

    void redraw_background() {
        p->set_bg_changed();
        this->update();
    }

public:
    QVBoxLayout*  layout()    {return p->layout_;}
    Title_Bar*    title_bar() {return p->title_bar_;}
    Skin*         skin()      {return p->skin_;}

protected:
    void resizeEvent(QResizeEvent *e) {p->resizeEvent(e);}
    void paintEvent(QPaintEvent *e) {p->paintEvent(e);}

private:
    Base_Widget_Imp *p;
    QSet<QObject*> alpha_children_;
};

//@childе@parent
void CenterParent(QWidget* parent, QWidget* child);


#endif

