'''
Generators that repeate stuff.

@author: <NAME>
@version: $Id: repeater.py 2020 2010-04-14 23:13:14Z meddingt $
'''

#
# Copyright (c) <NAME>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy 
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights 
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
# copies of the Software, and to permit persons to whom the Software is 
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in	
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#

# Authors:
#   <NAME> (<EMAIL>)

# $Id: repeater.py 2020 2010-04-14 23:13:14Z meddingt $

import static
from Peach import generator, group
from Peach.generator import Generator

#__all__ = ['Repeater']

class Repeater(generator.Generator):
	'''
	Will repeat a value (generated by a Generator) by round count.  Can be 
	used for basic buffer overflow testing.
	
	Example:
	
		>>> gen = Repeater(None, String("A"), 3)
		>>> gen.getValue()
		A
		>>> gen.next()
		>>> gen.getValue()
		AA
		>>> gen.next()
		>>> gen.getValue()
		AAA
	
	Example:
	
		>>> gen = Repeater(None, Static("Peach "), 5, 3)
		>>> gen.getValue()
		Peach
		>>> gen.next()
		>>> gen.getValue()
		Peach Peach Peach Peach Peach
		>>> gen.next()
		>>> gen.getValue()
		Peach Peach Peach Peach Peach Peach Peach Peach Peach Peach
		
	
	'''
	
	def __init__(self, group, generator, incrementor = 1, maxSteps = -1, startStep = None):
		'''
		@type	group: Group
		@param	group: Group this generator belongs to
		@type	generator: Generator
		@param	generator: Generator to repeate
		@type	incrementor: number
		@param	incrementor: Multiplier against round count
		@type	maxSteps: number
		@param	maxSteps: Maximum repeates
		@type	startSteps: number
		@param	startSteps: Start at this step
		'''
		Generator.__init__(self)
		self._incrementor = None
		self._roundCount = 1
		self._generator = None
		self._maxSteps = -1
		self._generator = generator
		self._incrementor = incrementor
		self.setGroup(group)
		self._maxSteps = maxSteps
		self._startStep = startStep
		
		if self._startStep != None:
			self._roundCount = self._startStep
	
	def next(self):
		self._roundCount+=1
		if self._maxSteps != -1 and self._roundCount > self._maxSteps:
			self._roundCount -= 1
			raise generator.GeneratorCompleted("Peach.repeater.Repeater")
	
	def getRawValue(self):
		# Hah, this is much faster then the old way!
		ret = str(self._generator.getValue()) * (self._roundCount*self._incrementor)
		#for i in range(self._roundCount*self._incrementor):
		#	ret += self._generator.getValue()
		return ret
	
	def getGenerator(self):
		'''
		Get Generator who's value we will repeat.
		
		@rtype: Generator
		@return: Generator we are repeating
		'''
		return self._generator
	def setGenerator(self, generator):
		'''
		Set Generator who's value we will repeat.
		
		@type	generator: Generator
		@param	generator: Generator to repeate
		'''
		self._generator = generator
	
	def reset(self):
		self._roundCount = 1
		
		if self._startStep != None:
			self._roundCount = self._startStep
		
		self._generator.reset()
	
	def unittest():
		g = group.Group()
		r = Repeater(g, static.Static('A'), 1, 10)
		
		try:
			while g.next():
				print r.getValue()
		except group.GroupCompleted:
			pass
	unittest = staticmethod(unittest)


class RepeaterGI(generator.Generator):
	'''
	Will repeat a value (generated by a Generator) by multiplier (generator).
	
	Example:
	
		Repeater(None, String("A"), BadUnsignedNumbers(None))
	
	Would produce a string of A's the length of each number returned by
	BadUnsignedNumbers.
	
	'''
	
	def __init__(self, group, generator, incrementor):
		'''
		@type	group: Group
		@param	group: Group this generator belongs to
		@type	generator: Generator
		@param	generator: Generator to repeate
		@type	incrementor: Generator
		@param	incrementor: Multiplier against round count
		'''
		Generator.__init__(self)
		self._incrementor = None
		self._roundCount = 1
		self._generator = None
	
		self._generator = generator
		self._incrementor = incrementor
		self.setGroup(group)
	
	def next(self):
		self._roundCount+=1
		self._incrementor.next()
	
	def getRawValue(self):
		try:
			ret = str(self._generator.getValue()) * int(self._incrementor.getValue())
		
		except OverflowError:
			# Integer overflow exception.  Oh well, we tried!
			ret = self._generator.getValue()
		
		except MemoryError:
			ret = self._generator.getValue()
			#print "RepeaterGI: MemoryError! Value is %d long multiplier is %d." % (
			#	len(str(ret)), int(self._incrementor.getValue()))
			
		return ret
	
	def reset(self):
		self._roundCount = 1
		self._incrementor.reset()
		self._generator.reset()
	

# end
