from __future__ import absolute_import
_F='serializer is not opened'
_E='serializer is closed'
_D='typ'
_C=False
_B=True
_A=None
from .error import YAMLError
from .compat import nprint,DBG_NODE,dbg,string_types,nprintf
from .util import RegExp
from .events import StreamStartEvent,StreamEndEvent,MappingStartEvent,MappingEndEvent,SequenceStartEvent,SequenceEndEvent,AliasEvent,ScalarEvent,DocumentStartEvent,DocumentEndEvent
from .nodes import MappingNode,ScalarNode,SequenceNode
if _C:from typing import Any,Dict,Union,Text,Optional;from .compat import VersionType
__all__=['Serializer','SerializerError']
class SerializerError(YAMLError):0
class Serializer:
	ANCHOR_TEMPLATE='id%03d';ANCHOR_RE=RegExp('id(?!000$)\\d{3,}')
	def __init__(A,encoding=_A,explicit_start=_A,explicit_end=_A,version=_A,tags=_A,dumper=_A):
		B=version;A.dumper=dumper
		if A.dumper is not _A:A.dumper._serializer=A
		A.use_encoding=encoding;A.use_explicit_start=explicit_start;A.use_explicit_end=explicit_end
		if isinstance(B,string_types):A.use_version=tuple(map(int,B.split('.')))
		else:A.use_version=B
		A.use_tags=tags;A.serialized_nodes={};A.anchors={};A.last_anchor_id=0;A.closed=_A;A._templated_id=_A
	@property
	def emitter(self):
		A=self
		if hasattr(A.dumper,_D):return A.dumper.emitter
		return A.dumper._emitter
	@property
	def resolver(self):
		A=self
		if hasattr(A.dumper,_D):A.dumper.resolver
		return A.dumper._resolver
	def open(A):
		if A.closed is _A:A.emitter.emit(StreamStartEvent(encoding=A.use_encoding));A.closed=_C
		elif A.closed:raise SerializerError(_E)
		else:raise SerializerError('serializer is already opened')
	def close(A):
		if A.closed is _A:raise SerializerError(_F)
		elif not A.closed:A.emitter.emit(StreamEndEvent());A.closed=_B
	def serialize(A,node):
		B=node
		if dbg(DBG_NODE):nprint('Serializing nodes');B.dump()
		if A.closed is _A:raise SerializerError(_F)
		elif A.closed:raise SerializerError(_E)
		A.emitter.emit(DocumentStartEvent(explicit=A.use_explicit_start,version=A.use_version,tags=A.use_tags));A.anchor_node(B);A.serialize_node(B,_A,_A);A.emitter.emit(DocumentEndEvent(explicit=A.use_explicit_end));A.serialized_nodes={};A.anchors={};A.last_anchor_id=0
	def anchor_node(B,node):
		A=node
		if A in B.anchors:
			if B.anchors[A]is _A:B.anchors[A]=B.generate_anchor(A)
		else:
			C=_A
			try:
				if A.anchor.always_dump:C=A.anchor.value
			except:pass
			B.anchors[A]=C
			if isinstance(A,SequenceNode):
				for D in A.value:B.anchor_node(D)
			elif isinstance(A,MappingNode):
				for (E,F) in A.value:B.anchor_node(E);B.anchor_node(F)
	def generate_anchor(A,node):
		try:B=node.anchor.value
		except:B=_A
		if B is _A:A.last_anchor_id+=1;return A.ANCHOR_TEMPLATE%A.last_anchor_id
		return B
	def serialize_node(B,node,parent,index):
		F=index;A=node;G=B.anchors[A]
		if A in B.serialized_nodes:B.emitter.emit(AliasEvent(G))
		else:
			B.serialized_nodes[A]=_B;B.resolver.descend_resolver(parent,F)
			if isinstance(A,ScalarNode):K=B.resolver.resolve(ScalarNode,A.value,(_B,_C));L=B.resolver.resolve(ScalarNode,A.value,(_C,_B));E=A.tag==K,A.tag==L,A.tag.startswith('tag:yaml.org,2002:');B.emitter.emit(ScalarEvent(G,A.tag,E,A.value,style=A.style,comment=A.comment))
			elif isinstance(A,SequenceNode):
				E=A.tag==B.resolver.resolve(SequenceNode,A.value,_B);C=A.comment;D=_A;H=_A
				if A.flow_style is _B:
					if C:H=C[0]
				if C and len(C)>2:D=C[2]
				else:D=_A
				B.emitter.emit(SequenceStartEvent(G,A.tag,E,flow_style=A.flow_style,comment=A.comment));F=0
				for M in A.value:B.serialize_node(M,A,F);F+=1
				B.emitter.emit(SequenceEndEvent(comment=[H,D]))
			elif isinstance(A,MappingNode):
				E=A.tag==B.resolver.resolve(MappingNode,A.value,_B);C=A.comment;D=_A;I=_A
				if A.flow_style is _B:
					if C:I=C[0]
				if C and len(C)>2:D=C[2]
				B.emitter.emit(MappingStartEvent(G,A.tag,E,flow_style=A.flow_style,comment=A.comment,nr_items=len(A.value)))
				for (J,N) in A.value:B.serialize_node(J,A,_A);B.serialize_node(N,A,J)
				B.emitter.emit(MappingEndEvent(comment=[I,D]))
			B.resolver.ascend_resolver()
def templated_id(s):return Serializer.ANCHOR_RE.match(s)