#include "qgpythonlib.h"

#include "qgpythonlib.h"
#include "Files/qgpython.h"

#include <QLibrary>

namespace PythonQt_QtAll
{
  //! initialize the Qt binding
  __declspec(dllimport) void init();
};

#include "qgpyconsole.h"
#include "qgpyeditdialog.h"

class Concretewidgets: public QgPythonWidgets
{
public:
    QgPyConsole* console;
    QgPyEditDialog* editDialog;

    Concretewidgets():
        console(0),
        editDialog(0)
    {
    }

    virtual QWidget* createConsole(QWidget* parent=0) override
    {
        if (!console)
            console=new QgPyConsole(parent);
        return console;
    }

    virtual QDialog* createEditDialog(QWidget* /*parent*/=0) override
    {
        if (!editDialog)
            editDialog=QgPyEditDialog::singleInstance(); //parent);
        return editDialog;
    }
};

class QgConcretePython: public QgPythonInterface
{
public:
   Concretewidgets concretewidgets;

   QVector<PythonQtObjectPtr> modules;

   QgConcretePython()
   {
   }
   ~QgConcretePython()
   {
   }

   QgPythonWidgets* pythonWidgets() override
   {
       return &concretewidgets;
   }

   PythonQtObjectPtr* mainModule() override
   {
       static PythonQtObjectPtr ptr=QgPython::instance().mainContext();
       return &ptr;
   }

   PythonQtObjectPtr* createModule(const QString& module_name) override
   {
       return createModuleFromScript(module_name, QString());
   }

   virtual PythonQtObjectPtr* createModuleFromScript(const QString& name, const QString& script) override
   {
       PythonQtObjectPtr pyobj=QgPython::instance().self().createModuleFromScript(name,script);
       modules.append(pyobj);
       return &modules.last();
   }

   virtual PythonQtObjectPtr* createModuleFromFile(const QString& name, const QString& file) override
   {
       PythonQtObjectPtr pyobj;
       if (file.isEmpty())
           pyobj=QgPython::instance().self().createModuleFromScript(name,QString());
       else
           pyobj=QgPython::instance().self().createModuleFromFile(name,file);
       if (!pyobj.isNull())
       {
           QgPython::instance().mainContext().evalScript(QString("import %1").arg(name));
       }
       modules.append(pyobj);
       return &modules.last();
   }

   bool addObject(const QString& name, QObject* obj, PythonQtObjectPtr* module) override
   {
       //QgPython::instance().mainContext().addObject(name, obj);
       if (!module)
       {
           qDebug()<<"QGPY:addObject()"<<name<<"(main context)";
           QgPython::instance().mainContext().addObject(name, obj);
       }
       else
       {
           if (module->isNull())
           {
               qWarning()<<"QgPy: invalid module";
               return false;
           }
           else
           {
               qDebug()<<"QGPY:addObject()"<<name<<module;
                module->addObject(name, obj);
           }
        }
       return true;
   }

   virtual bool evalScript(const QString& script, PythonQtObjectPtr* module) override
   {
       if (!module)
           QgPython::instance().mainContext().evalScript(script);
       else
           module->evalScript(script);
       return true;
   }

   virtual bool evalFile(const QString& file, PythonQtObjectPtr* module) override
   {
       if (!module)
           QgPython::instance().mainContext().evalFile(file);
       else
           module->evalFile(file);
       return true;
   }

};

class QgPyInit
{
public:
    QgPyInit()
    {
        //QString pyhome("D:\\Apps\\Portable\\WinPython-32bit-3.6.0.1Qt5\\python-3.6.0");
        QString pyhome(qgetenv("PYTHONHOME"));
        wchar_t buffer[2048];
        pyhome.toWCharArray(buffer);
        Py_SetPythonHome(buffer);

        PythonQt::init(/*PythonQt::IgnoreSiteModule |*/ PythonQt::RedirectStdOut, "PythonQt");

        QgPython& qgpy=QgPython::instance();
        PythonQtObjectPtr mainContext=qgpy.mainContext();

        // add a QObject to the namespace of the main python context
        mainContext.addObject("qgpy", &qgpy);
        //PythonQt_QtAll::init();
    }
};

const char* QGPYTHONSHARED_EXPORT qgp_create(unsigned int)
{
    static  QgPyInit qgPyInit;
    return 0;
}

class QWidget* QGPYTHONSHARED_EXPORT qgp_create_console(QWidget* p)
{
    //static  QgPyInit qgPyInit;
    return new QgPyConsole(p);
}

QgPythonInterface* QGPYTHONSHARED_EXPORT qgp_instance(void)
{
    static QgConcretePython concrete;
    return &concrete;
}

const char* QGPYTHONSHARED_EXPORT QGPYTHON_LIB_INITIALIZE_FUNCTION_(unsigned int flags)
{
    return qgp_create(flags);
}

QgPythonInterface* QGPYTHONSHARED_EXPORT QGPYHON_LIB_INSTANCE_FUNCTION_(void)
{
    return qgp_instance();
}
