import gpgme
import os
from StringIO import StringIO

class GPG2Signer(object):
  """ Helper class for signing data using GPG2. """
  def __init__(self, app, key_directory):
    if not app.config.get('GPG2_PRIVATE_KEY_NAME'):
      raise Exception('Missing configuration key GPG2_PRIVATE_KEY_NAME')

    if not app.config.get('GPG2_PRIVATE_KEY_FILENAME'):
      raise Exception('Missing configuration key GPG2_PRIVATE_KEY_FILENAME')

    if not app.config.get('GPG2_PUBLIC_KEY_FILENAME'):
      raise Exception('Missing configuration key GPG2_PUBLIC_KEY_FILENAME')

    self._ctx = gpgme.Context()
    self._ctx.armor = True
    self._private_key_name = app.config['GPG2_PRIVATE_KEY_NAME']
    self._public_key_path = os.path.join(key_directory, app.config['GPG2_PUBLIC_KEY_FILENAME'])

    key_file = os.path.join(key_directory, app.config['GPG2_PRIVATE_KEY_FILENAME'])
    if not os.path.exists(key_file):
      raise Exception('Missing key file %s' % key_file)

    with open(key_file, 'rb') as fp:
      self._ctx.import_(fp)

  @property
  def name(self):
    return 'gpg2'

  @property
  def public_key_path(self):
    return self._public_key_path

  def detached_sign(self, stream):
    """ Signs the given stream, returning the signature. """
    ctx = self._ctx
    ctx.signers = [ctx.get_key(self._private_key_name)]
    signature = StringIO()
    new_sigs = ctx.sign(stream, signature, gpgme.SIG_MODE_DETACH)

    signature.seek(0)
    return signature.getvalue()


class Signer(object):
  def __init__(self, app=None, key_directory=None):
    self.app = app
    if app is not None:
      self.state = self.init_app(app, key_directory)
    else:
      self.state = None

  def init_app(self, app, key_directory):
    preference = app.config.get('SIGNING_ENGINE', None)
    if preference is None:
      return None

    return SIGNING_ENGINES[preference](app, key_directory)

  def __getattr__(self, name):
    return getattr(self.state, name, None)


SIGNING_ENGINES = {
  'gpg2': GPG2Signer
}