#include <iostream>
#include <sstream>

#include "flow.hpp"

// ============================================================================
// Search function looks for a number of the form
// 8*k + base to divide the prime number. Correct
// values of 'base' are 1, 3, 5 and 7.

struct search
{
  int candidate;
 
  void operator () (flows::writer<int> out, int base) const
  {
    int i = 8 + base;

    // Stop processing once the output flow is silent,
    // since our answer is not needed anymore.
    while (!out.silent() && 
           candidate % i != 0 && 
           i * i <= candidate)
      {
        i += 8;
      }

    if (candidate % i == 0) 
      out.put(i);
  }

  search(int candidate) : candidate(candidate) {}
};

// ============================================================================
// The entry point. Asks for a number, determines if
// it's divides by 2, 3, 5 or 7, and then looks for
// higher-value divisors using four helper threads.  

int main()
{
  int candidate;
  
  std::cout << "Enter prime number candidate: \n";
  std::cin >> candidate;

  boost::optional<int> divisor;
  if (candidate % 2 == 0 && candidate != 2) divisor = 2;
  if (candidate % 3 == 0 && candidate != 3) divisor = 3;
  if (candidate % 5 == 0 && candidate != 5) divisor = 5;
  if (candidate % 7 == 0 && candidate != 7) divisor = 7;

  if (!divisor)
    {
      int base[] = { 1, 3, 5, 7 }; 
      
      // Generate a flow using four sub-threads. The flow
      // will contain between zero and four numbers which
      // divide the candidate.
      flows::reader<int> flow = 
        flows::generate<int>(search(candidate), base, base + 4);

      // The current thread remains as a blocked controller:
      // as soon as a divisor is found (or no divisors are
      // guaranteed to exist) it wakes up and silences the
      // flow, prompting any remaining threads to stop
      // computing.
      divisor = flow.get();
    }

  if (divisor) 
    std::cout << "The number is not prime, "
              << "it is divided by " << *divisor << "\n";

  else
    std::cout << "The number is prime.\n";
}
