# File lib/asciidoctor/document.rb, line 101
  def initialize(data = [], options = {}, &block)
    super(self, :document)
    @renderer = nil

    if options[:parent]
      @parent_document = options.delete(:parent)
      # should we dup attributes here?
      options[:attributes] = @parent_document.attributes
      options[:base_dir] ||= @parent_document.base_dir
      @safe = @parent_document.safe
      @renderer = @parent_document.renderer
    else
      @parent_document = nil
      @safe = nil
    end

    @header = nil
    @references = {
      :ids => {},
      :footnotes => [],
      :links => [],
      :images => [],
      :indexterms => []
    }
    @counters = {}
    @callouts = Callouts.new
    @options = options
    # safely resolve the safe mode from const, int or string
    if @safe.nil? && !(safe_mode = @options[:safe])
      @safe = SafeMode::SECURE
    elsif safe_mode.is_a?(Fixnum)
      # be permissive in case API user wants to define new levels
      @safe = safe_mode
    else
      begin
        @safe = SafeMode.const_get(safe_mode.to_s.upcase).to_i
      rescue
        @safe = SafeMode::SECURE.to_i
      end
    end
    @options[:header_footer] = @options.fetch(:header_footer, false)

    @attributes['encoding'] = 'UTF-8'
    @attributes['sectids'] = ''
    @attributes['notitle'] = '' unless @options[:header_footer]
    @attributes['toc-placement'] = 'auto'
    @attributes['stylesheet'] = ''
    @attributes['linkcss'] = ''

    # language strings
    # TODO load these based on language settings
    @attributes['caution-caption'] = 'Caution'
    @attributes['important-caption'] = 'Important'
    @attributes['note-caption'] = 'Note'
    @attributes['tip-caption'] = 'Tip'
    @attributes['warning-caption'] = 'Warning'
    @attributes['appendix-caption'] = 'Appendix'
    @attributes['example-caption'] = 'Example'
    @attributes['figure-caption'] = 'Figure'
    #@attributes['listing-caption'] = 'Listing'
    @attributes['table-caption'] = 'Table'
    @attributes['toc-title'] = 'Table of Contents'

    # attribute overrides are attributes that can only be set from the commandline
    # a direct assignment effectively makes the attribute a constant
    # assigning a nil value will result in the attribute being unset
    @attribute_overrides = options[:attributes] || {}

    @attribute_overrides['asciidoctor'] = ''
    @attribute_overrides['asciidoctor-version'] = VERSION

    safe_mode_name = SafeMode.constants.detect {|l| SafeMode.const_get(l) == @safe}.to_s.downcase
    @attribute_overrides['safe-mode-name'] = safe_mode_name
    @attribute_overrides["safe-mode-#{safe_mode_name}"] = ''
    @attribute_overrides['safe-mode-level'] = @safe

    # sync the embedded attribute w/ the value of options...do not allow override
    @attribute_overrides['embedded'] = @options[:header_footer] ? nil : ''

    # the only way to set the include-depth attribute is via the document options
    # 10 is the AsciiDoc default, though currently Asciidoctor only supports 1 level
    @attribute_overrides['include-depth'] ||= 10

    # if the base_dir option is specified, it overrides docdir as the root for relative paths
    # otherwise, the base_dir is the directory of the source file (docdir) or the current
    # directory of the input is a string
    if options[:base_dir].nil?
      if @attribute_overrides['docdir']
        @base_dir = @attribute_overrides['docdir'] = File.expand_path(@attribute_overrides['docdir'])
      else
        #puts 'asciidoctor: WARNING: setting base_dir is recommended when working with string documents' unless nested?
        @base_dir = @attribute_overrides['docdir'] = File.expand_path(Dir.pwd)
      end
    else
      @base_dir = @attribute_overrides['docdir'] = File.expand_path(options[:base_dir])
    end

    # allow common attributes backend and doctype to be set using options hash
    unless @options[:backend].nil?
      @attribute_overrides['backend'] = @options[:backend].to_s
    end

    unless @options[:doctype].nil?
      @attribute_overrides['doctype'] = @options[:doctype].to_s
    end

    if @safe >= SafeMode::SERVER
      # restrict document from setting linkcss, copycss, source-highlighter and backend
      @attribute_overrides['copycss'] ||= nil
      @attribute_overrides['source-highlighter'] ||= nil
      @attribute_overrides['backend'] ||= DEFAULT_BACKEND
      # restrict document from seeing the docdir and trim docfile to relative path
      if @attribute_overrides.has_key?('docfile') && @parent_document.nil?
        @attribute_overrides['docfile'] = @attribute_overrides['docfile'][(@attribute_overrides['docdir'].length + 1)..-1]
      end
      @attribute_overrides['docdir'] = ''
      if @safe >= SafeMode::SECURE
        # assign linkcss (preventing css embedding) unless disabled from the commandline
        unless @attribute_overrides.fetch('linkcss', '').nil? || @attribute_overrides.has_key?('linkcss!')
          @attribute_overrides['linkcss'] = ''
        end
        # restrict document from enabling icons
        @attribute_overrides['icons'] ||= nil
      end
    end
    
    @attribute_overrides.delete_if {|key, val|
      verdict = false
      # a nil value undefines the attribute 
      if val.nil?
        @attributes.delete(key)
      # a negative key undefines the attribute
      elsif key.end_with? '!'
        @attributes.delete(key[0..-2])
      # otherwise it's an attribute assignment
      else
        # a value ending in @ indicates this attribute does not override
        # an attribute with the same key in the document souce
        if val.is_a?(String) && val.end_with?('@')
          val.chop!
          verdict = true
        end
        @attributes[key] = val
      end
      verdict
    }

    @attributes['backend'] ||= DEFAULT_BACKEND
    @attributes['doctype'] ||= DEFAULT_DOCTYPE
    update_backend_attributes
    # make toc and numbered the default for the docbook backend
    # FIXME this doesn't take into account the backend being set in the document
    #if @attributes.has_key?('basebackend-docbook')
    #  @attributes['toc'] = '' unless @attribute_overrides.has_key?('toc!')
    #  @attributes['numbered'] = '' unless @attribute_overrides.has_key?('numbered!')
    #end

    if !@parent_document.nil?
      # don't need to do the extra processing within our own document
      @reader = Reader.new(data)
    else
      @reader = Reader.new(data, self, true, &block)
    end

    # dynamic intrinstic attribute values
    now = Time.new
    @attributes['localdate'] ||= now.strftime('%Y-%m-%d')
    @attributes['localtime'] ||= now.strftime('%H:%M:%S %Z')
    @attributes['localdatetime'] ||= [@attributes['localdate'], @attributes['localtime']] * ' '
    
    # docdate, doctime and docdatetime should default to
    # localdate, localtime and localdatetime if not otherwise set
    @attributes['docdate'] ||= @attributes['localdate']
    @attributes['doctime'] ||= @attributes['localtime']
    @attributes['docdatetime'] ||= @attributes['localdatetime']

    # fallback directories
    @attributes['stylesdir'] ||= '.'
    @attributes['iconsdir'] ||= File.join(@attributes.fetch('imagesdir', './images'), 'icons')

    # Now parse the lines in the reader into blocks
    Lexer.parse(@reader, self, :header_only => @options.fetch(:parse_header_only, false)) 

    @callouts.rewind
  end