#!/usr/bin/python

# This file is part of Wike (com.github.hugolabe.Wike)
# SPDX-FileCopyrightText: 2021-24 Hugo Olabera <hugolabe@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later


import os
import sys
import gettext

from gi.repository import GLib, Gio

pkgdatadir = '/usr/share/wike'
localedir = '/usr/share/locale'

resource = Gio.Resource.load(os.path.join(pkgdatadir, 'wike.gresource'))
resource._register()
gettext.install('wike', localedir)

from wike import wikipedia
from wike.data import settings, languages

dbus_interface_description = '''
<!DOCTYPE node PUBLIC
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
<node>
  <interface name="org.gnome.Shell.SearchProvider2">
    <method name="GetInitialResultSet">
      <arg type="as" name="terms" direction="in" />
      <arg type="as" name="results" direction="out" />
    </method>
    <method name="GetSubsearchResultSet">
      <arg type="as" name="previous_results" direction="in" />
      <arg type="as" name="terms" direction="in" />
      <arg type="as" name="results" direction="out" />
    </method>
    <method name="GetResultMetas">
      <arg type="as" name="identifiers" direction="in" />
      <arg type="aa{sv}" name="metas" direction="out" />
    </method>
    <method name="ActivateResult">
      <arg type="s" name="identifier" direction="in" />
      <arg type="as" name="terms" direction="in" />
      <arg type="u" name="timestamp" direction="in" />
    </method>
    <method name="LaunchSearch">
      <arg type="as" name="terms" direction="in" />
      <arg type="u" name="timestamp" direction="in" />
    </method>
  </interface>
</node>
'''


# Search provider service for integration with GNOME Shell search

class WikeSearchService:

  # Initialize variables and connect signals

  def __init__(self):
    self._results = dict()
    self._lang = settings.get_string('search-language')

    settings.connect('changed::search-language', self._search_lang_changed_cb)

  # Get results for first search

  def GetInitialResultSet(self, terms):
    text = ' '.join(terms)
    lang = self._lang
    self._results.clear()

    if text.startswith('-'):
      prefix = terms[0].lstrip('-')
      if prefix in languages.wikilangs.keys():
        lang = prefix
      if len(terms) > 1:
        text = text.split(' ', 1)[1]
      else:
        text = ''

    if len(text) > 2:
      if settings.get_boolean('search-desktop'):
        self._get_results(text, lang)
      else:
        key = 'search:' + lang + ':' + text
        value = _('Search “%s” on Wikipedia') % text
        self._results[key] = value

    return self._results.keys()

  # Get results for next searchs

  def GetSubsearchResultSet(self, previous_results, new_terms):
    return self.GetInitialResultSet(new_terms)

  # Get detailed information for results

  def GetResultMetas(self, ids):
    metas = []
    for item in ids:
      if item in self._results:
        meta = dict(id=GLib.Variant('s', item), name=GLib.Variant('s', self._results[item]))
        metas.append(meta)

    return metas

  # Open clicked result in Wike app

  def ActivateResult(self, id, terms, timestamp):
    if id.startswith('search'):
      self._results.clear()
      text = id.replace('search:', '', 1)
      params = text.split(':', 1)
      self._get_results(params[1], params[0])
      if len(self._results) > 0:
        uri = list(self._results.keys())[0]
      else:
        uri = 'notfound'
    else:
      uri = id

    GLib.spawn_async_with_pipes( None, ['/usr/bin/wike', '--url', uri], None, GLib.SpawnFlags.SEARCH_PATH, None )

  # Open Wike app on its current page

  def LaunchSearch(self, terms, timestamp):
    GLib.spawn_async_with_pipes( None, ['/usr/bin/wike'], None, GLib.SpawnFlags.SEARCH_PATH, None )

  # Run Wikipedia search and load results dict

  def _get_results(self, text, lang):
    try:
      found = wikipedia.search(text.lower(), lang, 5, None)
    except:
      found = None
    if found:
      for title, url in zip(found[0], found[1]):
        self._results[url] = title

  # Search language changed in app settings

  def _search_lang_changed_cb(self, settings, key):
    self._lang = settings.get_string('search-language')

# GIO application for search provider

class WikeSearchServiceApplication(Gio.Application):

  def __init__(self):
    Gio.Application.__init__(self,
                             application_id='com.github.hugolabe.Wike.SearchProvider',
                             flags=Gio.ApplicationFlags.IS_SERVICE,
                             inactivity_timeout=10000)
    self.service_object = WikeSearchService()
    self.search_interface = Gio.DBusNodeInfo.new_for_xml(dbus_interface_description).interfaces[0]

  # Register DBUS search provider object

  def do_dbus_register(self, connection, object_path):
    try:
      connection.register_object(object_path=object_path,
                                 interface_info=self.search_interface,
                                 method_call_closure=self.on_dbus_method_call)
    except:
      self.quit()
      return False
    finally:
      return True

  # Handle incoming method calls

  def on_dbus_method_call(self, connection, sender, object_path, interface_name, method_name, parameters, invocation):
    self.hold()

    method = getattr(self.service_object, method_name)
    arguments = list(parameters.unpack())

    results = method(*arguments),
    if results == (None,):
      results = ()
    results_type = '(' + ''.join(map(lambda argument_info: argument_info.signature, self.search_interface.lookup_method(method_name).out_args)) + ')'
    wrapped_results = GLib.Variant(results_type, results)

    invocation.return_value(wrapped_results)

    self.release()

# Run search provider application

if __name__ == '__main__':
  app = WikeSearchServiceApplication()
  sys.exit(app.run())
