#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import abc
import copy
import types

class AttribDict(dict):
    """
    This class defines the cracker object, inheriting from Python data
    type dictionary.

    >>> foo = AttribDict()
    >>> foo.bar = 1
    >>> foo.bar
    1
    """

    def __init__(self, indict = None):
        if indict is None:
            indict = {}

        super().__init__(indict)

    def __getattr__(self, item):
        """
        Maps values to attributes
        Only called if there *is NOT* an attribute with this name
        """

        try:
            return self.__getitem__(item)
        except KeyError:
            raise AttributeError("unable to access item {!s}".format(item))

    def __setattr__(self, item, value):
        """
        Maps attributes to values
        """
        if item in self.__dict__:
            super().__setattr__(item, value)
        else:
            self.__setitem__(item, value)

    def __deepcopy__(self, memo):
        retVal = self.__class__()
        memo[id(self)] = retVal

        for attr in dir(self):
            if not attr.startswith('_'):
                value = getattr(self, attr)
                if not isinstance(value, (types.BuiltinFunctionType,
                                            types.FunctionType,
                                            types.MethodType)):
                    setattr(retVal, attr, copy.deepcopy(value, memo))

        for key, value in self.items():
            retVal.__setitem__(key, copy.deepcopy(value, memo))

        return retVal

class Password(metaclass = abc.ABCMeta):
    """
    Password abstract class, define some functions that plugins should implement
    """
    def __init__(self, password):
        self._password = password

    @abc.abstractclassmethod
    def identify(password):
        """
        Identify password type and return True or False
        """
        pass

    @abc.abstractmethod
    def request(self): 
        """
        Request several sites to crack password
        """
        pass

    @abc.abstractmethod
    def crack(self):
        """
        Crack password
        """
        pass
