/*
 * Copyright (c) 2007, 2014, 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 _WB_MODULE_H_
#define _WB_MODULE_H_

#include "grtpp_module_cpp.h"

#include "wb_context.h"

#include "interfaces/plugin.h"

#ifdef _WIN32
  #include "wmi.h"
#endif

#define WBModule_VERSION "5.2.27"

namespace wb {

class WorkbenchImpl : public grt::ModuleImplBase, public PluginInterfaceImpl
{
  typedef grt::ModuleImplBase super;

public:
  WorkbenchImpl(grt::CPPModuleLoader *);
  ~WorkbenchImpl();

  void set_context(WBContext *wb);
  std::string getSystemInfo(bool indent);
  std::map<std::string, std::string> getSystemInfoMap();

  DEFINE_INIT_MODULE(WBModule_VERSION, "Oracle Corporation", grt::ModuleImplBase,
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::getPluginInfo),


    // Non-plugin functions
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::copyToClipboard),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::hasUnsavedChanges),

    // Model
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::newDocument),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::newDocumentFromDB),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::openModel),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::openRecentModel),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::saveModel),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::saveModelAs),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::exit),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::exportPNG),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::exportPDF),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::exportPS),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::exportSVG),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::selectAll),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::selectSimilar),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::selectConnected),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::goToNextSelected),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::goToPreviousSelected),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::highlightFigure),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::editSelectedFigure),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::editSelectedFigureInNewWindow),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::editObject),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::editObjectInNewWindow),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::raiseSelection),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::lowerSelection),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::newDiagram),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::toggleGrid),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::togglePageGrid),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::toggleGridAlign),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::toggleFKHighlight),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::zoomIn),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::zoomOut),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::zoomDefault),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::setFigureNotation),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::setRelationshipNotation),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::setMarker),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::goToMarker),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::startTrackingUndo),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::finishTrackingUndo),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::cancelTrackingUndo),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::createAttachedFile),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::setAttachedFileContents),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::getAttachedFileContents),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::getAttachedFileTmpPath),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::exportAttachedFileContents),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::addUndoListAdd),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::addUndoListRemove),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::addUndoObjectChange),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::addUndoDictSet),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::beginUndoGroup),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::endUndoGroup),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::setUndoDescription),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::createAttachedFile),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::setAttachedFileContents),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::getAttachedFileContents),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::getAttachedFileTmpPath),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::exportAttachedFileContents),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::openModelFile),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::closeModelFile),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::getDbFilePath),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::getTempDir),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::debugShowInfo),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::debugGrtStats),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::debugValidateGRT),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::getVideoAdapter),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::runScriptFile),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::installModuleFile),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::showUserTypeEditor),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::showDocumentProperties),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::showModelOptions),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::showOptions),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::showConnectionManager),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::showInstanceManagerFor),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::showInstanceManager),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::showQueryConnectDialog),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::saveConnections),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::saveInstances),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::refreshHomeConnections),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::showGRTShell),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::newGRTFile),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::openGRTFile),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::showPluginManager),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::reportBug),

    // Utilities
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::input),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::confirm),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::requestFileOpen),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::requestFileSave),

    DECLARE_MODULE_FUNCTION(WorkbenchImpl::createConnectionsFromLocalServers),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::createInstancesFromLocalServers),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::create_connection),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::initializeOtherRDBMS),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::deleteConnection),
    DECLARE_MODULE_FUNCTION(WorkbenchImpl::deleteConnectionGroup)
    );

protected:
  virtual void initialization_done()
  {
    // Called after init_module (defined by DEFINE_INIT_MODULE above) is done.
    // Here we register platform dependent functions.
#ifdef _WIN32
    register_functions(
      DECLARE_MODULE_FUNCTION(WorkbenchImpl::wmiOpenSession),
      DECLARE_MODULE_FUNCTION(WorkbenchImpl::wmiCloseSession),
      DECLARE_MODULE_FUNCTION(WorkbenchImpl::wmiQuery),
      DECLARE_MODULE_FUNCTION(WorkbenchImpl::wmiServiceControl),
      DECLARE_MODULE_FUNCTION(WorkbenchImpl::wmiSystemStat),
      DECLARE_MODULE_FUNCTION(WorkbenchImpl::wmiStartMonitoring),
      DECLARE_MODULE_FUNCTION(WorkbenchImpl::wmiReadValue),
      DECLARE_MODULE_FUNCTION(WorkbenchImpl::wmiStopMonitoring),
      NULL
    );
#endif
  };

private:
  WBContext *_wb;
#ifdef _WIN32
  std::map<int, wmi::WmiServices*> _wmi_sessions;
#ifdef DEBUG
  std::map<int, GThread*> _thread_for_wmi_session;
#endif
  int _last_wmi_session_id;

  std::map<int, wmi::WmiMonitor*> _wmi_monitors;
  int _last_wmi_monitor_id;
#endif

  virtual grt::ListRef<app_Plugin> getPluginInfo();

  int copyToClipboard(const std::string &str);

  int hasUnsavedChanges();

  // file
  int newDocument();
  int newDocumentFromDB();
  int openModel(const std::string &path);
  int openRecentModel(const std::string &index);
  int saveModel();
  int saveModelAs(const std::string &path);
  int exportPNG(const std::string &filename);
  int exportPDF(const std::string &filename);
  int exportPS(const std::string &filename);
  int exportSVG(const std::string &filename);

  int exit();


  // edit
  int selectAll();
  int selectSimilar();
  int selectConnected();

  int editSelectedFigure(const model_DiagramRef &view);
  int editSelectedFigureInNewWindow(const model_DiagramRef &view);

  int editObject(const GrtObjectRef &object);
  int editObjectInNewWindow(const GrtObjectRef &object);

  // canvas manipulation
  int raiseSelection(const model_DiagramRef &view);
  int lowerSelection(const model_DiagramRef &view);

  // view
  int newDiagram(const model_ModelRef &model);

  int toggleGrid(const model_DiagramRef &view);
  int togglePageGrid(const model_DiagramRef &view);
  int toggleGridAlign(const model_DiagramRef &view);
  int toggleFKHighlight(const model_DiagramRef &view);

  int zoomIn();
  int zoomOut();
  int zoomDefault();

  int goToNextSelected();
  int goToPreviousSelected();

  int setMarker(const std::string &marker);
  int goToMarker(const std::string &marker);

  int setFigureNotation(const std::string &name, workbench_physical_ModelRef model);
  int setRelationshipNotation(const std::string &name, workbench_physical_ModelRef model);

  int highlightFigure(const model_ObjectRef &figure);
  // undo
  int startTrackingUndo();
  int finishTrackingUndo(const std::string &description);
  int cancelTrackingUndo();

  int addUndoListAdd(const grt::BaseListRef &list);
  int addUndoListRemove(const grt::BaseListRef &list, int index);
  int addUndoObjectChange(const grt::ObjectRef &object, const std::string &member);
  int addUndoDictSet(const grt::DictRef &dict, const std::string &key);
  int beginUndoGroup();
  int endUndoGroup();
  int setUndoDescription(const std::string &text);

  // attached file management
  std::string createAttachedFile(const std::string &group, const std::string &tmpl);
  int setAttachedFileContents(const std::string &filename, const std::string &text);
  std::string getAttachedFileContents(const std::string &filename);
  std::string getAttachedFileTmpPath(const std::string &filename);
  int exportAttachedFileContents(const std::string &filename, const std::string &export_to);
  workbench_DocumentRef openModelFile(const std::string &path);
  int closeModelFile();
  std::string getDbFilePath();
  std::string getTempDir();

  int runScriptFile(const std::string &filename);
  int installModuleFile(const std::string &filename);

  // debugging
  int debugShowInfo();
  int debugValidateGRT();
  int debugGrtStats();

  int showUserTypeEditor(const workbench_physical_ModelRef &model);
  int showDocumentProperties();
  int showModelOptions(const workbench_physical_ModelRef &model);
  int showOptions();
  int showConnectionManager();
  int showInstanceManagerFor(const db_mgmt_ConnectionRef &conn);
  int showInstanceManager();
  int showQueryConnectDialog();
  int saveConnections();
  int saveInstances();
  int showGRTShell();
  int showPluginManager();
  int newGRTFile();
  int openGRTFile();
  int reportBug(const std::string error_info = "");

  // UI
  int refreshHomeConnections();
  std::string request_input_m(const std::string &caption);

  std::string input(const std::string &caption);
  int confirm(const std::string &title, const std::string &caption);

  std::string requestFileOpen(const std::string &caption, const std::string &extensions);
  std::string requestFileSave(const std::string &caption, const std::string &extensions);
  bool _is_other_dbms_initialized;

#ifdef _WIN32
  int wmiOpenSession(const std::string server, const std::string& user, const std::string& password);
  int wmiCloseSession(int session);
  grt::DictListRef wmiQuery(int session, const std::string& query);
  std::string wmiServiceControl(int session, const std::string& service, const std::string& action);
  std::string wmiSystemStat(int session, const std::string& what);

  int wmiStartMonitoring(int session, const std::string& what);
  std::string wmiReadValue(int monitor);
  int wmiStopMonitoring(int monitor);

#endif

  db_mgmt_ConnectionRef create_connection(const std::string& host, const std::string& user,
    const std::string socket_or_pipe_name, int can_use_networking, int can_use_socket_or_pipe,
    int port, const std::string& name);
  grt::DictListRef getLocalServerList();
  int createConnectionsFromLocalServers();
  int createInstancesFromLocalServers();

  std::string getVideoAdapter();
  std::string getFullVideoAdapterInfo(bool indent);
  int initializeOtherRDBMS();
  int deleteConnection(const db_mgmt_ConnectionRef &connection);
  int deleteConnectionGroup(const std::string& group);
};

};

#endif
