#!/usr/bin/env python

'''Rearrange a series of lines on stdin into a random order'''

import os
import sys
import random

import python2x3

def usage(retval):
	'''Give a usage message'''
	sys.stderr.write('Usage: %s [-0] [-h|--help]\n' % sys.argv[0])
	sys.stderr.write('-0 gives null termination instead of newline termination\n' % sys.argv[0])
	sys.exit(retval)

def newlines():
	'''Generate lines of text, minus their newline terminator'''
	for line in sys.stdin:
		if line[-1:] == '\n':
			yield line[:-1]
		else:
			yield line

def my_range(maximum):
	'''Generate the values from 0..maximum-1, for consistent semantics between python 2.x and python 3.x'''
	value = 0
	while value < maximum:
		yield value
		value += 1
			
def shuffle(list_, num_elements, verbose, every_n):
	'''rearrange elements of list_ into random order'''
	randobj = random.Random()

	for element_no in my_range(num_elements):
		if verbose and element_no % every_n == 0 and element_no != 0:
			sys.stderr.write('%f%% done\n' % (float(element_no) * 100.0 / float(num_elements)))
		random_element_no = int(randobj.random() * num_elements)
		list_[element_no], list_[random_element_no] = list_[random_element_no], list_[element_no]

def get_input(generator, verbose, every_n):
	'''Get the lines of input we need to rearrange'''
	list_ = []

	for element_no, line in enumerate(generator()):
		if verbose and element_no % every_n == 0 and element_no != 0:
			sys.stderr.write('read %d lines\n' % element_no)
		list_.append(line)

	num_elements = len(list_)

	return list_, num_elements

def main():
	'''Main function'''
	use_readline0 = False
	verbose = False
	every_n = 1000

	while sys.argv[1:]:
		if sys.argv[1] == '-0':
			use_readline0 = True
		elif sys.argv[1] == '-v':
			verbose = True
		elif sys.argv[1] in [ '-h', '--help' ]:
			usage(0)
		else:
			sys.stderr.write('%s: Illegal option: %s\n' % (sys.argv[0], sys.argv[1]))
			usage(1)
		del sys.argv[1]

	if use_readline0:
		import readline0

	if use_readline0:
		generator = readline0.readline0
		terminator = python2x3.string_to_binary('\0')
	else:
		#generator = sys.stdin.readline
		generator = newlines
		terminator = python2x3.string_to_binary('\n')

	list_, num_elements = get_input(generator, verbose, every_n)

	if verbose:
		sys.stderr.write('Read a total of %d lines, about to start swaps\n' % num_elements)

	shuffle(list_, num_elements, verbose, every_n)

	if verbose:
		sys.stderr.write('Done with swaps\n')

	for element in list_:
		os.write(1, python2x3.string_to_binary(element) + terminator)

main()