# -*- coding: utf-8 -*-
# vim: set et sts=2:
# pylint: disable-msg=W0311,C0301,C0103,C0111,R0904,R0903

import ConfigParser
import datetime
import flask
import logging
import logging.handlers
import os, errno
import argparse
import traceback
from slapos.certificate_authority.web import app
from slapos.certificate_authority.certificate_authority import CertificateAuthority

def parseArguments():
  """
  Parse arguments for monitor instance.
  """
  parser = argparse.ArgumentParser()
  parser.add_argument('--ca_dir',
                      help='Certificate authority base directory')
  parser.add_argument('--openssl_bin',
                      default='openssl',
                      help='Path of openssl binary file')
  parser.add_argument('--config_file',
                      help='Openssl configuration file. Default: $ca_dir/openssl.cnf')
  parser.add_argument('--certs_dir',
                      help='Directory where to put generated certificates. Default: $ca_dir/certs')
  parser.add_argument('--key_dir',
                      help='Directory where to put CA keys. Default: $ca_dir/private')
  parser.add_argument('--crl_dir',
                      help='Directory for revoked certificate list. Default: $ca_dir/crl')
  parser.add_argument('--cert_file',
                      help='Path for Certificate file. Defaul: $ca_dir/cacert.pem')
  parser.add_argument('--key_file',
                      help='Path of key file. Default: $key_dir/cakey.pem')
  parser.add_argument('--host',
                      default=[],
                      help='Host or IP of ca server.')
  parser.add_argument('--port',
                      default='9086',
                      help='Port for ca server.')
  parser.add_argument('--debug',
                      action="store_true", dest="debug",
                      help='Enable debug mode.')
  parser.add_argument('--log_file',
                      help='Path for log output')
  parser.add_argument('--trusted_host',
                      default=[],
                      action='append', dest='trusted_host_list',
                      help='IP Allowed to call signcert method.')

  return parser.parse_args()


def getLogger(debug=False, log_file=None):
  logger = logging.getLogger("CertificateAuthority")
  logger.setLevel(logging.INFO)

  if not log_file:
    logger.addHandler(logging.StreamHandler())
  else:
    handler = logging.FileHandler(log_file)
    handler.setFormatter(logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s"))
    logger.addHandler(handler)
    logger.info('Configured logging to file %r' % log_file)

  if debug:
    logger.setLevel(logging.DEBUG)
  return logger

def getConfig(self, key):
  if key in self.keys():
    temp_dict = dict()
    temp_dict.update(self)
    return temp_dict[key]
  else:
    raise KeyError

def start():
  """
  start certificate authority service
  """
  flask.config.Config.__getattr__ = getConfig

  options = parseArguments()
  if not options.ca_dir:
    options.ca_dir = os.getcwd()
  else:
    options.ca_dir = os.path.abspath(options.ca_dir)
  if not options.config_file:
    options.config_file = os.path.join(options.ca_dir, 'openssl.cnf')
  if not options.certs_dir:
    options.certs_dir = os.path.join(options.ca_dir, 'certs')
  if not options.key_dir:
    options.key_dir = os.path.join(options.ca_dir, 'private')
  if not options.crl_dir:
    options.crl_dir = os.path.join(options.ca_dir, 'crl')
  if not options.cert_file:
    options.cert_file = os.path.join(options.ca_dir, 'cacert.pem')
  if not options.key_file:
    options.key_file = os.path.join(options.ca_dir, 'private', 'cakey.pem')
  
  logger = getLogger(options.debug, options.log_file)
  ca = CertificateAuthority(options.openssl_bin,
      openssl_configuration=options.config_file, certificate=options.cert_file,
      key=options.key_file, ca_directory=options.ca_dir)

  #config = Config()
  app.config.update(
    ca_dir=options.ca_dir,
    trusted_host_list=options.trusted_host_list,
    csr_dir=os.path.join(options.ca_dir, 'csr'),
    req_dir=os.path.join(options.ca_dir, 'req'),
    cert_dir=os.path.join(options.ca_dir, 'certs'),
    newcert_dir=os.path.join(options.ca_dir, 'newcerts'),
    crl_dir=os.path.join(options.ca_dir, 'crl'),
    key_dir=os.path.join(options.ca_dir, 'private'),
    ca=ca,
  )

  for key in ['csr', 'req', 'cert', 'crl', 'key', 'newcert']:
    try:
      path = app.config['%s_dir' % key]
      os.makedirs(path)
    except OSError as exc:
      if exc.errno == errno.EEXIST and os.path.isdir(path):
        continue
      else:
        raise

  # Generate certificate Authority cert and key
  ca.checkAuthority()

  app.logger.addHandler(logger)
  app.logger.info("Certificate Authority server started on http://%s:%s" % (
      options.host, options.port))
  app.run(
        debug=options.debug,
        host=options.host,
        port=int(options.port)
    )
