# Path: pywebdriver/plugins/base_driver.py
# class ThreadDriver(Thread, AbstractDriver):
#     def __init__(self, *args, **kwargs):
#         Thread.__init__(self)
#         AbstractDriver.__init__(self, *args, **kwargs)
#         self.queue = Queue()
#         self.lock = Lock()
#         self.vendor_product = None
# 
#     def get_vendor_product(self):
#         return self.vendor_product
# 
#     def lockedstart(self):
#         with self.lock:
#             if not self.is_alive():
#                 self.daemon = True
#                 self.start()
# 
#     def set_status(self, status, message=None):
#         if status == self.status["status"]:
#             if message is not None and (
#                 len(self.status["messages"]) == 0
#                 or message != self.status["messages"][-1]
#             ):
#                 self.status["messages"].append(message)
#         else:
#             self.status["status"] = status
#             if message:
#                 self.status["messages"] = [message]
#             else:
#                 self.status["messages"] = []
# 
#     def process_task(self, task, timestamp, data):
#         return getattr(self, task)(data)
# 
#     def push_task(self, task, data=None):
#         if not hasattr(self, task):
#             raise AttributeError("The method %s do not exist for the Driver" % task)
#         self.lockedstart()
#         self.queue.put((time.time(), task, data))
# 
#     def run(self):
#         while True:
#             try:
#                 timestamp, task, data = self.queue.get(True)
#                 self.process_task(task, timestamp, data)
#             except Exception as e:
#                 self.set_status("error", str(e))
#                 errmsg = (
#                     str(e)
#                     + "\n"
#                     + "-" * 60
#                     + "\n"
#                     + traceback.format_exc()
#                     + "-" * 60
#                     + "\n"
#                 )
#                 app.logger.error(errmsg)


import time
from collections import OrderedDict
from .base_driver import ThreadDriver
#   it under the terms of the GNU Affero General Public License as
#   published by the Free Software Foundation, either version 3 of the
#   License, or (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################



class LimitedDict(OrderedDict):
    """A dictionary that only keeps the last few added keys
    This serves as a FIFO cache"""

    def __init__(self, size=20):
        super(LimitedDict, self).__init__()
        self._max_size = size

    def __setitem__(self, key, value):
        if len(self) == self._max_size:
            self.popitem(last=False)
        super(LimitedDict, self).__setitem__(key, value)



# Path: pywebdriver/plugins/base_driver.py
# class ThreadDriver(Thread, AbstractDriver):
#     def __init__(self, *args, **kwargs):
#         Thread.__init__(self)
#         AbstractDriver.__init__(self, *args, **kwargs)
#         self.queue = Queue()
#         self.lock = Lock()
#         self.vendor_product = None
# 
#     def get_vendor_product(self):
#         return self.vendor_product
# 
#     def lockedstart(self):
#         with self.lock:
#             if not self.is_alive():
#                 self.daemon = True
#                 self.start()
# 
#     def set_status(self, status, message=None):
#         if status == self.status["status"]:
#             if message is not None and (
#                 len(self.status["messages"]) == 0
#                 or message != self.status["messages"][-1]
#             ):
#                 self.status["messages"].append(message)
#         else:
#             self.status["status"] = status
#             if message:
#                 self.status["messages"] = [message]
#             else:
#                 self.status["messages"] = []
# 
#     def process_task(self, task, timestamp, data):
#         return getattr(self, task)(data)
# 
#     def push_task(self, task, data=None):
#         if not hasattr(self, task):
#             raise AttributeError("The method %s do not exist for the Driver" % task)
#         self.lockedstart()
#         self.queue.put((time.time(), task, data))
# 
#     def run(self):
#         while True:
#             try:
#                 timestamp, task, data = self.queue.get(True)
#                 self.process_task(task, timestamp, data)
#             except Exception as e:
#                 self.set_status("error", str(e))
#                 errmsg = (
#                     str(e)
#                     + "\n"
#                     + "-" * 60
#                     + "\n"
#                     + traceback.format_exc()
#                     + "-" * 60
#                     + "\n"
#                 )
#                 app.logger.error(errmsg)


# Path: pywebdriver/plugins/payment_base_driver.py
import time
from collections import OrderedDict
from .base_driver import ThreadDriver

#   it under the terms of the GNU Affero General Public License as
#   published by the Free Software Foundation, either version 3 of the
#   License, or (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################



class LimitedDict(OrderedDict):
    """A dictionary that only keeps the last few added keys
    This serves as a FIFO cache"""

    def __init__(self, size=20):
        super(LimitedDict, self).__init__()
        self._max_size = size

    def __setitem__(self, key, value):
        if len(self) == self._max_size:
            self.popitem(last=False)
        super(LimitedDict, self).__setitem__(key, value)



class PaymentTerminalDriver(ThreadDriver):