/*
* This file is part of Code::Blocks Studio, an open-source cross-platform IDE
* Copyright (C) 2003  Yiannis An. Mandravellos
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
* Contact e-mail: Yiannis An. Mandravellos <mandrav@codeblocks.org>
* Program URL   : http://www.codeblocks.org
*
* $Id: help_plugin.cpp,v 1.7 2005/10/07 09:19:31 mandrav Exp $
* $Date: 2005/10/07 09:19:31 $
*/

#include "help_plugin.h"

#include <wx/process.h>
#include <wx/intl.h>
#include <wx/textdlg.h>
#include <wx/xrc/xmlres.h>
#include <wx/fs_zip.h>
#include <wx/mimetype.h>
#include <wx/filename.h>
#include <manager.h>
#include <configmanager.h>
#include <editormanager.h>
#include <messagemanager.h>
#include <projectmanager.h>
#include <cbeditor.h>
#include <cbproject.h>
#include <licenses.h>

#include <wx/help.h> //(wxWindows chooses the appropriate help controller class)
#include <wx/helpbase.h> //(wxHelpControllerBase class)
#include <wx/helpwin.h> //(Windows Help controller)

#ifdef __WXMSW__
#include <wx/msw/helpchm.h> //(MS HTML Help controller)
#endif

#include <wx/generic/helpext.h> //(external HTML browser controller)
#include <wx/html/helpctrl.h> //(wxHTML based help controller: wxHtmlHelpController)

// max 20 help items (it should be sufficient)
#define MAX_HELP_ITEMS 20

int idHelpMenus[MAX_HELP_ITEMS];
int idPopupMenus[MAX_HELP_ITEMS];

CB_IMPLEMENT_PLUGIN(HelpPlugin);

BEGIN_EVENT_TABLE(HelpPlugin, cbPlugin)
  // we hook the menus dynamically
END_EVENT_TABLE()

HelpPlugin::HelpPlugin()
: m_pMenuBar(0), m_LastId(0)
{
  //ctor
  wxString resPath = ConfigManager::Get()->Read(_T("data_path"), wxEmptyString);
  wxXmlResource::Get()->Load(resPath + _T("/help_plugin.zip#zip:*.xrc"));

  m_PluginInfo.name = _T("HelpPlugin");
  m_PluginInfo.title = _T("Help plugin");
  m_PluginInfo.version = _T("0.1");
  m_PluginInfo.description = _T("Code::Blocks Help plugin");
  m_PluginInfo.author = _T("Bourricot | Ceniza (maintainer)");
  m_PluginInfo.authorEmail = _T("titi37fr@yahoo.fr | ceniza@gda.utp.edu.co");
  m_PluginInfo.authorWebsite = _T("www.codeblocks.org");
  m_PluginInfo.thanksTo = _T("Codeblocks dev team !\nBourricot for the initial version");
  m_PluginInfo.license = LICENSE_GPL;
  m_PluginInfo.hasConfigure = true;

  ConfigManager::AddConfiguration(m_PluginInfo.title, _T("/help_plugin"));

  // initialize IDs for Help and popup menu
  for (int i = 0; i < MAX_HELP_ITEMS; ++i)
  {
    idHelpMenus[i] = wxNewId();
    idPopupMenus[i] = wxNewId();

    // dynamically connect the events
    Connect(idHelpMenus[i], -1, wxEVT_COMMAND_MENU_SELECTED,
            (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction)
            &HelpPlugin::OnHelp);
    Connect(idPopupMenus[i], -1, wxEVT_COMMAND_MENU_SELECTED,
            (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction)
            &HelpPlugin::OnFindItem);
  }

  m_LastId = idHelpMenus[0];
}

HelpPlugin::~HelpPlugin()
{
  //dtor
}

void HelpPlugin::OnAttach()
{
  // load configuration (only saved in our config dialog)
  HelpCommon::LoadHelpFilesVector(m_Vector);
}

int HelpPlugin::Configure()
{
  HelpConfigDialog dlg;

  if (dlg.ShowModal() == wxID_OK)
  {
    // remove entries from help menu
    int counter = m_LastId - idHelpMenus[0];
    HelpCommon::HelpFilesVector::iterator it;

    for (it = m_Vector.begin(); it != m_Vector.end(); ++it)
    {
      RemoveFromHelpMenu(idHelpMenus[--counter], it->first);
    }

    // reload configuration (saved in the config dialog)
    HelpCommon::LoadHelpFilesVector(m_Vector);
    BuildMenu(m_pMenuBar);
    return 0;
  }

  return -1;
}

void HelpPlugin::OnRelease(bool appShutDown)
{
	//empty
}

void HelpPlugin::BuildMenu(wxMenuBar *menuBar)
{
  if (!m_IsAttached)
  {
    return;
  }

  m_pMenuBar = menuBar;

  // add entries in help menu
  int counter = 0;
  HelpCommon::HelpFilesVector::iterator it;

  for (it = m_Vector.begin(); it != m_Vector.end(); ++it, ++counter)
  {
    if (counter == HelpCommon::getDefaultHelpIndex())
    {
      AddToHelpMenu(idHelpMenus[counter], it->first + _T("\tF1"));
    }
    else
    {
      AddToHelpMenu(idHelpMenus[counter], it->first);
    }
  }

  m_LastId = idHelpMenus[0] + counter;
}

void HelpPlugin::BuildModuleMenu(const ModuleType type, wxMenu *menu, const wxString &arg)
{
  if (!menu || !m_IsAttached)
  {
    return;
  }

  if (type == mtEditorManager)
  {
    if (m_Vector.size() != 0)
    {
      menu->AppendSeparator();
    }

    // add entries in popup menu
    int counter = 0;
    HelpCommon::HelpFilesVector::iterator it;

    for (it = m_Vector.begin(); it != m_Vector.end(); ++it)
    {
      AddToPopupMenu(menu, idPopupMenus[counter++], it->first);
    }
  }
}

bool HelpPlugin::BuildToolBar(wxToolBar *toolBar)
{
	return false;
}

void HelpPlugin::AddToHelpMenu(int id, const wxString &help)
{
  if (!m_pMenuBar)
  {
    return;
  }

  int pos = m_pMenuBar->FindMenu(_("Help"));

  if (pos != wxNOT_FOUND)
  {
    wxMenu *helpMenu = m_pMenuBar->GetMenu(pos);

    if (id == idHelpMenus[0])
    {
      helpMenu->AppendSeparator();
    }

    helpMenu->Append(id, help);
  }
}

void HelpPlugin::RemoveFromHelpMenu(int id, const wxString &help)
{
  if (!m_pMenuBar)
  {
    return;
  }

  int pos = m_pMenuBar->FindMenu(_("Help"));

  if (pos != wxNOT_FOUND)
  {
    wxMenu *helpMenu = m_pMenuBar->GetMenu(pos);
    wxMenuItem *mi = helpMenu->Remove(id);

    if (id)
    {
      delete mi;
    }

    // remove separator too (if it's the last thing left)
    mi = helpMenu->FindItemByPosition(helpMenu->GetMenuItemCount() - 1);

    if (mi && (mi->GetKind() == wxITEM_SEPARATOR || mi->GetText().IsEmpty()))
    {
      helpMenu->Remove(mi);
      delete mi;
    }
  }
}

void HelpPlugin::AddToPopupMenu(wxMenu *menu, int id, const wxString &help)
{
  wxString tmp;

  if (!help.IsEmpty())
  {
    tmp.Append(_("Locate in "));
    tmp.Append(help);
    menu->Append(id, tmp);
  }
}

wxString HelpPlugin::HelpFileFromId(int id)
{
  int counter = 0;
  HelpCommon::HelpFilesVector::iterator it;

  for (it = m_Vector.begin(); it != m_Vector.end(); ++it, ++counter)
  {
    if (idHelpMenus[counter] == id || idPopupMenus[counter] == id)
    {
      return it->second;
    }
  }

  return wxEmptyString;
}

void HelpPlugin::LaunchHelp(const wxString &helpfile, const wxString &keyword)
{
  wxString ext = wxFileName(helpfile).GetExt();
  Manager::Get()->GetMessageManager()->DebugLog(_("Help File is %s"), helpfile.c_str());

  if (!keyword.IsEmpty())
  {
#ifdef __WXMSW__
  	if (ext.CmpNoCase(_T("hlp")) == 0)
  	{
      wxWinHelpController HelpCtl;
      HelpCtl.Initialize(helpfile);
      HelpCtl.KeywordSearch(keyword);
      return;
  	}

  	if (ext.CmpNoCase(_T("chm")) == 0)
  	{
      wxCHMHelpController HelpCtl;
      HelpCtl.Initialize(helpfile);
      HelpCtl.KeywordSearch(keyword);
      return;
  	}
#endif
  }

  // Just call it with the associated program
  wxFileType *filetype = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);

  if (!filetype)
  {
    wxMessageBox(_("Couldn't find an associated program to open ") + wxFileName(helpfile).GetFullName(), _("Warning"), wxOK | wxICON_EXCLAMATION);
    return;
  }

  wxExecute(filetype->GetOpenCommand(helpfile));
  delete filetype;
}

// events
void HelpPlugin::OnHelp(wxCommandEvent &event)
{
  int id = event.GetId();
  wxString help = HelpFileFromId(id);
  LaunchHelp(help);
}

void HelpPlugin::OnFindItem(wxCommandEvent &event)
{
  cbEditor *ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();

  if (!ed)
  {
    return;
  }

  cbStyledTextCtrl *control = ed->GetControl();
  wxString text = control->GetSelectedText();

  if (text.IsEmpty())
  {
    int origPos = control->GetCurrentPos();
    int start = control->WordStartPosition(origPos, true);
    int end = control->WordEndPosition(origPos, true);
    text = control->GetTextRange(start, end);
  }

  int id = event.GetId();
  wxString help = HelpFileFromId(id);
  LaunchHelp(help, text);
}


syntax highlighted by Code2HTML, v. 0.9.1