# -*- coding: utf-8 -*-
import io
from contextlib import contextmanager

from common import read_signature
# from kdb3 import KDB3Reader, KDB3_SIGNATURE
from kdb4 import KDB4Reader, KDB4_SIGNATURE

BASE_SIGNATURE = 0x9AA2D903

_kdb_readers = {
    # KDB3_SIGNATURE[1]: KDB3Reader,
    #0xB54BFB66: KDB4Reader, # pre2.x may work, untested
    KDB4_SIGNATURE[1]: KDB4Reader,
    }

@contextmanager
def open(filename, **credentials):
    """
    A contextmanager to open the KeePass file with `filename`. Use a `password`
    and/or `keyfile` named argument for decryption.
    
    Files are identified using their signature and a reader suitable for 
    the file format is intialized and returned.
    
    Note: `keyfile` is currently not supported for v3 KeePass files.
    """
    kdb = None
    try:
        with io.open(filename, 'rb') as stream:
            signature = read_signature(stream)
            cls = get_kdb_reader(signature)
            kdb = cls(stream, **credentials)
            yield kdb
            kdb.close()
    except:
        if kdb: kdb.close()
        raise

def add_kdb_reader(sub_signature, cls):
    """
    Add or overwrite the class used to process a KeePass file.
    
    KeePass uses two signatures to identify files. The base signature is 
    always `0x9AA2D903`. The second/sub signature varies. For example
    KeePassX uses the v3 sub signature `0xB54BFB65` and KeePass2 the v4 sub 
    signature `0xB54BFB67`.
    
    Use this method to add or replace a class by givin a `sub_signature` as
    integer and a class, which should be a subclass of 
    `keepass.common.KDBFile`.
    """
    _kdb_readers[sub_signature] = cls

def get_kdb_reader(signature):
    """
    Retrieve the class used to process a KeePass file by `signature`, which
    is a a tuple or list with two elements. The first being the base signature 
    and the second the sub signature as integers.
    """
    if signature[0] != BASE_SIGNATURE:
        raise IOError('Unknown base signature.')
    
    if signature[1] not in _kdb_readers:
        raise IOError('Unknown sub signature.')
    
    return _kdb_readers[signature[1]]

