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

import time
from threading import *

class Idler(object):

    def __init__(self, oConnection, fnCallback, oLogger, sDebug):

        self.oThread = Thread(target=self.idle)
        self.oConnection = oConnection
        self.oEvent = Event()
        self.fnCallback = fnCallback
        self.bNeedSync = False
        self.oLogger = oLogger
        self.bAborted = False
        self.sDebug = sDebug

    def start(self):

        self.oThread.start()

    def stop(self):

        if self.oConnection.oImap is not None:
            try:
                # Send a NOOP command to interrupt the IDLE mode and free the blocked thread
                self.oConnection.oImap.noop()
            except:
                pass
        self.oEvent.set()

    def join(self):

        self.oThread.join()

    def idle(self):

        while True:

            if self.oEvent.isSet():
                break

            self.bNeedSync = False
            self.bAborted = False

            def callback(lstArgs):

                if (lstArgs[2] != None) and (lstArgs[2][0] is self.oConnection.oImap.abort):

                    if self.sDebug == 'info':

                        self.oLogger.info('"{0}:{1}" has been closed by the server.'.format(self.oConnection.strLogin, self.oConnection.strFolder))

                    self.bAborted = True

                else:

                    self.bNeedSync = True

                # We may need to skip the condition
                # if not self.oEvent.isSet():
                self.oEvent.set()

            while not self.oConnection.isOpen():

                if self.sDebug == 'info':

                    self.oLogger.info('"{0}:{1}" IDLE is waiting for a connection.'.format(self.oConnection.strLogin, self.oConnection.strFolder))

                time.sleep(10)

            self.oConnection.oImap.idle(callback=callback, timeout=600)
            self.oEvent.wait()

            if self.bNeedSync:

                self.oEvent.clear()
                self.fnCallback(self.oConnection, False)

        try:

            if self.oConnection.oImap != None:
                self.oConnection.oImap.noop()

        except:

            pass

        if self.bAborted:
            self.fnCallback(self.oConnection, True)