from __future__ import absolute_import
import ruamel.yaml
from ruamel.yaml.comments import CommentedBase, CommentedMap, CommentedSeq
import re
import os
import traceback

from typing import (Any, AnyStr, Callable, cast, Dict, List, Iterable, Tuple,
                    TypeVar, Union, Text)
import six

lineno_re = re.compile(u"^(.*?:[0-9]+:[0-9]+: )(( *)(.*))")

def _add_lc_filename(r, source):  # type: (ruamel.yaml.comments.CommentedBase, AnyStr) -> None
    if isinstance(r, ruamel.yaml.comments.CommentedBase):
        r.lc.filename = source
    if isinstance(r, list):
        for d in r:
            _add_lc_filename(d, source)
    elif isinstance(r, dict):
        for d in six.itervalues(r):
            _add_lc_filename(d, source)

def relname(source):  # type: (Text) -> Text
    if source.startswith("file://"):
        source = source[7:]
        source = os.path.relpath(source)
    return source

def add_lc_filename(r, source):  # type: (ruamel.yaml.comments.CommentedBase, Text) -> None
    _add_lc_filename(r, relname(source))

def reflow(text, maxline, shift=""):  # type: (Text, int, Text) -> Text
    if maxline < 20:
        maxline = 20
    if len(text) > maxline:
        sp = text.rfind(' ', 0, maxline)
        if sp < 1:
            sp = text.find(' ', sp+1)
            if sp == -1:
                sp = len(text)
        if sp < len(text):
            return "%s\n%s%s" % (text[0:sp], shift, reflow(text[sp+1:], maxline, shift))
    return text

def indent(v, nolead=False, shift=u"  ", bullet=u"  "):  # type: (Text, bool, Text, Text) -> Text
    if nolead:
        return v.splitlines()[0] + u"\n".join([shift + l for l in v.splitlines()[1:]])
    else:
        def lineno(i, l):  # type: (int, Text) -> Text
            r = lineno_re.match(l)
            if bool(r):
                return r.group(1) + (bullet if i == 0 else shift) + r.group(2)
            else:
                return (bullet if i == 0 else shift) + l

        return u"\n".join([lineno(i, l) for i, l in enumerate(v.splitlines())])

def bullets(textlist, bul):  # type: (List[Text], Text) -> Text
    if len(textlist) == 1:
        return textlist[0]
    else:
        return "\n".join(indent(t, bullet=bul) for t in textlist)

def strip_dup_lineno(text, maxline=None):  # type: (Text, int) -> Text
    if maxline is None:
        maxline = int(os.environ.get("COLUMNS", "100"))
    pre = None
    msg = []
    for l in text.splitlines():
        g = lineno_re.match(l)
        if not g:
            msg.append(l)
            continue
        shift = len(g.group(1)) + len(g.group(3))
        g2 = reflow(g.group(2), maxline-shift, " " * shift)
        if g.group(1) != pre:
            pre = g.group(1)
            msg.append(pre + g2)
        else:
            g2 = reflow(g.group(2), maxline-len(g.group(1)), " " * (len(g.group(1))+len(g.group(3))))
            msg.append(" " * len(g.group(1)) + g2)
    return "\n".join(msg)

def cmap(d, lc=None, fn=None):  # type: (Union[int, float, str, Text, Dict, List], List[int], Text) -> Union[int, float, str, Text, CommentedMap, CommentedSeq]
    if lc is None:
        lc = [0, 0, 0, 0]
    if fn is None:
        fn = "test"

    if isinstance(d, CommentedMap):
        fn = d.lc.filename if hasattr(d.lc, "filename") else fn
        for k,v in six.iteritems(d):
            if k in d.lc.data:
                d[k] = cmap(v, lc=d.lc.data[k], fn=fn)
            else:
                d[k] = cmap(v, lc, fn=fn)
        return d
    if isinstance(d, CommentedSeq):
        fn = d.lc.filename if hasattr(d.lc, "filename") else fn
        for k,v in enumerate(d):
            if k in d.lc.data:
                d[k] = cmap(v, lc=d.lc.data[k], fn=fn)
            else:
                d[k] = cmap(v, lc, fn=fn)
        return d
    if isinstance(d, dict):
        cm = CommentedMap()
        for k in sorted(d.keys()):
            v = d[k]
            if isinstance(v, CommentedBase):
                uselc = [v.lc.line, v.lc.col, v.lc.line, v.lc.col]
                vfn = v.lc.filename if hasattr(v.lc, "filename") else fn
            else:
                uselc = lc
                vfn = fn
            cm[k] = cmap(v, lc=uselc, fn=vfn)
            cm.lc.add_kv_line_col(k, uselc)
            cm.lc.filename = fn
        return cm
    if isinstance(d, list):
        cs = CommentedSeq()
        for k,v in enumerate(d):
            if isinstance(v, CommentedBase):
                uselc = [v.lc.line, v.lc.col, v.lc.line, v.lc.col]
                vfn = v.lc.filename if hasattr(v.lc, "filename") else fn
            else:
                uselc = lc
                vfn = fn
            cs.append(cmap(v, lc=uselc, fn=vfn))
            cs.lc.add_kv_line_col(k, uselc)
            cs.lc.filename = fn
        return cs
    else:
        return d

class SourceLine(object):
    def __init__(self, item, key=None, raise_type=six.text_type, include_traceback=False):  # type: (Any, Any, Callable, bool) -> None
        self.item = item
        self.key = key
        self.raise_type = raise_type
        self.include_traceback = include_traceback

    def __enter__(self):  # type: () -> SourceLine
        return self

    def __exit__(self,
                 exc_type,   # type: Any
                 exc_value,  # type: Any
                 tb   # type: Any
                 ):   # -> Any
        if not exc_value:
            return
        if self.include_traceback:
            raise self.makeError("\n".join(traceback.format_exception(exc_type, exc_value, tb)))
        else:
            raise self.makeError(six.text_type(exc_value))

    def makeLead(self):  # type: () -> Text
        if self.key is None or self.item.lc.data is None or self.key not in self.item.lc.data:
            return "%s:%i:%i:" % (self.item.lc.filename if hasattr(self.item.lc, "filename") else "",
                                  (self.item.lc.line or 0)+1,
                                  (self.item.lc.col or 0)+1)
        else:
            return "%s:%i:%i:" % (self.item.lc.filename if hasattr(self.item.lc, "filename") else "",
                                  (self.item.lc.data[self.key][0] or 0)+1,
                                  (self.item.lc.data[self.key][1] or 0)+1)

    def makeError(self, msg):  # type: (Text) -> Any
        if not isinstance(self.item, ruamel.yaml.comments.CommentedBase):
            return self.raise_type(msg)
        errs = []
        lead = self.makeLead()
        for m in msg.splitlines():
            if bool(lineno_re.match(m)):
                errs.append(m)
            else:
                errs.append("%s %s" % (lead, m))
        return self.raise_type("\n".join(errs))

from types import NoneType
from six.moves import urllib
import ruamel.yaml as yaml
from StringIO import StringIO
import copy

class ValidationException(Exception):
    pass

class Savable(object):
    pass

class LoadingOptions(object):
    def __init__(self, fetcher=None, namespaces=None, fileuri=None, copyfrom=None):
        if copyfrom is not None:
            self.idx = copyfrom.idx
            if fetcher is None:
                fetcher = copyfrom.fetcher
            if fileuri is None:
                fileuri = copyfrom.fileuri
        else:
            self.idx = {}

        if fetcher is None:
            import os
            import requests
            from cachecontrol.wrapper import CacheControl
            from cachecontrol.caches import FileCache
            from schema_salad.ref_resolver import DefaultFetcher
            if "HOME" in os.environ:
                session = CacheControl(
                    requests.Session(),
                    cache=FileCache(os.path.join(os.environ["HOME"], ".cache", "salad")))
            elif "TMP" in os.environ:
                session = CacheControl(
                    requests.Session(),
                    cache=FileCache(os.path.join(os.environ["TMP"], ".cache", "salad")))
            else:
                session = CacheControl(
                    requests.Session(),
                    cache=FileCache("/tmp", ".cache", "salad"))
            self.fetcher = DefaultFetcher({}, session)
        else:
            self.fetcher = fetcher

        self.fileuri = fileuri

        self.vocab = _vocab
        self.rvocab = _rvocab

        if namespaces is not None:
            self.vocab = self.vocab.copy()
            self.rvocab = self.rvocab.copy()
            for k,v in namespaces.iteritems():
                self.vocab[k] = v
                self.rvocab[v] = k

def load_field(val, fieldtype, baseuri, loadingOptions):
    if isinstance(val, dict):
        if "$import" in val:
            return _document_load_by_url(fieldtype, loadingOptions.fetcher.urljoin(loadingOptions.fileuri, val["$import"]), loadingOptions)
        elif "$include" in val:
            val = loadingOptions.fetcher.fetch_text(loadingOptions.fetcher.urljoin(loadingOptions.fileuri, val["$include"]))
    return fieldtype.load(val, baseuri, loadingOptions)


def save(val):
   if isinstance(val, Savable):
       return val.save()
   if isinstance(val, list):
       return [save(v) for v in val]
   return val

def expand_url(url,                 # type: Text
               base_url,            # type: Text
               loadingOptions,
               scoped_id=False,     # type: bool
               vocab_term=False,    # type: bool
               scoped_ref=None      # type: int
               ):
    # type: (...) -> Text
    if url in (u"@id", u"@type"):
        return url

    if vocab_term and url in loadingOptions.vocab:
        return url

    if bool(loadingOptions.vocab) and u":" in url:
        prefix = url.split(u":")[0]
        if prefix in loadingOptions.vocab:
            url = loadingOptions.vocab[prefix] + url[len(prefix) + 1:]

    split = urllib.parse.urlsplit(url)

    if ((bool(split.scheme) and split.scheme in [u'http', u'https', u'file']) or url.startswith(u"$(")
        or url.startswith(u"${")):
        pass
    elif scoped_id and not bool(split.fragment):
        splitbase = urllib.parse.urlsplit(base_url)
        frg = u""
        if bool(splitbase.fragment):
            frg = splitbase.fragment + u"/" + split.path
        else:
            frg = split.path
        pt = splitbase.path if splitbase.path != '' else "/"
        url = urllib.parse.urlunsplit(
            (splitbase.scheme, splitbase.netloc, pt, splitbase.query, frg))
    elif scoped_ref is not None and not split.fragment:
        pass
    else:
        url = loadingOptions.fetcher.urljoin(base_url, url)

    if vocab_term:
        if bool(split.scheme):
            if url in loadingOptions.rvocab:
                return loadingOptions.rvocab[url]
        else:
            raise ValidationException("Term '%s' not in vocabulary" % url)
    return url


class _Loader(object):
    def load(self, doc, baseuri, loadingOptions, docRoot=None):
        pass

class _PrimitiveLoader(_Loader):
    def __init__(self, tp):
        self.tp = tp

    def load(self, doc, baseuri, loadingOptions, docRoot=None):
        if not isinstance(doc, self.tp):
            raise ValidationException("Expected a %s but got %s" % (self.tp, type(doc)))
        return doc

    def __repr__(self):
        return str(self.tp)

class _ArrayLoader(_Loader):
    def __init__(self, items):
        self.items = items

    def load(self, doc, baseuri, loadingOptions, docRoot=None):
        if not isinstance(doc, list):
            raise ValidationException("Expected a list")
        r = []
        errors = []
        for i in xrange(0, len(doc)):
            try:
                lf = load_field(doc[i], _UnionLoader((self, self.items)), baseuri, loadingOptions)
                if isinstance(lf, list):
                    r.extend(lf)
                else:
                    r.append(lf)
            except ValidationException as e:
                errors.append(SourceLine(doc, i, str).makeError(six.text_type(e)))
        if errors:
            raise ValidationException("\n".join(errors))
        return r

    def __repr__(self):
        return "array<%s>" % self.items

class _EnumLoader(_Loader):
    def __init__(self, symbols):
        self.symbols = symbols

    def load(self, doc, baseuri, loadingOptions, docRoot=None):
        if doc in self.symbols:
            return doc
        else:
            raise ValidationException("Expected one of %s" % (self.symbols,))


class _RecordLoader(_Loader):
    def __init__(self, classtype):
        self.classtype = classtype

    def load(self, doc, baseuri, loadingOptions, docRoot=None):
        if not isinstance(doc, dict):
            raise ValidationException("Expected a dict")
        return self.classtype(doc, baseuri, loadingOptions, docRoot=docRoot)

    def __repr__(self):
        return str(self.classtype)


class _UnionLoader(_Loader):
    def __init__(self, alternates):
        self.alternates = alternates

    def load(self, doc, baseuri, loadingOptions, docRoot=None):
        errors = []
        for t in self.alternates:
            try:
                return t.load(doc, baseuri, loadingOptions, docRoot=docRoot)
            except ValidationException as e:
                errors.append("tried %s but\n%s" % (t, indent(str(e))))
        raise ValidationException(bullets(errors, "- "))

    def __repr__(self):
        return " | ".join(str(a) for a in self.alternates)

class _URILoader(_Loader):
    def __init__(self, inner, scoped_id, vocab_term, scoped_ref):
        self.inner = inner
        self.scoped_id = scoped_id
        self.vocab_term = vocab_term
        self.scoped_ref = scoped_ref

    def load(self, doc, baseuri, loadingOptions, docRoot=None):
        if isinstance(doc, list):
            return [self.load(i, baseuri, loadingOptions) for i in doc]
        if isinstance(doc, basestring):
            return expand_url(doc, baseuri, loadingOptions,
                              self.scoped_id, self.vocab_term, self.scoped_ref)
        return self.inner.load(doc, baseuri, loadingOptions)


class _TypeDSLLoader(_Loader):
    def __init__(self, inner):
        self.inner = inner

    def load(self, doc, baseuri, loadingOptions, docRoot=None):
        return self.inner.load(doc, baseuri, loadingOptions)


class _IdMapLoader(_Loader):
    def __init__(self, inner, mapSubject, mapPredicate):
        self.inner = inner
        self.mapSubject = mapSubject
        self.mapPredicate = mapPredicate

    def load(self, doc, baseuri, loadingOptions, docRoot=None):
        if isinstance(doc, dict):
            r = []
            for k in sorted(doc.keys()):
                val = doc[k]
                if isinstance(val, dict):
                    v = copy.copy(val)
                    if hasattr(val, 'lc'):
                        v.lc.data = val.lc.data
                        v.lc.filename = val.lc.filename
                else:
                    if self.mapPredicate:
                        v = {self.mapPredicate: val}
                    else:
                        raise ValidationException("No mapPredicate")
                v[self.mapSubject] = k
                r.append(v)
            doc = r
        return self.inner.load(doc, baseuri, loadingOptions)


def _document_load(loader, doc, baseuri, loadingOptions):
    if isinstance(doc, basestring):
        return _document_load_by_url(loader, doc, loadingOptions)

    if isinstance(doc, dict):
        if "$namespaces" in doc:
            loadingOptions = LoadingOptions(copyfrom=loadingOptions, namespaces=doc["$namespaces"])

        if "$base" in doc:
            baseuri = doc["$base"]

        if "$graph" in doc:
            return loader.load(doc["$graph"], baseuri, loadingOptions)
        else:
            return loader.load(doc, baseuri, loadingOptions, docRoot=baseuri)

    if isinstance(doc, list):
        return loader.load(doc, baseuri, loadingOptions)

    raise ValidationException()


def _document_load_by_url(loader, url, loadingOptions):
    if url in loadingOptions.idx:
        return _document_load(loader, loadingOptions.idx[url], url, loadingOptions)

    text = loadingOptions.fetcher.fetch_text(url)
    if isinstance(text, bytes):
        textIO = StringIO(text.decode('utf-8'))
    else:
        textIO = StringIO(text)
    textIO.name = url    # type: ignore
    result = yaml.round_trip_load(textIO)
    add_lc_filename(result, url)

    loadingOptions.idx[url] = result

    loadingOptions = LoadingOptions(copyfrom=loadingOptions, fileuri=url)

    return _document_load(loader, result, url, loadingOptions)

class RecordField(Savable):
    """
A field of a record.
    """
    def __init__(self, _doc, baseuri, loadingOptions, docRoot=None):
           doc = copy.copy(_doc)
           if hasattr(_doc, 'lc'):
               doc.lc.data = _doc.lc.data
               doc.lc.filename = _doc.lc.filename
           errors = []
           #doc = {expand_url(d, u"", loadingOptions, scoped_id=False, vocab_term=True): v for d,v in doc.items()}
           if 'name' in doc:
               try:
                   self.name = load_field(doc.get('name'), uri_strtype_True_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'name', str).makeError("the `name` field is not valid because:\n"+str(e)))
           else:
               self.name = None


           if self.name is None:
               if docRoot is not None:
                   self.name = docRoot
               else:
                   raise ValidationException("Missing name")
           baseuri = self.name
           if 'doc' in doc:
               try:
                   self.doc = load_field(doc.get('doc'), union_of_None_type_or_strtype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'doc', str).makeError("the `doc` field is not valid because:\n"+str(e)))
           else:
               self.doc = None

           try:
               self.type = load_field(doc.get('type'), typedsl_uri_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_False_True_2, baseuri, loadingOptions)
           except ValidationException as e:
               errors.append(SourceLine(doc, 'type', str).makeError("the `type` field is not valid because:\n"+str(e)))


           if errors:
               raise ValidationException("Trying 'RecordField'\n"+"\n".join(errors))

    def save(self):
        r = {}
        if self.name is not None:
            r['name'] = save(self.name)
        if self.doc is not None:
            r['doc'] = save(self.doc)
        if self.type is not None:
            r['type'] = save(self.type)
        return r


class RecordSchema(Savable):
    def __init__(self, _doc, baseuri, loadingOptions, docRoot=None):
           doc = copy.copy(_doc)
           if hasattr(_doc, 'lc'):
               doc.lc.data = _doc.lc.data
               doc.lc.filename = _doc.lc.filename
           errors = []
           #doc = {expand_url(d, u"", loadingOptions, scoped_id=False, vocab_term=True): v for d,v in doc.items()}
           if 'fields' in doc:
               try:
                   self.fields = load_field(doc.get('fields'), idmap_fields_union_of_None_type_or_array_of_RecordFieldLoader, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'fields', str).makeError("the `fields` field is not valid because:\n"+str(e)))
           else:
               self.fields = None

           try:
               self.type = load_field(doc.get('type'), typedsl_uri_Record_symbolLoader_False_True_2, baseuri, loadingOptions)
           except ValidationException as e:
               errors.append(SourceLine(doc, 'type', str).makeError("the `type` field is not valid because:\n"+str(e)))


           if errors:
               raise ValidationException("Trying 'RecordSchema'\n"+"\n".join(errors))

    def save(self):
        r = {}
        if self.fields is not None:
            r['fields'] = save(self.fields)
        if self.type is not None:
            r['type'] = save(self.type)
        return r


class EnumSchema(Savable):
    """
Define an enumerated type.

    """
    def __init__(self, _doc, baseuri, loadingOptions, docRoot=None):
           doc = copy.copy(_doc)
           if hasattr(_doc, 'lc'):
               doc.lc.data = _doc.lc.data
               doc.lc.filename = _doc.lc.filename
           errors = []
           #doc = {expand_url(d, u"", loadingOptions, scoped_id=False, vocab_term=True): v for d,v in doc.items()}
           try:
               self.symbols = load_field(doc.get('symbols'), uri_array_of_strtype_False_False_None, baseuri, loadingOptions)
           except ValidationException as e:
               errors.append(SourceLine(doc, 'symbols', str).makeError("the `symbols` field is not valid because:\n"+str(e)))

           try:
               self.type = load_field(doc.get('type'), typedsl_uri_Enum_symbolLoader_False_True_2, baseuri, loadingOptions)
           except ValidationException as e:
               errors.append(SourceLine(doc, 'type', str).makeError("the `type` field is not valid because:\n"+str(e)))


           if errors:
               raise ValidationException("Trying 'EnumSchema'\n"+"\n".join(errors))

    def save(self):
        r = {}
        if self.symbols is not None:
            r['symbols'] = save(self.symbols)
        if self.type is not None:
            r['type'] = save(self.type)
        return r


class ArraySchema(Savable):
    def __init__(self, _doc, baseuri, loadingOptions, docRoot=None):
           doc = copy.copy(_doc)
           if hasattr(_doc, 'lc'):
               doc.lc.data = _doc.lc.data
               doc.lc.filename = _doc.lc.filename
           errors = []
           #doc = {expand_url(d, u"", loadingOptions, scoped_id=False, vocab_term=True): v for d,v in doc.items()}
           try:
               self.items = load_field(doc.get('items'), uri_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_False_True_2, baseuri, loadingOptions)
           except ValidationException as e:
               errors.append(SourceLine(doc, 'items', str).makeError("the `items` field is not valid because:\n"+str(e)))

           try:
               self.type = load_field(doc.get('type'), typedsl_uri_Array_symbolLoader_False_True_2, baseuri, loadingOptions)
           except ValidationException as e:
               errors.append(SourceLine(doc, 'type', str).makeError("the `type` field is not valid because:\n"+str(e)))


           if errors:
               raise ValidationException("Trying 'ArraySchema'\n"+"\n".join(errors))

    def save(self):
        r = {}
        if self.items is not None:
            r['items'] = save(self.items)
        if self.type is not None:
            r['type'] = save(self.type)
        return r


class JsonldPredicate(Savable):
    """
Attached to a record field to define how the parent record field is handled for
URI resolution and JSON-LD context generation.

    """
    def __init__(self, _doc, baseuri, loadingOptions, docRoot=None):
           doc = copy.copy(_doc)
           if hasattr(_doc, 'lc'):
               doc.lc.data = _doc.lc.data
               doc.lc.filename = _doc.lc.filename
           errors = []
           #doc = {expand_url(d, u"", loadingOptions, scoped_id=False, vocab_term=True): v for d,v in doc.items()}
           if '_id' in doc:
               try:
                   self._id = load_field(doc.get('_id'), uri_union_of_None_type_or_strtype_False_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, '_id', str).makeError("the `_id` field is not valid because:\n"+str(e)))
           else:
               self._id = None

           if '_type' in doc:
               try:
                   self._type = load_field(doc.get('_type'), union_of_None_type_or_strtype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, '_type', str).makeError("the `_type` field is not valid because:\n"+str(e)))
           else:
               self._type = None

           if '_container' in doc:
               try:
                   self._container = load_field(doc.get('_container'), union_of_None_type_or_strtype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, '_container', str).makeError("the `_container` field is not valid because:\n"+str(e)))
           else:
               self._container = None

           if 'identity' in doc:
               try:
                   self.identity = load_field(doc.get('identity'), union_of_None_type_or_booltype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'identity', str).makeError("the `identity` field is not valid because:\n"+str(e)))
           else:
               self.identity = None

           if 'noLinkCheck' in doc:
               try:
                   self.noLinkCheck = load_field(doc.get('noLinkCheck'), union_of_None_type_or_booltype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'noLinkCheck', str).makeError("the `noLinkCheck` field is not valid because:\n"+str(e)))
           else:
               self.noLinkCheck = None

           if 'mapSubject' in doc:
               try:
                   self.mapSubject = load_field(doc.get('mapSubject'), union_of_None_type_or_strtype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'mapSubject', str).makeError("the `mapSubject` field is not valid because:\n"+str(e)))
           else:
               self.mapSubject = None

           if 'mapPredicate' in doc:
               try:
                   self.mapPredicate = load_field(doc.get('mapPredicate'), union_of_None_type_or_strtype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'mapPredicate', str).makeError("the `mapPredicate` field is not valid because:\n"+str(e)))
           else:
               self.mapPredicate = None

           if 'refScope' in doc:
               try:
                   self.refScope = load_field(doc.get('refScope'), union_of_None_type_or_inttype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'refScope', str).makeError("the `refScope` field is not valid because:\n"+str(e)))
           else:
               self.refScope = None

           if 'typeDSL' in doc:
               try:
                   self.typeDSL = load_field(doc.get('typeDSL'), union_of_None_type_or_booltype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'typeDSL', str).makeError("the `typeDSL` field is not valid because:\n"+str(e)))
           else:
               self.typeDSL = None


           if errors:
               raise ValidationException("Trying 'JsonldPredicate'\n"+"\n".join(errors))

    def save(self):
        r = {}
        if self._id is not None:
            r['_id'] = save(self._id)
        if self._type is not None:
            r['_type'] = save(self._type)
        if self._container is not None:
            r['_container'] = save(self._container)
        if self.identity is not None:
            r['identity'] = save(self.identity)
        if self.noLinkCheck is not None:
            r['noLinkCheck'] = save(self.noLinkCheck)
        if self.mapSubject is not None:
            r['mapSubject'] = save(self.mapSubject)
        if self.mapPredicate is not None:
            r['mapPredicate'] = save(self.mapPredicate)
        if self.refScope is not None:
            r['refScope'] = save(self.refScope)
        if self.typeDSL is not None:
            r['typeDSL'] = save(self.typeDSL)
        return r


class SpecializeDef(Savable):
    def __init__(self, _doc, baseuri, loadingOptions, docRoot=None):
           doc = copy.copy(_doc)
           if hasattr(_doc, 'lc'):
               doc.lc.data = _doc.lc.data
               doc.lc.filename = _doc.lc.filename
           errors = []
           #doc = {expand_url(d, u"", loadingOptions, scoped_id=False, vocab_term=True): v for d,v in doc.items()}
           try:
               self.specializeFrom = load_field(doc.get('specializeFrom'), uri_strtype_False_False_1, baseuri, loadingOptions)
           except ValidationException as e:
               errors.append(SourceLine(doc, 'specializeFrom', str).makeError("the `specializeFrom` field is not valid because:\n"+str(e)))

           try:
               self.specializeTo = load_field(doc.get('specializeTo'), uri_strtype_False_False_1, baseuri, loadingOptions)
           except ValidationException as e:
               errors.append(SourceLine(doc, 'specializeTo', str).makeError("the `specializeTo` field is not valid because:\n"+str(e)))


           if errors:
               raise ValidationException("Trying 'SpecializeDef'\n"+"\n".join(errors))

    def save(self):
        r = {}
        if self.specializeFrom is not None:
            r['specializeFrom'] = save(self.specializeFrom)
        if self.specializeTo is not None:
            r['specializeTo'] = save(self.specializeTo)
        return r


class NamedType(Savable):
    def __init__(self, _doc, baseuri, loadingOptions, docRoot=None):
           doc = copy.copy(_doc)
           if hasattr(_doc, 'lc'):
               doc.lc.data = _doc.lc.data
               doc.lc.filename = _doc.lc.filename
           errors = []
           #doc = {expand_url(d, u"", loadingOptions, scoped_id=False, vocab_term=True): v for d,v in doc.items()}
           if 'name' in doc:
               try:
                   self.name = load_field(doc.get('name'), uri_strtype_True_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'name', str).makeError("the `name` field is not valid because:\n"+str(e)))
           else:
               self.name = None


           if self.name is None:
               if docRoot is not None:
                   self.name = docRoot
               else:
                   raise ValidationException("Missing name")
           baseuri = self.name
           if 'inVocab' in doc:
               try:
                   self.inVocab = load_field(doc.get('inVocab'), union_of_None_type_or_booltype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'inVocab', str).makeError("the `inVocab` field is not valid because:\n"+str(e)))
           else:
               self.inVocab = None


           if errors:
               raise ValidationException("Trying 'NamedType'\n"+"\n".join(errors))

    def save(self):
        r = {}
        if self.name is not None:
            r['name'] = save(self.name)
        if self.inVocab is not None:
            r['inVocab'] = save(self.inVocab)
        return r


class DocType(Savable):
    def __init__(self, _doc, baseuri, loadingOptions, docRoot=None):
           doc = copy.copy(_doc)
           if hasattr(_doc, 'lc'):
               doc.lc.data = _doc.lc.data
               doc.lc.filename = _doc.lc.filename
           errors = []
           #doc = {expand_url(d, u"", loadingOptions, scoped_id=False, vocab_term=True): v for d,v in doc.items()}
           if 'doc' in doc:
               try:
                   self.doc = load_field(doc.get('doc'), union_of_None_type_or_strtype_or_array_of_strtype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'doc', str).makeError("the `doc` field is not valid because:\n"+str(e)))
           else:
               self.doc = None

           if 'docParent' in doc:
               try:
                   self.docParent = load_field(doc.get('docParent'), uri_union_of_None_type_or_strtype_False_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'docParent', str).makeError("the `docParent` field is not valid because:\n"+str(e)))
           else:
               self.docParent = None

           if 'docChild' in doc:
               try:
                   self.docChild = load_field(doc.get('docChild'), uri_union_of_None_type_or_strtype_or_array_of_strtype_False_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'docChild', str).makeError("the `docChild` field is not valid because:\n"+str(e)))
           else:
               self.docChild = None

           if 'docAfter' in doc:
               try:
                   self.docAfter = load_field(doc.get('docAfter'), uri_union_of_None_type_or_strtype_False_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'docAfter', str).makeError("the `docAfter` field is not valid because:\n"+str(e)))
           else:
               self.docAfter = None


           if errors:
               raise ValidationException("Trying 'DocType'\n"+"\n".join(errors))

    def save(self):
        r = {}
        if self.doc is not None:
            r['doc'] = save(self.doc)
        if self.docParent is not None:
            r['docParent'] = save(self.docParent)
        if self.docChild is not None:
            r['docChild'] = save(self.docChild)
        if self.docAfter is not None:
            r['docAfter'] = save(self.docAfter)
        return r


class SchemaDefinedType(DocType):
    """
Abstract base for schema-defined types.

    """
    def __init__(self, _doc, baseuri, loadingOptions, docRoot=None):
           doc = copy.copy(_doc)
           if hasattr(_doc, 'lc'):
               doc.lc.data = _doc.lc.data
               doc.lc.filename = _doc.lc.filename
           errors = []
           #doc = {expand_url(d, u"", loadingOptions, scoped_id=False, vocab_term=True): v for d,v in doc.items()}
           if 'doc' in doc:
               try:
                   self.doc = load_field(doc.get('doc'), union_of_None_type_or_strtype_or_array_of_strtype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'doc', str).makeError("the `doc` field is not valid because:\n"+str(e)))
           else:
               self.doc = None

           if 'docParent' in doc:
               try:
                   self.docParent = load_field(doc.get('docParent'), uri_union_of_None_type_or_strtype_False_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'docParent', str).makeError("the `docParent` field is not valid because:\n"+str(e)))
           else:
               self.docParent = None

           if 'docChild' in doc:
               try:
                   self.docChild = load_field(doc.get('docChild'), uri_union_of_None_type_or_strtype_or_array_of_strtype_False_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'docChild', str).makeError("the `docChild` field is not valid because:\n"+str(e)))
           else:
               self.docChild = None

           if 'docAfter' in doc:
               try:
                   self.docAfter = load_field(doc.get('docAfter'), uri_union_of_None_type_or_strtype_False_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'docAfter', str).makeError("the `docAfter` field is not valid because:\n"+str(e)))
           else:
               self.docAfter = None

           if 'jsonldPredicate' in doc:
               try:
                   self.jsonldPredicate = load_field(doc.get('jsonldPredicate'), union_of_None_type_or_strtype_or_JsonldPredicateLoader, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'jsonldPredicate', str).makeError("the `jsonldPredicate` field is not valid because:\n"+str(e)))
           else:
               self.jsonldPredicate = None

           if 'documentRoot' in doc:
               try:
                   self.documentRoot = load_field(doc.get('documentRoot'), union_of_None_type_or_booltype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'documentRoot', str).makeError("the `documentRoot` field is not valid because:\n"+str(e)))
           else:
               self.documentRoot = None


           if errors:
               raise ValidationException("Trying 'SchemaDefinedType'\n"+"\n".join(errors))

    def save(self):
        r = {}
        if self.doc is not None:
            r['doc'] = save(self.doc)
        if self.docParent is not None:
            r['docParent'] = save(self.docParent)
        if self.docChild is not None:
            r['docChild'] = save(self.docChild)
        if self.docAfter is not None:
            r['docAfter'] = save(self.docAfter)
        if self.jsonldPredicate is not None:
            r['jsonldPredicate'] = save(self.jsonldPredicate)
        if self.documentRoot is not None:
            r['documentRoot'] = save(self.documentRoot)
        return r


class SaladRecordField(RecordField):
    """
A field of a record.
    """
    def __init__(self, _doc, baseuri, loadingOptions, docRoot=None):
           doc = copy.copy(_doc)
           if hasattr(_doc, 'lc'):
               doc.lc.data = _doc.lc.data
               doc.lc.filename = _doc.lc.filename
           errors = []
           #doc = {expand_url(d, u"", loadingOptions, scoped_id=False, vocab_term=True): v for d,v in doc.items()}
           if 'name' in doc:
               try:
                   self.name = load_field(doc.get('name'), uri_strtype_True_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'name', str).makeError("the `name` field is not valid because:\n"+str(e)))
           else:
               self.name = None


           if self.name is None:
               if docRoot is not None:
                   self.name = docRoot
               else:
                   raise ValidationException("Missing name")
           baseuri = self.name
           if 'doc' in doc:
               try:
                   self.doc = load_field(doc.get('doc'), union_of_None_type_or_strtype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'doc', str).makeError("the `doc` field is not valid because:\n"+str(e)))
           else:
               self.doc = None

           try:
               self.type = load_field(doc.get('type'), typedsl_uri_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_False_True_2, baseuri, loadingOptions)
           except ValidationException as e:
               errors.append(SourceLine(doc, 'type', str).makeError("the `type` field is not valid because:\n"+str(e)))

           if 'jsonldPredicate' in doc:
               try:
                   self.jsonldPredicate = load_field(doc.get('jsonldPredicate'), union_of_None_type_or_strtype_or_JsonldPredicateLoader, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'jsonldPredicate', str).makeError("the `jsonldPredicate` field is not valid because:\n"+str(e)))
           else:
               self.jsonldPredicate = None


           if errors:
               raise ValidationException("Trying 'SaladRecordField'\n"+"\n".join(errors))

    def save(self):
        r = {}
        if self.name is not None:
            r['name'] = save(self.name)
        if self.doc is not None:
            r['doc'] = save(self.doc)
        if self.type is not None:
            r['type'] = save(self.type)
        if self.jsonldPredicate is not None:
            r['jsonldPredicate'] = save(self.jsonldPredicate)
        return r


class SaladRecordSchema(NamedType, RecordSchema, SchemaDefinedType):
    def __init__(self, _doc, baseuri, loadingOptions, docRoot=None):
           doc = copy.copy(_doc)
           if hasattr(_doc, 'lc'):
               doc.lc.data = _doc.lc.data
               doc.lc.filename = _doc.lc.filename
           errors = []
           #doc = {expand_url(d, u"", loadingOptions, scoped_id=False, vocab_term=True): v for d,v in doc.items()}
           if 'name' in doc:
               try:
                   self.name = load_field(doc.get('name'), uri_strtype_True_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'name', str).makeError("the `name` field is not valid because:\n"+str(e)))
           else:
               self.name = None


           if self.name is None:
               if docRoot is not None:
                   self.name = docRoot
               else:
                   raise ValidationException("Missing name")
           baseuri = self.name
           if 'inVocab' in doc:
               try:
                   self.inVocab = load_field(doc.get('inVocab'), union_of_None_type_or_booltype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'inVocab', str).makeError("the `inVocab` field is not valid because:\n"+str(e)))
           else:
               self.inVocab = None

           if 'fields' in doc:
               try:
                   self.fields = load_field(doc.get('fields'), idmap_fields_union_of_None_type_or_array_of_SaladRecordFieldLoader, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'fields', str).makeError("the `fields` field is not valid because:\n"+str(e)))
           else:
               self.fields = None

           try:
               self.type = load_field(doc.get('type'), typedsl_uri_Record_symbolLoader_False_True_2, baseuri, loadingOptions)
           except ValidationException as e:
               errors.append(SourceLine(doc, 'type', str).makeError("the `type` field is not valid because:\n"+str(e)))

           if 'doc' in doc:
               try:
                   self.doc = load_field(doc.get('doc'), union_of_None_type_or_strtype_or_array_of_strtype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'doc', str).makeError("the `doc` field is not valid because:\n"+str(e)))
           else:
               self.doc = None

           if 'docParent' in doc:
               try:
                   self.docParent = load_field(doc.get('docParent'), uri_union_of_None_type_or_strtype_False_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'docParent', str).makeError("the `docParent` field is not valid because:\n"+str(e)))
           else:
               self.docParent = None

           if 'docChild' in doc:
               try:
                   self.docChild = load_field(doc.get('docChild'), uri_union_of_None_type_or_strtype_or_array_of_strtype_False_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'docChild', str).makeError("the `docChild` field is not valid because:\n"+str(e)))
           else:
               self.docChild = None

           if 'docAfter' in doc:
               try:
                   self.docAfter = load_field(doc.get('docAfter'), uri_union_of_None_type_or_strtype_False_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'docAfter', str).makeError("the `docAfter` field is not valid because:\n"+str(e)))
           else:
               self.docAfter = None

           if 'jsonldPredicate' in doc:
               try:
                   self.jsonldPredicate = load_field(doc.get('jsonldPredicate'), union_of_None_type_or_strtype_or_JsonldPredicateLoader, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'jsonldPredicate', str).makeError("the `jsonldPredicate` field is not valid because:\n"+str(e)))
           else:
               self.jsonldPredicate = None

           if 'documentRoot' in doc:
               try:
                   self.documentRoot = load_field(doc.get('documentRoot'), union_of_None_type_or_booltype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'documentRoot', str).makeError("the `documentRoot` field is not valid because:\n"+str(e)))
           else:
               self.documentRoot = None

           if 'abstract' in doc:
               try:
                   self.abstract = load_field(doc.get('abstract'), union_of_None_type_or_booltype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'abstract', str).makeError("the `abstract` field is not valid because:\n"+str(e)))
           else:
               self.abstract = None

           if 'extends' in doc:
               try:
                   self.extends = load_field(doc.get('extends'), uri_union_of_None_type_or_strtype_or_array_of_strtype_False_False_1, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'extends', str).makeError("the `extends` field is not valid because:\n"+str(e)))
           else:
               self.extends = None

           if 'specialize' in doc:
               try:
                   self.specialize = load_field(doc.get('specialize'), idmap_specialize_union_of_None_type_or_array_of_SpecializeDefLoader, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'specialize', str).makeError("the `specialize` field is not valid because:\n"+str(e)))
           else:
               self.specialize = None


           if errors:
               raise ValidationException("Trying 'SaladRecordSchema'\n"+"\n".join(errors))

    def save(self):
        r = {}
        if self.name is not None:
            r['name'] = save(self.name)
        if self.inVocab is not None:
            r['inVocab'] = save(self.inVocab)
        if self.fields is not None:
            r['fields'] = save(self.fields)
        if self.type is not None:
            r['type'] = save(self.type)
        if self.doc is not None:
            r['doc'] = save(self.doc)
        if self.docParent is not None:
            r['docParent'] = save(self.docParent)
        if self.docChild is not None:
            r['docChild'] = save(self.docChild)
        if self.docAfter is not None:
            r['docAfter'] = save(self.docAfter)
        if self.jsonldPredicate is not None:
            r['jsonldPredicate'] = save(self.jsonldPredicate)
        if self.documentRoot is not None:
            r['documentRoot'] = save(self.documentRoot)
        if self.abstract is not None:
            r['abstract'] = save(self.abstract)
        if self.extends is not None:
            r['extends'] = save(self.extends)
        if self.specialize is not None:
            r['specialize'] = save(self.specialize)
        return r


class SaladEnumSchema(NamedType, EnumSchema, SchemaDefinedType):
    """
Define an enumerated type.

    """
    def __init__(self, _doc, baseuri, loadingOptions, docRoot=None):
           doc = copy.copy(_doc)
           if hasattr(_doc, 'lc'):
               doc.lc.data = _doc.lc.data
               doc.lc.filename = _doc.lc.filename
           errors = []
           #doc = {expand_url(d, u"", loadingOptions, scoped_id=False, vocab_term=True): v for d,v in doc.items()}
           if 'name' in doc:
               try:
                   self.name = load_field(doc.get('name'), uri_strtype_True_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'name', str).makeError("the `name` field is not valid because:\n"+str(e)))
           else:
               self.name = None


           if self.name is None:
               if docRoot is not None:
                   self.name = docRoot
               else:
                   raise ValidationException("Missing name")
           baseuri = self.name
           if 'inVocab' in doc:
               try:
                   self.inVocab = load_field(doc.get('inVocab'), union_of_None_type_or_booltype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'inVocab', str).makeError("the `inVocab` field is not valid because:\n"+str(e)))
           else:
               self.inVocab = None

           try:
               self.symbols = load_field(doc.get('symbols'), uri_array_of_strtype_False_False_None, baseuri, loadingOptions)
           except ValidationException as e:
               errors.append(SourceLine(doc, 'symbols', str).makeError("the `symbols` field is not valid because:\n"+str(e)))

            
               
           try:
               self.type = load_field(doc.get('type'), typedsl_uri_Enum_symbolLoader_False_True_2, baseuri, loadingOptions)
           except ValidationException as e:
               errors.append(SourceLine(doc, 'type', str).makeError("the `type` field is not valid because:\n"+str(e)))

           if 'doc' in doc:
               try:
                   self.doc = load_field(doc.get('doc'), union_of_None_type_or_strtype_or_array_of_strtype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'doc', str).makeError("the `doc` field is not valid because:\n"+str(e)))
           else:
               self.doc = None

           if 'docParent' in doc:
               try:
                   self.docParent = load_field(doc.get('docParent'), uri_union_of_None_type_or_strtype_False_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'docParent', str).makeError("the `docParent` field is not valid because:\n"+str(e)))
           else:
               self.docParent = None

           if 'docChild' in doc:
               try:
                   self.docChild = load_field(doc.get('docChild'), uri_union_of_None_type_or_strtype_or_array_of_strtype_False_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'docChild', str).makeError("the `docChild` field is not valid because:\n"+str(e)))
           else:
               self.docChild = None

           if 'docAfter' in doc:
               try:
                   self.docAfter = load_field(doc.get('docAfter'), uri_union_of_None_type_or_strtype_False_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'docAfter', str).makeError("the `docAfter` field is not valid because:\n"+str(e)))
           else:
               self.docAfter = None

           if 'jsonldPredicate' in doc:
               try:
                   self.jsonldPredicate = load_field(doc.get('jsonldPredicate'), union_of_None_type_or_strtype_or_JsonldPredicateLoader, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'jsonldPredicate', str).makeError("the `jsonldPredicate` field is not valid because:\n"+str(e)))
           else:
               self.jsonldPredicate = None

           if 'documentRoot' in doc:
               try:
                   self.documentRoot = load_field(doc.get('documentRoot'), union_of_None_type_or_booltype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'documentRoot', str).makeError("the `documentRoot` field is not valid because:\n"+str(e)))
           else:
               self.documentRoot = None

           if 'extends' in doc:
               try:
                   self.extends = load_field(doc.get('extends'), uri_union_of_None_type_or_strtype_or_array_of_strtype_False_False_1, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'extends', str).makeError("the `extends` field is not valid because:\n"+str(e)))
           else:
               self.extends = None


           if errors:
               raise ValidationException("Trying 'SaladEnumSchema'\n"+"\n".join(errors))

    def save(self):
        r = {}
        if self.name is not None:
            r['name'] = save(self.name)
        if self.inVocab is not None:
            r['inVocab'] = save(self.inVocab)
        if self.symbols is not None:
            r['symbols'] = save(self.symbols)
        if self.type is not None:
            r['type'] = save(self.type)
        if self.doc is not None:
            r['doc'] = save(self.doc)
        if self.docParent is not None:
            r['docParent'] = save(self.docParent)
        if self.docChild is not None:
            r['docChild'] = save(self.docChild)
        if self.docAfter is not None:
            r['docAfter'] = save(self.docAfter)
        if self.jsonldPredicate is not None:
            r['jsonldPredicate'] = save(self.jsonldPredicate)
        if self.documentRoot is not None:
            r['documentRoot'] = save(self.documentRoot)
        if self.extends is not None:
            r['extends'] = save(self.extends)
        return r


class Documentation(NamedType, DocType):
    """
A documentation section.  This type exists to facilitate self-documenting
schemas but has no role in formal validation.

    """
    def __init__(self, _doc, baseuri, loadingOptions, docRoot=None):
           doc = copy.copy(_doc)
           if hasattr(_doc, 'lc'):
               doc.lc.data = _doc.lc.data
               doc.lc.filename = _doc.lc.filename
           errors = []
           #doc = {expand_url(d, u"", loadingOptions, scoped_id=False, vocab_term=True): v for d,v in doc.items()}
           if 'name' in doc:
               try:
                   self.name = load_field(doc.get('name'), uri_strtype_True_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'name', str).makeError("the `name` field is not valid because:\n"+str(e)))
           else:
               self.name = None


           if self.name is None:
               if docRoot is not None:
                   self.name = docRoot
               else:
                   raise ValidationException("Missing name")
           baseuri = self.name
           if 'inVocab' in doc:
               try:
                   self.inVocab = load_field(doc.get('inVocab'), union_of_None_type_or_booltype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'inVocab', str).makeError("the `inVocab` field is not valid because:\n"+str(e)))
           else:
               self.inVocab = None

           if 'doc' in doc:
               try:
                   self.doc = load_field(doc.get('doc'), union_of_None_type_or_strtype_or_array_of_strtype, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'doc', str).makeError("the `doc` field is not valid because:\n"+str(e)))
           else:
               self.doc = None

           if 'docParent' in doc:
               try:
                   self.docParent = load_field(doc.get('docParent'), uri_union_of_None_type_or_strtype_False_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'docParent', str).makeError("the `docParent` field is not valid because:\n"+str(e)))
           else:
               self.docParent = None

           if 'docChild' in doc:
               try:
                   self.docChild = load_field(doc.get('docChild'), uri_union_of_None_type_or_strtype_or_array_of_strtype_False_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'docChild', str).makeError("the `docChild` field is not valid because:\n"+str(e)))
           else:
               self.docChild = None

           if 'docAfter' in doc:
               try:
                   self.docAfter = load_field(doc.get('docAfter'), uri_union_of_None_type_or_strtype_False_False_None, baseuri, loadingOptions)
               except ValidationException as e:
                   errors.append(SourceLine(doc, 'docAfter', str).makeError("the `docAfter` field is not valid because:\n"+str(e)))
           else:
               self.docAfter = None

           try:
               self.type = load_field(doc.get('type'), typedsl_uri_Documentation_symbolLoader_False_True_2, baseuri, loadingOptions)
           except ValidationException as e:
               errors.append(SourceLine(doc, 'type', str).makeError("the `type` field is not valid because:\n"+str(e)))


           if errors:
               raise ValidationException("Trying 'Documentation'\n"+"\n".join(errors))

    def save(self):
        r = {}
        if self.name is not None:
            r['name'] = save(self.name)
        if self.inVocab is not None:
            r['inVocab'] = save(self.inVocab)
        if self.doc is not None:
            r['doc'] = save(self.doc)
        if self.docParent is not None:
            r['docParent'] = save(self.docParent)
        if self.docChild is not None:
            r['docChild'] = save(self.docChild)
        if self.docAfter is not None:
            r['docAfter'] = save(self.docAfter)
        if self.type is not None:
            r['type'] = save(self.type)
        return r


_vocab = {
    "fields": "https://w3id.org/cwl/salad#fields",
    "int": "http://www.w3.org/2001/XMLSchema#int",
    "refScope": "https://w3id.org/cwl/salad#JsonldPredicate/refScope",
    "abstract": "https://w3id.org/cwl/salad#SaladRecordSchema/abstract",
    "float": "http://www.w3.org/2001/XMLSchema#float",
    "symbols": "https://w3id.org/cwl/salad#symbols",
    "inVocab": "https://w3id.org/cwl/salad#NamedType/inVocab",
    "jsonldPredicate": "https://w3id.org/cwl/salad#SchemaDefinedType/jsonldPredicate",
    "boolean": "http://www.w3.org/2001/XMLSchema#boolean",
    "mapPredicate": "https://w3id.org/cwl/salad#JsonldPredicate/mapPredicate",
    "NamedType": "https://w3id.org/cwl/salad#NamedType",
    "array": "https://w3id.org/cwl/salad#array",
    "null": "https://w3id.org/cwl/salad#null",
    "SchemaDefinedType": "https://w3id.org/cwl/salad#SchemaDefinedType",
    "mapSubject": "https://w3id.org/cwl/salad#JsonldPredicate/mapSubject",
    "SaladRecordField": "https://w3id.org/cwl/salad#SaladRecordField",
    "SaladEnumSchema": "https://w3id.org/cwl/salad#SaladEnumSchema",
    "SpecializeDef": "https://w3id.org/cwl/salad#SpecializeDef",
    "DocType": "https://w3id.org/cwl/salad#DocType",
    "long": "http://www.w3.org/2001/XMLSchema#long",
    "JsonldPredicate": "https://w3id.org/cwl/salad#JsonldPredicate",
    "docParent": "https://w3id.org/cwl/salad#docParent",
    "extends": "https://w3id.org/cwl/salad#extends",
    "specializeFrom": "https://w3id.org/cwl/salad#specializeFrom",
    "type": "https://w3id.org/cwl/salad#type",
    "ArraySchema": "https://w3id.org/cwl/salad#ArraySchema",
    "_type": "https://w3id.org/cwl/salad#JsonldPredicate/_type",
    "docChild": "https://w3id.org/cwl/salad#docChild",
    "string": "http://www.w3.org/2001/XMLSchema#string",
    "RecordField": "https://w3id.org/cwl/salad#RecordField",
    "enum": "https://w3id.org/cwl/salad#enum",
    "RecordSchema": "https://w3id.org/cwl/salad#RecordSchema",
    "typeDSL": "https://w3id.org/cwl/salad#JsonldPredicate/typeDSL",
    "Documentation": "https://w3id.org/cwl/salad#Documentation",
    "docAfter": "https://w3id.org/cwl/salad#docAfter",
    "_container": "https://w3id.org/cwl/salad#JsonldPredicate/_container",
    "noLinkCheck": "https://w3id.org/cwl/salad#JsonldPredicate/noLinkCheck",
    "identity": "https://w3id.org/cwl/salad#JsonldPredicate/identity",
    "EnumSchema": "https://w3id.org/cwl/salad#EnumSchema",
    "specialize": "https://w3id.org/cwl/salad#specialize",
    "documentRoot": "https://w3id.org/cwl/salad#SchemaDefinedType/documentRoot",
    "double": "http://www.w3.org/2001/XMLSchema#double",
    "documentation": "https://w3id.org/cwl/salad#documentation",
    "SaladRecordSchema": "https://w3id.org/cwl/salad#SaladRecordSchema",
    "record": "https://w3id.org/cwl/salad#record",
    "doc": "https://w3id.org/cwl/salad#DocType/doc",
    "specializeTo": "https://w3id.org/cwl/salad#specializeTo",
    "items": "https://w3id.org/cwl/salad#items",
    "_id": "https://w3id.org/cwl/salad#_id",
    "Any": "https://w3id.org/cwl/salad#Any",
}
_rvocab = {
    "https://w3id.org/cwl/salad#fields": "fields",
    "http://www.w3.org/2001/XMLSchema#int": "int",
    "https://w3id.org/cwl/salad#JsonldPredicate/refScope": "refScope",
    "https://w3id.org/cwl/salad#SaladRecordSchema/abstract": "abstract",
    "http://www.w3.org/2001/XMLSchema#float": "float",
    "https://w3id.org/cwl/salad#symbols": "symbols",
    "https://w3id.org/cwl/salad#NamedType/inVocab": "inVocab",
    "https://w3id.org/cwl/salad#SchemaDefinedType/jsonldPredicate": "jsonldPredicate",
    "http://www.w3.org/2001/XMLSchema#boolean": "boolean",
    "https://w3id.org/cwl/salad#JsonldPredicate/mapPredicate": "mapPredicate",
    "https://w3id.org/cwl/salad#NamedType": "NamedType",
    "https://w3id.org/cwl/salad#array": "array",
    "https://w3id.org/cwl/salad#null": "null",
    "https://w3id.org/cwl/salad#SchemaDefinedType": "SchemaDefinedType",
    "https://w3id.org/cwl/salad#JsonldPredicate/mapSubject": "mapSubject",
    "https://w3id.org/cwl/salad#SaladRecordField": "SaladRecordField",
    "https://w3id.org/cwl/salad#SaladEnumSchema": "SaladEnumSchema",
    "https://w3id.org/cwl/salad#SpecializeDef": "SpecializeDef",
    "https://w3id.org/cwl/salad#DocType": "DocType",
    "http://www.w3.org/2001/XMLSchema#long": "long",
    "https://w3id.org/cwl/salad#JsonldPredicate": "JsonldPredicate",
    "https://w3id.org/cwl/salad#docParent": "docParent",
    "https://w3id.org/cwl/salad#extends": "extends",
    "https://w3id.org/cwl/salad#specializeFrom": "specializeFrom",
    "https://w3id.org/cwl/salad#type": "type",
    "https://w3id.org/cwl/salad#ArraySchema": "ArraySchema",
    "https://w3id.org/cwl/salad#JsonldPredicate/_type": "_type",
    "https://w3id.org/cwl/salad#docChild": "docChild",
    "http://www.w3.org/2001/XMLSchema#string": "string",
    "https://w3id.org/cwl/salad#RecordField": "RecordField",
    "https://w3id.org/cwl/salad#enum": "enum",
    "https://w3id.org/cwl/salad#RecordSchema": "RecordSchema",
    "https://w3id.org/cwl/salad#JsonldPredicate/typeDSL": "typeDSL",
    "https://w3id.org/cwl/salad#Documentation": "Documentation",
    "https://w3id.org/cwl/salad#docAfter": "docAfter",
    "https://w3id.org/cwl/salad#JsonldPredicate/_container": "_container",
    "https://w3id.org/cwl/salad#JsonldPredicate/noLinkCheck": "noLinkCheck",
    "https://w3id.org/cwl/salad#JsonldPredicate/identity": "identity",
    "https://w3id.org/cwl/salad#EnumSchema": "EnumSchema",
    "https://w3id.org/cwl/salad#specialize": "specialize",
    "https://w3id.org/cwl/salad#SchemaDefinedType/documentRoot": "documentRoot",
    "http://www.w3.org/2001/XMLSchema#double": "double",
    "https://w3id.org/cwl/salad#documentation": "documentation",
    "https://w3id.org/cwl/salad#SaladRecordSchema": "SaladRecordSchema",
    "https://w3id.org/cwl/salad#record": "record",
    "https://w3id.org/cwl/salad#DocType/doc": "doc",
    "https://w3id.org/cwl/salad#specializeTo": "specializeTo",
    "https://w3id.org/cwl/salad#items": "items",
    "https://w3id.org/cwl/salad#_id": "_id",
    "https://w3id.org/cwl/salad#Any": "Any",
}

inttype = _PrimitiveLoader(int)
booltype = _PrimitiveLoader(bool)
None_type = _PrimitiveLoader(NoneType)
strtype = _PrimitiveLoader((str, six.text_type))
PrimitiveTypeLoader = _EnumLoader(("null", "boolean", "int", "long", "float", "double", "string",))
AnyLoader = _EnumLoader(("Any",))
RecordFieldLoader = _RecordLoader(RecordField)
RecordSchemaLoader = _RecordLoader(RecordSchema)
EnumSchemaLoader = _RecordLoader(EnumSchema)
ArraySchemaLoader = _RecordLoader(ArraySchema)
JsonldPredicateLoader = _RecordLoader(JsonldPredicate)
SpecializeDefLoader = _RecordLoader(SpecializeDef)
NamedTypeLoader = _RecordLoader(NamedType)
DocTypeLoader = _RecordLoader(DocType)
SchemaDefinedTypeLoader = _RecordLoader(SchemaDefinedType)
SaladRecordFieldLoader = _RecordLoader(SaladRecordField)
SaladRecordSchemaLoader = _RecordLoader(SaladRecordSchema)
SaladEnumSchemaLoader = _RecordLoader(SaladEnumSchema)
DocumentationLoader = _RecordLoader(Documentation)
uri_strtype_True_False_None = _URILoader(strtype, True, False, None)
union_of_None_type_or_strtype = _UnionLoader((None_type, strtype))
union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype = _UnionLoader((PrimitiveTypeLoader, RecordSchemaLoader, EnumSchemaLoader, ArraySchemaLoader, strtype))
array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype = _ArrayLoader(union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype)
union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype = _UnionLoader((PrimitiveTypeLoader, RecordSchemaLoader, EnumSchemaLoader, ArraySchemaLoader, strtype, array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype))
uri_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_False_True_2 = _URILoader(union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype, False, True, 2)
typedsl_uri_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_False_True_2 = _TypeDSLLoader(uri_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_or_array_of_union_of_PrimitiveTypeLoader_or_RecordSchemaLoader_or_EnumSchemaLoader_or_ArraySchemaLoader_or_strtype_False_True_2)
array_of_RecordFieldLoader = _ArrayLoader(RecordFieldLoader)
union_of_None_type_or_array_of_RecordFieldLoader = _UnionLoader((None_type, array_of_RecordFieldLoader))
idmap_fields_union_of_None_type_or_array_of_RecordFieldLoader = _IdMapLoader(union_of_None_type_or_array_of_RecordFieldLoader, 'name', 'type')
Record_symbolLoader = _EnumLoader(("record",))
uri_Record_symbolLoader_False_True_2 = _URILoader(Record_symbolLoader, False, True, 2)
typedsl_uri_Record_symbolLoader_False_True_2 = _TypeDSLLoader(uri_Record_symbolLoader_False_True_2)
array_of_strtype = _ArrayLoader(strtype)
uri_array_of_strtype_False_False_None = _URILoader(array_of_strtype, False, False, None)
Enum_symbolLoader = _EnumLoader(("enum",))
uri_Enum_symbolLoader_False_True_2 = _URILoader(Enum_symbolLoader, False, True, 2)
typedsl_uri_Enum_symbolLoader_False_True_2 = _TypeDSLLoader(uri_Enum_symbolLoader_False_True_2)
Array_symbolLoader = _EnumLoader(("array",))
uri_Array_symbolLoader_False_True_2 = _URILoader(Array_symbolLoader, False, True, 2)
typedsl_uri_Array_symbolLoader_False_True_2 = _TypeDSLLoader(uri_Array_symbolLoader_False_True_2)
uri_union_of_None_type_or_strtype_False_False_None = _URILoader(union_of_None_type_or_strtype, False, False, None)
union_of_None_type_or_booltype = _UnionLoader((None_type, booltype))
union_of_None_type_or_inttype = _UnionLoader((None_type, inttype))
uri_strtype_False_False_1 = _URILoader(strtype, False, False, 1)
union_of_None_type_or_strtype_or_array_of_strtype = _UnionLoader((None_type, strtype, array_of_strtype))
uri_union_of_None_type_or_strtype_or_array_of_strtype_False_False_None = _URILoader(union_of_None_type_or_strtype_or_array_of_strtype, False, False, None)
union_of_None_type_or_strtype_or_JsonldPredicateLoader = _UnionLoader((None_type, strtype, JsonldPredicateLoader))
array_of_SaladRecordFieldLoader = _ArrayLoader(SaladRecordFieldLoader)
union_of_None_type_or_array_of_SaladRecordFieldLoader = _UnionLoader((None_type, array_of_SaladRecordFieldLoader))
idmap_fields_union_of_None_type_or_array_of_SaladRecordFieldLoader = _IdMapLoader(union_of_None_type_or_array_of_SaladRecordFieldLoader, 'name', 'type')
uri_union_of_None_type_or_strtype_or_array_of_strtype_False_False_1 = _URILoader(union_of_None_type_or_strtype_or_array_of_strtype, False, False, 1)
array_of_SpecializeDefLoader = _ArrayLoader(SpecializeDefLoader)
union_of_None_type_or_array_of_SpecializeDefLoader = _UnionLoader((None_type, array_of_SpecializeDefLoader))
idmap_specialize_union_of_None_type_or_array_of_SpecializeDefLoader = _IdMapLoader(union_of_None_type_or_array_of_SpecializeDefLoader, 'specializeFrom', 'specializeTo')
Documentation_symbolLoader = _EnumLoader(("documentation",))
uri_Documentation_symbolLoader_False_True_2 = _URILoader(Documentation_symbolLoader, False, True, 2)
typedsl_uri_Documentation_symbolLoader_False_True_2 = _TypeDSLLoader(uri_Documentation_symbolLoader_False_True_2)
union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_DocumentationLoader = _UnionLoader((SaladRecordSchemaLoader, SaladEnumSchemaLoader, DocumentationLoader))
array_of_union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_DocumentationLoader = _ArrayLoader(union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_DocumentationLoader)
union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_DocumentationLoader_or_array_of_union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_DocumentationLoader = _UnionLoader((SaladRecordSchemaLoader, SaladEnumSchemaLoader, DocumentationLoader, array_of_union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_DocumentationLoader))



def load_document(doc, baseuri, loadingOptions):
    return _document_load(union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_DocumentationLoader_or_array_of_union_of_SaladRecordSchemaLoader_or_SaladEnumSchemaLoader_or_DocumentationLoader, doc, baseuri, loadingOptions)
