import threading;
import queue;
import sys;

#------------------------------------------------------------------------------#

class PrimeWorker(threading.Thread):

   def __init__(self,number,getNextNumber):
       threading.Thread.__init__(self);
       self.MyPrime=number;
       self.MyGetter=getNextNumber;
       self.MyQueue=queue.Queue();

   def run(self):
       while True:
           nb=self.MyGetter();
           if nb==0:
               return;
           if nb % self.MyPrime != 0:
               break;
       # end while

       with primeNumbersLock:
           primeNumbers.append(nb);

       getNextNumber=self.MyQueue.get;
       nextWorker=PrimeWorker(nb,getNextNumber);
       with allThreadsLock:
           allThreads.append(nextWorker);
       nextWorker.start();

       while True:
           nb=self.MyGetter();
           if nb==0:
               self.MyQueue.put(0);
               break;
           if nb % self.MyPrime != 0:
               self.MyQueue.put(nb);
       # end while
        
   # end def
# end class

#------------------------------------------------------------------------------#

class FirstWorker(threading.Thread):

   def __init__(self,maxNumber):
       threading.Thread.__init__(self);
       self.MaxNumber=maxNumber;
       self.MyQueue=queue.Queue();

   def run(self):
       nb=3;
       getNextNumber=self.MyQueue.get;
       thread=PrimeWorker(nb,getNextNumber);
       with allThreadsLock:
           allThreads.append(thread);
       thread.start();

       nb+=2;
       while nb<=self.MaxNumber:
           self.MyQueue.put(nb);
           nb+=2;
       # end while
       
       self.MyQueue.put(0);
   # end def
# end class

#------------------------------------------------------------------------------#

def getPrimeTwins(pList):
   twinsList=[];
   lastNb=3;
   for nb in pList:
       if nb==lastNb+2:
           twinsList.append((lastNb,nb));
       lastNb=nb;
   # end for
   return twinsList;
# end def

#------------------------------------------------------------------------------#

def getNumberInput():
   infoStr="# Enter the largest 'number' for sieving ..."
   errorStr="# Enter a 'number' > 2 OR 'e' for exit ...";
   print(infoStr);
   while True:
       inputData=input("N> ");
       inputData.strip();

       if inputData.isdigit():
           nb=int(inputData);
           if nb>2:
               userData=('number',nb);
               break;
       elif inputData.isalpha():
           if inputData=='e':
               userData=('command',inputData);
               break;
           # end if
       # end if
       print(errorStr);
   # end while
               
   return userData;
# end def

#------------------------------------------------------------------------------#
#------------------------------------------------------------------------------#

if __name__ == '__main__':
   print('\n# Beginning...');

#------------------------------------------------------------------------------#

   infoStr="# Largest number is: "

   while True:
       (taskKind,taskData)=getNumberInput();
       
       if taskKind=='number':
           print(infoStr,taskData,'\n');

           allThreads=[];
           allThreadsLock=threading.Lock();
           primeNumbers=[2,3];
           primeNumbersLock=threading.Lock();

           thread=FirstWorker(taskData);
           with allThreadsLock:
               allThreads.append(thread);
           thread.start();
           for myThread in allThreads:
               myThread.join();
               
       elif taskKind=='command':
           if taskData=='e':
               print('# Exit by user');
               sys.exit();
           else:
               pass;
           # end if
       # end if
       
       nbPrimes=len(primeNumbers);
       print('> Number of primes: ',nbPrimes);

       twinsList=getPrimeTwins(primeNumbers);
       nbTwins=len(twinsList);
       print('> Number of twins: ',nbTwins);
       print('\n> The prime twins are: ');
       print(twinsList,'\n');
   # end while

#------------------------------------------------------------------------------#
   print('# Finished.\n');
# end if main