content: 
  module Converter (rationalToGray, grayToSignIO, signToGray, Gray, startF, startC) where
  
  import Stream
  import Data.Ratio
  import Control.Concurrent
  import Control.Concurrent.MVar
  import System.IO.Unsafe
  
  
  type Gray = [Integer]
  type State = (Integer, Integer)
  
  
  -- Convert a rational number (in (-1,1)) to its Gray representation
  rationalToGray :: Rational -> Gray
  rationalToGray x
                  |x<0            = f (negate' (rationalToStream (-x))) (0,0)
                  |otherwise      = f (rationalToStream x) (0,0)
  
  
  -- Function to implement the two heads Turing machine that convert a
  -- signed-digit stream to the corresponding Gray-code representation
  f :: Stream -> State -> Stream
  f (x:xs) (0,0)
              |x==(-1)    = 0:f xs (0,0)
              |x==0       = c:1:ds
              |x==1       = 1:f xs (1,0)
              where c:ds = f xs (0,1)
  
  f (x:xs) (0,1)
              |x==(-1)    = 0:f xs (1,0)
              |x==0       = c:0:ds
              |x==1       = 1:f xs (0,0)
              where c:ds = f xs (0,1)
  
  f (x:xs) (1,0)
              |x==(-1)    = 1:f xs (0,0)
              |x==0       = c:1:ds
              |x==1       = 0:f xs (1,0)
              where c:ds = f xs (1,1)
  
  f (x:xs) (1,1)
              |x==(-1)    = 1:f xs (1,0)
              |x==0       = c:0:ds
              |x==1       = 0:f xs (0,0)
              where c:ds = f xs (1,1)
  
  
  
  
  -- Anotherway to convert from a rational to Gray code representation
  -- Behave exactly the same like above
  rationalToGray' :: Rational -> Gray
  rationalToGray' x
                  |x<0            = signToGray (negate' (rationalToStream (-x)))
                  |otherwise      = signToGray (rationalToStream x)
  
  
  -- Function to convert a signed-digit stream to Gray representation
  -- Is much shorter than above
  signToGray :: Stream -> Stream
  signToGray (1:xs)       = 1:f'(signToGray xs)
  signToGray ((-1):xs)    = 0:signToGray xs
  signToGray (0:xs)       = c:1:(f' ds)
                          where c:ds = signToGray xs
  
  
  
  -- Convert a Gray-code stream to the corresponding signed-digit representation
  -- Make use of threads
  grayToSignIO :: Stream -> IO Stream
  grayToSignIO (x1:x2:xs) = do
                          c <- threadTesting(x1:x2:xs)
                          if (c==1)
                             then (do  co <- unsafeInterleaveIO (grayToSignIO (f'(x2:xs)))
                                       return (1:co))
                             else if (c==2)
                                     then (do co <- unsafeInterleaveIO (grayToSignIO (x2:xs))
                                              return ((-1):co))
                                     else (do co <- unsafeInterleaveIO (grayToSignIO (x1:f' xs))
                                              return (0:co))
  
  -- Flip the first bit of an infinite stream
  f' (x:xs) = (f'' x):xs
              where f'' 1 = 0
                    f'' 0 = 1
  
  
  -- Launch two threads which run concurrently, test for the first digit of the stream (1, 0 or bottom)
  -- As soon as one thread terminate, grab that result and proceed
  threadTesting :: Stream -> IO Int
  threadTesting xs = do   m <- newEmptyMVar
                          c1 <- forkIO (f1 m xs)
                          c2 <- forkIO (f2 m xs)
                          c <- takeMVar m
                          killThread c1
                          killThread c2
                          return c
  
  -- Test case 1, when the first bit is either 1 or 0.
  -- In case of bottom, f1 will never terminate, then f2 will definitely terminate
  f1 :: MVar Int -> Stream -> IO()
  f1 m (0:xs) = putMVar m 2
  f1 m (1:xs) = putMVar m 1
  
  -- Test case 2, when the first bit is completely ignored, esp in case it was a bottom
  -- If the second bit is 1, then we can output, don't care value of the first bit
  -- If the second bit is 0, then loop forever, give chances to f1 to terminate
  f2 :: MVar Int -> Stream -> IO()
  f2 m (c1:c2:xs)
                  |c2==1          = putMVar m 3
                  |otherwise      = yield
  
  
  
  
  -- Testing
  startC :: IO()
  startC = do
              c<- unsafeInterleaveIO (grayToSignIO (1:1:z0))
              putStrLn (show (take 100 c))
  
  
  startF = signToGray ((-1):1:z0)
  
  
  z0 = 0:z0
  loop' = loop'
  z1' = (1:z1')
  