# -*- coding: utf-8 -*-
"""


<DefineSource>
@Date : Fri Nov 14 13:20:38 2014 \n
@Author : Erwan Ledoux \n\n
</DefineSource>


The Doer defines instances that are going to decorate a big family of classes in this framework. 
Staying on the idea, that one module should associate
one class, now a decorated class by a Doer should have a NameStr that is 
a DoStr and express also method a method with the name <DoStr>[0].lower()+<DoStr>[1:]
All the attributes that are controlling this method process are <DoingStr><MiddleStr><TypeStr>
and all the ones resetted during the method are <DoneStr><MiddleStr><TypeStr>.
This helps a lot for defining a fisrt level of objects that are acting like input-output controllers.

"""

#<DefineAugmentation>
import ShareYourSystem as SYS
BaseModuleStr="ShareYourSystem.Standards.Classors.Defaultor")
DecorationModule=BaseModule
SYS.setSubModule(globals())
#</DefineAugmentation>

#<ImportSpecificModules>

import collections
import inspect
import six
#</ImportSpecificModules>

#<DefineLocals>
DoingAttributePrefixStr='_'
#DoingDecorationPrefixStr='@'
DoingWrapPrefixStr='do_'
DoingDecorationPrefixStr=""
DoingDecorationTagStr="superDo"
DoingDecorationSuffixStr="_"
#</DefineLocals>

#<DefineFunctions>
def DefaultDoFunction(
	_InstanceVariable,
	*_LiargVariablesList,
	**_KwargVariablesDict
):
	return _InstanceVariable

def do(
				_InstanceVariable,
				*_LiargVariablesList,
				**_KwargVariablesDict
			):

	#Define
	DoDecorationMethodStr=_KwargVariablesDict['DoDecorationMethodStr']
	DoMethodStr=DoDecorationMethodStr.split(DoingDecorationSuffixStr)[-1] if DoingDecorationSuffixStr in DoDecorationMethodStr else DoDecorationMethodStr
	DoStr=DoMethodStr[0].upper()+DoMethodStr[1:]
	DoingStr=DoStrToDoingStrOrderedDict[DoStr]
	DoClassStr=_KwargVariablesDict['DoClassStr']
	DoClass=getattr(SYS,DoClassStr)
	DoWrapMethodStr=DoingWrapPrefixStr+DoMethodStr
	DoWrapUnboundMethod=getattr(
								DoClass,
								DoWrapMethodStr
							)
	del _KwargVariablesDict['DoDecorationMethodStr']
	del _KwargVariablesDict['DoClassStr']

	#debug
	'''
	print('Doer l.54 inside of the function DoFunction')
	print('InstanceVariable is ',_InstanceVariable)
	print('_LiargVariablesList is ',_LiargVariablesList)
	print('_KwargVariablesDict is ',_KwargVariablesDict)
	print('')
	'''

	#Definition of the DoKwargTuplesList
	DoKwargTuplesList=map(
		lambda __KwargTuple:
		(
			DoingStr+DoingAttributePrefixStr.join(
			__KwargTuple[0].split(DoingAttributePrefixStr)[1:]),
			__KwargTuple[1]
		) if __KwargTuple[0].startswith(DoingAttributePrefixStr)
		else __KwargTuple,
		_KwargVariablesDict.items()
	)

	#Check
	if len(DoKwargTuplesList)>0:

		#group by
		[
			DoClass.DoTempAttributeItemTuplesList,
			DoClass.DoTempNotAttributeItemTupleItemsList
		]=SYS.groupby(
			lambda __DoKwargTuple:
			hasattr(_InstanceVariable,__DoKwargTuple[0]),
			DoKwargTuplesList
		)

		#set in the instance the corresponding kwarged arguments
		map(	
				lambda __DoTempAttributeItemTuple:
				#set direct explicit attributes
				_InstanceVariable.__setattr__(*__DoTempAttributeItemTuple),
				DoClass.DoTempAttributeItemTuplesList
			)

		#Define
		DoneKwargDict=dict(DoClass.DoTempNotAttributeItemTupleItemsList)

	else:

		#Define
		DoneKwargDict={}

	#map
	TypeClassesList=map(
			lambda __DoneKeyStr:
			SYS.getTypeClassWithTypeStr(
					SYS.getTypeStrWithKeyStr(__DoneKeyStr)
			)
			if getattr(_InstanceVariable,__DoneKeyStr)==None 
			else None.__class__,
			DoClass.DoingAttributeVariablesOrderedDict.keys(
				)+DoClass.DoneAttributeVariablesOrderedDict.keys()
	)

	#debug
	'''
	print('TypeClassesList is '+str(TypeClassesList))
	print('')
	'''

	#set in the instance
	map(
			lambda __DoneKeyStr,__TypeClass:
			setattr(
					_InstanceVariable,
					__DoneKeyStr,
					__TypeClass()
			)
			if __TypeClass!=None.__class__ 
			else None,
			DoClass.DoingAttributeVariablesOrderedDict.keys(
				)+DoClass.DoneAttributeVariablesOrderedDict.keys(),
			TypeClassesList
	)

	#debug
	'''
	print('Doer l.274 we are going to call the DoWrapMethod')
	print('DoWrapMethod is ',DoWrapMethod)
	print('')
	'''

	#Return the call of the defined do method
	if len(DoneKwargDict)>0:
		return DoWrapUnboundMethod(
			_InstanceVariable,
			*_LiargVariablesList,
			**DoneKwargDict
		)
	else:
		return DoWrapUnboundMethod(
			_InstanceVariable,
			*_LiargVariablesList
		)
#</DefineFunctions>


#<DefineClass>
@DecorationClass()
class DoerClass(BaseClass):

	def default_init(self,
						_DoClass=None,
						_DoingGetBool=False,
						**_KwargVariablesDict
					):
	
		#Call the parent init method
		BaseClass.__init__(self,**_KwargVariablesDict)

	def __call__(self,_Class):

		#debug
		'''
		print('Doer l.247 __call__ method')
		print('_Class is ',_Class)
		print('')
		'''

		#Call the parent init method
		BaseClass.__call__(self,_Class)

		#Do
		self.do(_Class)

		#Debug
		'''
		print('do is done')
		print('')
		'''

		#Return 
		return _Class

	def do(self,_Class):

		#set
		self.DoClass=_Class
		
		#debug
		'''
		print("Doer l.337 : self.DoClass is ",self.DoClass)
		print('')
		'''

		#alias
		DoClass=self.DoClass

		#Definition
		DoerStr=DoClass.NameStr
		DoStr=DoerStrToDoStrOrderedDict[DoerStr]
		DoMethodStr=DoStr[0].lower()+DoStr[1:] if DoStr[0]!='_' else '_'+DoStr[1].lower()+DoStr[2:]
		DoneStr=DoStrToDoneStrOrderedDict[DoStr]
		DoingStr=DoneStrToDoingStrOrderedDict[DoneStr]
		LocalVariablesDict=vars()

		#debug
		print('Doer l.132 : DoerStr is '+DoerStr)
		print('DoStr is '+DoStr)
		print('DoMethodStr is '+DoMethodStr)
		print('DoingStr is '+DoingStr)
		print('DoneStr is '+DoneStr)
		print('')

		#set 
		map(
				lambda __KeyStr:
				setattr(DoClass,__KeyStr,LocalVariablesDict[__KeyStr]),
				['DoerStr','DoStr','DoneStr','DoingStr','DoMethodStr']
			)
		
		#set a lists that will contain the tempory setting items during a call of the <do> method in the instance
		DoClass.DoHistoryOrderedDict=collections.OrderedDict()

		#Check
		if hasattr(DoClass,'DefaultAttributeItemTuplesList'):
			
			#Debug
			'''
			print('Doer l.383')
			print('DoClass.DefaultAttributeItemTuplesList is ',_Class.DefaultAttributeItemTuplesList)
			print('')
			'''

			#Check for doing and done keyStrs
			DoClass.DoneAttributeVariablesOrderedDict=collections.OrderedDict(
				SYS._filter(
				lambda __DefaultAttributeItemTuple:
				__DefaultAttributeItemTuple[0].startswith(DoneStr),
				DoClass.DefaultAttributeItemTuplesList
				)
			)
			DoClass.DoingAttributeVariablesOrderedDict=collections.OrderedDict(
				SYS._filter(
				lambda __DefaultAttributeItemTuple:
				__DefaultAttributeItemTuple[0].startswith(DoingStr),
				DoClass.DefaultAttributeItemTuplesList
				)
			)

			#Definition
			DoWrapMethodStr=DoingWrapPrefixStr+DoMethodStr

			#Debug
			'''
			print('Doer l.401')
			print('DoClass.DoneAttributeVariablesOrderedDict is ',DoClass.DoneAttributeVariablesOrderedDict)
			print('DoClass.DoingAttributeVariablesOrderedDict is ',DoClass.DoingAttributeVariablesOrderedDict)
			print('DoWrapMethodStr is ',DoWrapMethodStr)
			print('')
			'''
			
			#Check 
			if hasattr(DoClass,DoWrapMethodStr):

				#Debug
				'''
				print('There is a DoWrapMethod here already')
				print('')
				'''

				#Get
				DoWrapMethod=getattr(
						DoClass,
						DoWrapMethodStr
					)
			else:

				#Debug
				'''
				print('There is no DoWrapMethod here')
				print('')
				'''

				#Definition of a default function
				DoWrapMethod=DefaultDoFunction


			#debug
			'''
			print('DoWrapMethod is '+str(DoWrapMethod))
			print('')
			'''

			#Link
			"""
			DoingMethodKeyStr='init'+DoClass.NameStr
			setattr(
					DoClass,
					DoingMethodKeyStr,
					initDo
				)
			"""

			#Definition of the ExecStr that will define the function
			DoDecorationMethodStr=DoingDecorationPrefixStr+DoingDecorationTagStr+DoingDecorationSuffixStr+DoMethodStr
			DoExecStr="def "+DoDecorationMethodStr+"(_InstanceVariable,"
			DoExecStr+=",".join(
				map(