text: "use strict";
  
  module.exports = parse;
  
  var BlankNode = require('./blank-node');
  
  var jsonld = require('jsonld');
  
  var Literal = require('./literal');
  
  var N3 = require('n3'); // @@ Goal: remove this dependency
  
  
  var N3Parser = require('./n3parser');
  
  var NamedNode = require('./named-node');
  
  var parseRDFaDOM = require('./rdfaparser').parseRDFaDOM;
  
  var RDFParser = require('./rdfxmlparser');
  
  var sparqlUpdateParser = require('./patch-parser');
  
  var Util = require('./util');
  /**
   * Parse a string and put the result into the graph kb.
   * Normal method is sync.
   * Unfortunately jsdonld is currently written to need to be called async.
   * Hence the mess below with executeCallback.
   */
  
  
  function parse(str, kb, base, contentType, callback) {
    contentType = contentType || 'text/turtle';
    contentType = contentType.split(';')[0];
  
    try {
      if (contentType === 'text/n3' || contentType === 'text/turtle') {
        var p = N3Parser(kb, kb, base, base, null, null, '', null);
        p.loadBuf(str);
        executeCallback();
      } else if (contentType === 'application/rdf+xml') {
        var parser = new RDFParser(kb);
        parser.parse(Util.parseXML(str), base, kb.sym(base));
        executeCallback();
      } else if (contentType === 'application/xhtml+xml') {
        parseRDFaDOM(Util.parseXML(str, {
          contentType: 'application/xhtml+xml'
        }), kb, base);
        executeCallback();
      } else if (contentType === 'text/html') {
        parseRDFaDOM(Util.parseXML(str, {
          contentType: 'text/html'
        }), kb, base);
        executeCallback();
      } else if (contentType === 'application/sparql-update') {
        // @@ we handle a subset
        sparqlUpdateParser(str, kb, base);
        executeCallback();
      } else if (contentType === 'application/ld+json' || contentType === 'application/nquads' || contentType === 'application/n-quads') {
        var n3Parser = N3.Parser();
        var triples = [];
  
        if (contentType === 'application/ld+json') {
          var jsonDocument;
  
          try {
            jsonDocument = JSON.parse(str);
          } catch (parseErr) {
            return callback(parseErr, null);
          }
  
          jsonld.toRDF(jsonDocument, {
            format: 'application/nquads',
            base: base
          }, nquadCallback);
        } else {
          nquadCallback(null, str);
        }
      } else {
        throw new Error("Don't know how to parse " + contentType + ' yet');
      }
    } catch (e) {
      executeErrorCallback(e);
    }
  
    parse.handled = {
      'text/n3': true,
      'text/turtle': true,
      'application/rdf+xml': true,
      'application/xhtml+xml': true,
      'text/html': true,
      'application/sparql-update': true,
      'application/ld+json': true,
      'application/nquads': true,
      'application/n-quads': true
    };
  
    function executeCallback() {
      if (callback) {
        callback(null, kb);
      } else {
        return;
      }
    }
  
    function executeErrorCallback(e) {
      if (contentType !== 'application/ld+json' || contentType !== 'application/nquads' || contentType !== 'application/n-quads') {
        if (callback) {
          callback(e, kb);
        } else {
          throw new Error('Error trying to parse <' + base + '> as ' + contentType + ':\n' + e + ':\n' + e.stack);
        }
      }
    }
    /*
      function setJsonLdBase (doc, base) {
        if (doc instanceof Array) {
          return
        }
        if (!('@context' in doc)) {
          doc['@context'] = {}
        }
        doc['@context']['@base'] = base
      }
    */
  
  
    function nquadCallback(err, nquads) {
      if (err) {
        callback(err, kb);
      }
  
      try {
        n3Parser.parse(nquads, tripleCallback);
      } catch (err) {
        callback(err, kb);
      }
    }
  
    function tripleCallback(err, triple, prefixes) {
      if (err) {
        callback(err, kb);
      }
  
      if (triple) {
        triples.push(triple);
      } else {
        for (var i = 0; i < triples.length; i++) {
          addTriple(kb, triples[i]);
        }
  
        callback(null, kb);
      }
    }
  
    function addTriple(kb, triple) {
      var subject = createTerm(triple.subject);
      var predicate = createTerm(triple.predicate);
      var object = createTerm(triple.object);
      var why = null;
  
      if (triple.graph) {
        why = createTerm(triple.graph);
      }
  
      kb.add(subject, predicate, object, why);
    }
  
    function createTerm(termString) {
      var value;
  
      if (N3.Util.isLiteral(termString)) {
        value = N3.Util.getLiteralValue(termString);
        var language = N3.Util.getLiteralLanguage(termString);
        var datatype = new NamedNode(N3.Util.getLiteralType(termString));
        return new Literal(value, language, datatype);
      } else if (N3.Util.isIRI(termString)) {
        return new NamedNode(termString);
      } else if (N3.Util.isBlank(termString)) {
        value = termString.substring(2, termString.length);
        return new BlankNode(value);
      } else {
        return null;
      }
    }
  }