# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Mobius Forensic Toolkit
# Copyright (C) 2008,2009,2010,2011,2012,2013,2014,2015,2016 Eduardo Aguiar
#
# 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, 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, see <http://www.gnu.org/licenses/>.
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
import mobius.extension
import mobius
import mobius.config
import glob
import os
import os.path

USERDIR = os.path.join (os.path.expanduser ("~"), '.mobiusft')

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief Resource list
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
class ResourceList (object):

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief initialize object
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def __init__ (self):
    self.__resource_ids = []
    self.__resources = {}

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief iterate through resources
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def __iter__ (self):
    for resource_id in self.__resource_ids:
      yield resource_id, self.__resources.get (resource_id)

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief add resource
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def add (self, resource_id, resource):
    self.__resource_ids.append (resource_id)
    self.__resources[resource_id] = resource

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief remove resource
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def remove (self, resource_id):
    try:
      self.__resource_ids.remove (resource_id)
    except ValueError:
      pass

    self.__resources.pop (resource_id, None)

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief get resource
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def get (self, resource_id):
    return self.__resources.get (resource_id)


# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief Application class
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
class Application (object):

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief initialize object
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def __init__ (self):
    self.__resources = {}

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief Return path to application file/directory
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def get_path (self, *args):
    path = USERDIR

    if args:
      path = os.path.join (path, *args)

    return path
      
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief Create application subdirectory
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def make_directory (self, dirname=None):
    dir = self.get_path (dirname)

    if not os.path.isdir (dir):
      os.makedirs (dir)

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief Run application
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def run (self):

    # application data services
    mobius.mediator.advertise ('app.get-user-path', self.svc_get_path)
    mobius.mediator.advertise ('app.get-path', self.svc_get_path)
    mobius.mediator.advertise ('app.get-data-path', self.svc_get_data_path)
    mobius.mediator.advertise ('app.get-name', self.svc_get_name)
    mobius.mediator.advertise ('app.get-version', self.svc_get_version)

    # resource services
    mobius.mediator.advertise ('app.add-resource', self.svc_add_resource)
    mobius.mediator.advertise ('app.remove-resource', self.svc_remove_resource)
    mobius.mediator.advertise ('app.get-resource', self.svc_get_resource)
    mobius.mediator.advertise ('app.list-resources', self.svc_list_resources)

    # extension data services
    mobius.mediator.advertise ('extension.get-metadata', mobius.extension.svc_extension_get_metadata)
    mobius.mediator.advertise ('extension.get-metadata-from-file', mobius.extension.svc_extension_get_metadata_from_file)
    mobius.mediator.advertise ('extension.get-icon-data-from-file', mobius.extension.svc_extension_get_icon_data_from_file)
    mobius.mediator.advertise ('extension.get-icon-path', mobius.extension.svc_extension_get_icon_path)
    mobius.mediator.advertise ('extension.get-resource-path', mobius.extension.svc_extension_get_resource_path)

    # extension running services
    mobius.mediator.advertise ('extension.is-running', mobius.extension.svc_extension_is_running)
    mobius.mediator.advertise ('extension.start-api', mobius.extension.svc_extension_start_api)
    mobius.mediator.advertise ('extension.stop-api', mobius.extension.svc_extension_stop_api)
    mobius.mediator.advertise ('extension.start', mobius.extension.svc_extension_start)
    mobius.mediator.advertise ('extension.stop', mobius.extension.svc_extension_stop)
    mobius.mediator.advertise ('extension.start-all', mobius.extension.svc_extension_start_all)
    mobius.mediator.advertise ('extension.stop-all', mobius.extension.svc_extension_stop_all)
    mobius.mediator.advertise ('extension.list', mobius.extension.svc_extension_list)
    mobius.mediator.advertise ('extension.install', mobius.extension.svc_extension_install)
    mobius.mediator.advertise ('extension.uninstall', mobius.extension.svc_extension_uninstall)

    # configure user account
    self.__configure_user ()

    # start extensions API
    mobius.mediator.call ('extension.start-all')

    # start application
    mobius.mediator.emit ('app.starting')
    mobius.mediator.call ('app.start')
    
    # stop extensions
    mobius.mediator.emit ('app.stopping')
    mobius.mediator.call ('extension.stop-all')

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief Configure application for current user
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def __configure_user (self):

    # if there is no $HOME/.mobiusft/extensions dir, install available extensions
    extensions_dir = self.get_path ('extensions')

    if not os.path.exists (extensions_dir):
      self.make_directory ('extensions')
      dist_dir = mobius.config.get_data_path ('extensions')

      for path in sorted (glob.glob ('%s/*.mobius' % dist_dir)):
        print 'Installing extension %s' % os.path.basename (path)
        mobius.extension.install (path)

    # @begin-deprecated version=0.5.4 brief=force installation of extension-manager
    else:
      extension_manager_dir = self.get_path ('extensions', 'extension-manager')
      if not os.path.exists (extension_manager_dir):
        dist_dir = mobius.config.get_data_path ('extensions')

        for path in sorted (glob.glob ('%s/*.mobius' % dist_dir)):
          print 'Installing extension %s' % os.path.basename (path)
          mobius.extension.install (path)
    # @end-deprecated

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief service: app.add-resource
  # @param resource_id: resource ID
  # @param resource: resource object
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def svc_add_resource (self, resource_id, resource):
    if '.' in resource_id:
      group_id, item_id = resource_id.rsplit ('.', 1)
      resource_list = self.__resources.setdefault (group_id, ResourceList ())
      resource_list.add (item_id, resource)

      mobius.mediator.emit ('app.resource-added', group_id, item_id, resource)

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief service: app.remove-resource
  # @param resource_id: resource ID
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def svc_remove_resource (self, resource_id):
    if '.' in resource_id:
      group_id, item_id = resource_id.rsplit ('.', 1)
      resource_list = self.__resources.setdefault (group_id, ResourceList ())
      resource_list.remove (item_id)

      mobius.mediator.emit ('app.resource-removed', group_id, item_id)

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief service: app.get-resource
  # @param resource_id: resource ID
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def svc_get_resource (self, resource_id):
    value = None

    if '.' in resource_id:
      group_id, item_id = resource_id.rsplit ('.', 1)
      resource_list = self.__resources.setdefault (group_id, ResourceList ())
      value = resource_list.get (item_id)
  
    return value
    
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief service: app.list-resources
  # @param resource_id: group ID
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def svc_list_resources (self, group_id):
    resource_list = self.__resources.get (group_id) or []

    return list (iter (resource_list))

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief Return path to application file/directory
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def svc_get_path (self, *args):
    path = USERDIR

    if args:
      path = os.path.join (path, *args)

    return path

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief Return path to data file/directory
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def svc_get_data_path (self, *args):
    path = mobius.config.get_data_path (*args)
    return path

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief Return application name
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def svc_get_name (self):
    return mobius.config.APP_NAME

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief Return application version
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def svc_get_version (self):
    return mobius.config.APP_VERSION
