# encoding: utf-8
"""
validation.py

Created by Thomas Mangin on 2013-03-18.
Copyright (c) 2009-2013 Exa Networks. All rights reserved.
"""

__all__ = ["validation", "ValidationError"]

FORMAT = 3
DEBUG = False

from collections import deque
from collections import OrderedDict

from exabgp.data import check

TYPE=check.TYPE
PRESENCE=check.PRESENCE

class ValidationError (Exception):
	internal_error = 'invalid configuration definition (internal error)'
	mandatory_error = 'missing mandatory configuration field'
	type_error = 'the data for this configuration option is not what was expected'
	configuration_error = 'the configuration is missing this information'
	conflicting_error = 'the configuration has conflicting information'

	def __init__ (self,location,message):
		self.location = location
		self.message = message

	def __str__ (self):
		location = ','.join(self.location) if self.location else 'root'
		return 'location ' + location + ' : ' + self.message

_attributes = OrderedDict((
	('next-hop', (TYPE.string, PRESENCE.optional, '', check.ipv4)),
	('origin' , (TYPE.string, PRESENCE.optional, '', ['igp','egp','incomplete'])),
	('as-path' , (TYPE.array, PRESENCE.optional, '', check.aspath)),
	('as-sequence' , (TYPE.array, PRESENCE.optional, '', check.assequence)),
	('local-preference', (TYPE.integer, PRESENCE.optional, '', check.localpreference)),
	('med', (TYPE.integer, PRESENCE.optional, '', check.med)),
	('aggregator' , (TYPE.string , PRESENCE.optional, '', check.ipv4)),
	('aggregator-id' , (TYPE.string , PRESENCE.optional, '', check.ipv4)),
	('atomic-aggregate' , (TYPE.boolean , PRESENCE.optional, '', check.nop)),
	('community' , (TYPE.array , PRESENCE.optional, '', check.community)),
	('extended-community' , (TYPE.array , PRESENCE.optional, '', check.extendedcommunity)),
	('aigp', (TYPE.integer, PRESENCE.optional, '', check.aigp)),
	('label' , (TYPE.array , PRESENCE.optional, '', check.label)),
	('cluster-list' , (TYPE.array , PRESENCE.optional, '', check.clusterlist)),
	('originator-id' , (TYPE.string , PRESENCE.optional, '', check.originator)),
	('path-information' , (TYPE.string|TYPE.integer , PRESENCE.optional, '', check.pathinformation)),
	('route-distinguisher' , (TYPE.string , PRESENCE.optional, '', check.distinguisher)),
	('split' , (TYPE.integer , PRESENCE.optional, '', check.split)),
	('watchdog' , (TYPE.string , PRESENCE.optional, '', check.watchdog)),
	('withdrawn' , (TYPE.boolean , PRESENCE.optional, '', check.nop)),
))

_definition = (TYPE.object, PRESENCE.mandatory, '', OrderedDict((
	('exabgp' , (TYPE.integer, PRESENCE.mandatory, '', [FORMAT,])),
	('neighbor' , (TYPE.object, PRESENCE.mandatory, '', OrderedDict((
		('<*>' , (TYPE.object, PRESENCE.mandatory, '', OrderedDict((
			('tcp' , (TYPE.object, PRESENCE.mandatory, '', OrderedDict((
				('bind' , (TYPE.string, PRESENCE.mandatory, '', check.ip)),
				('connect' , (TYPE.string, PRESENCE.mandatory, '', check.ip)),
				('ttl-security' , (TYPE.integer, PRESENCE.optional, '', check.uint8)),
				('md5' , (TYPE.string, PRESENCE.optional, '', check.md5)),
				('passive' , (TYPE.boolean, PRESENCE.optional, '', check.nop)),
			)))),
			('api' , (TYPE.object, PRESENCE.optional, 'api', OrderedDict((
				('<*>' , (TYPE.array, PRESENCE.mandatory, '', ['neighbor-changes','send-packets','receive-packets','receive-routes'])),
			)))),
			('session' , (TYPE.object, PRESENCE.mandatory, '', OrderedDict((
				('router-id' , (TYPE.string, PRESENCE.mandatory, '', check.ipv4)),
				('hold-time' , (TYPE.integer, PRESENCE.mandatory, '', check.uint16)),
				('asn' , (TYPE.object, PRESENCE.mandatory, '', OrderedDict((
					('local' , (TYPE.integer, PRESENCE.mandatory, '', check.uint32)),
					('peer' , (TYPE.integer, PRESENCE.mandatory, '', check.uint32)),
				)))),
				('feature' , (TYPE.object, PRESENCE.optional, '', OrderedDict((
					('updates' , (TYPE.object, PRESENCE.optional, '', OrderedDict((
						('group' , (TYPE.boolean, PRESENCE.optional, '', check.nop)),
						('flush' , (TYPE.boolean, PRESENCE.optional, '', check.nop)),
					)))),
					('rib' , (TYPE.object, PRESENCE.optional, '', OrderedDict((
						('adj-rib-out' , (TYPE.boolean, PRESENCE.optional, '', check.nop)),
					)))),
				)))),
				('capability' , (TYPE.object, PRESENCE.mandatory, '', OrderedDict((
					('family' , (TYPE.object, PRESENCE.mandatory, '', OrderedDict((
						('ipv4' , (TYPE.array, PRESENCE.optional, '', ['unicast','multicast','nlri-mpls','mpls-vpn','flow-vpn','flow'])),
						('ipv6' , (TYPE.array, PRESENCE.optional, '', ['unicast','flow'])),
						('alias' , (TYPE.string, PRESENCE.optional, '', ['all','minimal'])),
					)))),
					('asn4' , (TYPE.boolean, PRESENCE.optional, '', check.nop)),
					('route-refresh' , (TYPE.boolean, PRESENCE.optional, '', check.nop)),
					('graceful-restart' , (TYPE.boolean, PRESENCE.optional, '', check.nop)),
					('multi-session' , (TYPE.boolean, PRESENCE.optional, '', check.nop)),
					('add-path' , (TYPE.boolean, PRESENCE.optional, '', check.nop)),
					('aigp' , (TYPE.boolean, PRESENCE.optional, '', check.nop)),
				)))),
			)))),
			('announce' , (TYPE.array, PRESENCE.optional, ['update,prefix','update,flow'], check.string)),
		)))),
	)))),
	('api' , (TYPE.object, PRESENCE.optional, '', OrderedDict((
		('<*>' , (TYPE.object, PRESENCE.optional, '', OrderedDict((
			('encoder' , (TYPE.string, PRESENCE.optional, '', ['json','text'])),
			('program' , (TYPE.string, PRESENCE.mandatory, '', check.nop)),
		)))),
	)))),
	('attribute' , (TYPE.object, PRESENCE.optional, '', OrderedDict((