#----------------------------------------------------------------------
# Copyright (c) 2010-2013 Raytheon BBN Technologies
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and/or hardware specification (the "Work") to
# deal in the Work without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Work, and to permit persons to whom the Work
# is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Work.
#
# THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS
# IN THE WORK.
#----------------------------------------------------------------------
'''
Credential creation and verification utilities.
'''

import os
import logging
import xmlrpclib
import sys
import datetime
import dateutil

import ext.sfa.trust.credential as cred
import ext.sfa.trust.gid as gid
import ext.sfa.trust.rights as rights
from ext.sfa.util.xrn import hrn_authfor_hrn

def naiveUTC(dt):
    """Converts dt to a naive datetime in UTC.

    if 'dt' has a timezone then
        convert to UTC
        strip off timezone (make it "naive" in Python parlance)
    """
    if dt.tzinfo:
        tz_utc = dateutil.tz.tzutc()
        dt = dt.astimezone(tz_utc)
        dt = dt.replace(tzinfo=None)
    return dt

class CredentialVerifier(object):
    """Utilities to verify signed credentials from a given set of 
    root certificates. Will compare target and source URNs, and privileges.
    See verify and verify_from_strings methods in particular."""

    CATEDCERTSFNAME = 'CATedCACerts.pem'

    # root_cert_fileordir is a trusted root cert file or directory of
    # trusted roots for verifying credentials
    def __init__(self, root_cert_fileordir, crl_files_path):
        self.logger = logging.getLogger('cred-verifier')
        if root_cert_fileordir is None:
            raise Exception("Missing Root certs argument")
        elif os.path.isdir(root_cert_fileordir):
            files = os.listdir(root_cert_fileordir)
            self.root_cert_files = []
            for file in files:
                # FIXME: exclude files that aren't cert files?
                if file == CredentialVerifier.CATEDCERTSFNAME:
                    continue
                self.root_cert_files.append(os.path.expanduser(os.path.join(root_cert_fileordir, file)))
            self.logger.info('Will accept credentials signed by any of %d root certs found in %s: %r' % (len(self.root_cert_files), root_cert_fileordir, self.root_cert_files))
        elif os.path.isfile(root_cert_fileordir):
            self.logger.info('Will accept credentials signed by the single root cert %s' % root_cert_fileordir)
            self.root_cert_files = [root_cert_fileordir]
        else:
            raise Exception("Couldn't find Root certs in %s" % root_cert_fileordir)

        self.crl_files_path = crl_files_path

    @classmethod
    def getCAsFileFromDir(cls, caCerts):
        '''Take a directory of CA certificates and concatenate them into a single
        file suitable for use by the Python SSL library to validate client 
        credentials. Existing file is replaced.'''
        if caCerts is None:
            raise Exception ('Missing caCerts argument')
        if os.path.isfile(os.path.expanduser(caCerts)):
            return caCerts
        if not os.path.isdir(os.path.expanduser(caCerts)):
            raise Exception ('caCerts arg Not a file or a dir: %s' % caCerts)

        logger = logging.getLogger('cred-verifier')

        # Now we have a dir of caCerts files
        # For each file in the dir (isfile), concatenate them into a new file
        comboFullPath = os.path.join(caCerts, CredentialVerifier.CATEDCERTSFNAME)

        caFiles = os.listdir(caCerts)
        #logger.debug('Got %d potential caCert files in the dir', len(caFiles))

        outfile = open(comboFullPath, "w")
        okFileCount = 0
        for filename in caFiles:
            filepath = os.path.join(caCerts, filename)
            # Confirm it's a CA file?
            #        if not file.endswith('.pem'):
            #            continue
            if not os.path.isfile(os.path.expanduser(filepath)):
                logger.debug('Skipping non file %s', filepath)
                continue
            if filename == CredentialVerifier.CATEDCERTSFNAME:
                # logger.debug('Skipping previous cated certs file')
                continue
            okFileCount += 1
            logger.info("Adding trusted cert file %s", filename)
            certfile = open(filepath)
            for line in certfile:
                outfile.write(line)