
# 2009-01-10 katoy

require 'rubygems'
require 'xml/libxml'
require 'open-uri'
require 'pp'
require 'benchmark'

class RoleRef
  attr_reader :roleURI
  attr_reader :type
  attr_reader :href

  def parse(reader)
    @roleURI = reader['roleURI'].to_sym if reader['roleURI'] != nil
    @type  = reader['xlink:type'].to_sym if reader['xlink:type'] != nil
    @href  = reader['xlink:href'].to_sym if reader['xlink:href'] != nil
    self
  end

  def to_s
    "RoleRef roleURI='#{@roleURI.to_s}' href='#{@href.to_s}' type='#{@type.to_s}'"
  end
end

class Loc
  attr_reader :label
  attr_reader :type
  attr_reader :href
  attr_reader :role

  def parse(reader)
    @label = reader['xlink:label'].to_sym if reader['xlink:label'] != nil
    @type  = reader['xlink:type'].to_sym if reader['xlink:type'] != nil
    @href  = reader['xlink:href'].to_sym if reader['xlink:href'] != nil
    @role  = reader['xlink:role'].to_sym if reader['xlink:role'] != nil
    self
  end

  def to_s
    "Loc type='#{@type.to_s}' href='#{@href.to_s}' label='#{@label.to_s}' role='#{@role.to_s}'"
  end
end

class Arc
  attr_reader :type
  attr_reader :arcrole
  attr_reader :from
  attr_reader :to
  attr_reader :use
  attr_reader :priority
  attr_reader :order

  def parse(reader)
    @type = reader['xlink:type'].to_sym if reader['xlink:type'] != nil
    @arcrole = reader['xlink:arcrole'].to_sym if reader['xlink:arcrole'] != nil
    @from = reader['xlink:from'].to_sym if reader['xlink:from'] != nil
    @to = reader['xlink:to'].to_sym if reader['xlink:to'] != nil
    @use = reader['use'].to_sym if reader['use'] != nil
    @priority = reader['priority'].to_sym if reader['priority'] != nil
    @order = reader['order'].to_sym if reader['order'] != nil
    self
  end

  def to_s
    "Arc type='#{@type.to_s}' arcrole='#{@arcrole.to_s}' from='#{@from.to_s}' to='#{@to.to_s}' use='#{@use.to_s}' priority='#{@priority.to_s}' order='#{@order.to_s}'"
  end
end

class Label
  attr_reader :label
  attr_reader :type
  attr_reader :role
  attr_reader :lang
  attr_reader :id
  attr_reader :text

  def parse(reader)
    @label = reader['xlink:label'].to_sym if reader['xlink:label'] != nil
    @id = reader['id'].to_sym if reader['id'] != nil
    @type = reader['xlink:type'].to_sym if reader['xlink:type'] != nil
    @role = reader['xlink:role'].to_sym if reader['xlink:role'] != nil
    @lang = reader['xml:lang'].to_sym if reader['xml:lang'] != nil
    @text = reader.expand.child

    @id = @label if @id == nil and @label != nil 

    self
  end

  def to_s
    "Label type='#{@type.to_s}' label='#{@label.to_s}' role='#{@role.to_s}' lang='#{@lang.to_s}' id='#{@id.to_s}' text='#{@text}'"
  end
end

class Link
  attr_reader :role
  attr_reader :type
  attr_reader :href

  attr_reader :locs
  attr_reader :arcs

  attr_reader :labels
  attr_reader :id2labels

  def initialize
    @locs = {}  # label => loc
    @arcs = {}  # from => [arc]
    @labels = {}  # id => label
    @id2labels = { } # uri => [text]
  end

  def parse(reader, file, dir)
    @role  = reader['xlink:role'].to_sym if reader['xlink:role'] != nil
    @type = reader['xlink:type'].to_sym if reader['xlink:type'] != nil
    @href = reader['xlink:href'].to_sym if reader['xlink:href'] != nil
    while reader.read
      break if reader.depth == 1
      next if reader.namespace_uri == nil

      name = "#{reader.namespace_uri}:#{reader.local_name}"
      case name
        #--- Arc
      when 'http://www.xbrl.org/2003/linkbase:definitionArc'
        arc = Arc.new.parse(reader)
        @arcs[arc.from] = [] if @arcs[arc.from] == nil
        @arcs[arc.from] <<  arc
      when 'http://www.xbrl.org/2003/linkbase:presentationArc'
        arc = Arc.new.parse(reader)
        @arcs[arc.from] = [] if @arcs[arc.from] == nil
        @arcs[arc.from] <<  arc
      when 'http://www.xbrl.org/2003/linkbase:labelArc'
        arc = Arc.new.parse(reader)
        @arcs[arc.from] = [] if @arcs[arc.from] == nil
        @arcs[arc.from] <<  arc
      when 'http://www.xbrl.org/2003/linkbase:referenceArc'
        arc = Arc.new.parse(reader)
        @arcs[arc.from] = [] if @arcs[arc.from] == nil
        @arcs[arc.from] <<  arc
      when 'http://www.xbrl.org/2003/linkbase:calculationArc'
        arc = Arc.new.parse(reader)
        @arcs[arc.from] = [] if @arcs[arc.from] == nil
        @arcs[arc.from] <<  arc

        #-- loc
      when 'http://www.xbrl.org/2003/linkbase:loc'
        loc = Loc.new.parse(reader)
        @locs[loc.label] = loc

        #-- label
      when 'http://www.xbrl.org/2003/linkbase:label'
        label = Label.new.parse(reader)
        @labels[label.id] = label

        #-- reference
      when 'http://www.xbrl.org/2003/linkbase:reference'
        label = Label.new.parse(reader)
        @references[label.id] = label

      else
        puts "******* ignore(1) #{name} in label at #{file} line:#{reader.line_number}"
      end      
    end

    pp role
    @arcs.each do |from, as|
      # pp from
      from_href = @locs[from].href
      as.each do |a|
        # pp a
        @id2labels[from_href] = { } if @id2labels[from_href] == nil
        @id2labels[from_href][a.to] = { } if @id2labels[from_href][a.to] == nil
        @id2labels[from_href][a.to][@labels[a.to].lang] = @labels[a.to].text if @labels[a.to] != nil
      end
    end
    self
  end

  def to_s
    "Link role='#{@role.to_s}' type='#{@type.to_s}' href='#{@href.to_s}'"
  end
end

class Linkbase
  attr_reader :labellinks
  attr_reader :presentationlinks
  attr_reader :calculationlinks
  attr_reader :definitionlinks
  attr_reader :rolerefs

  def initialize
    @labellinks = []
    @presentationlinks = []
    @calculationlinks = []
    @definitionlinks = []
    @rolerefs = []
  end

  def parse(file, dir='')

    begin
      reader = XML::Reader.file file
    rescue
      puts "---- error reading #{file}"
      reader.close if reader != nil
      return self
    end

    while reader.read
      
      next if reader.namespace_uri == nil
      name = "#{reader.namespace_uri}:#{reader.local_name}"

      case name

      when 'http://www.xbrl.org/2003/linkbase:linkbase'

      when 'http://www.xbrl.org/2003/linkbase:roleRef'
        @rolerefs << RoleRef.new.parse(reader)

      when 'http://www.xbrl.org/2003/linkbase:definitionLink'
        @definitionlinks << Link.new.parse(reader, file, dir)
      when 'http://www.xbrl.org/2003/linkbase:calculationLink'
        @calculationlinks << Link.new.parse(reader, file, dir)
      when 'http://www.xbrl.org/2003/linkbase:presentationLink'
        @presentationlinks << Link.new.parse(reader, file, dir)
      when 'http://www.xbrl.org/2003/linkbase:labelLink'
        @labellinks << Link.new.parse(reader, file, dir)
      else
        puts "******* ignore(0) #{name} in label at #{file} line:#{reader.line_number}"
      end      
    end
    self
  end
end

if $0 == __FILE__
  # pat = '../data/msft/msft-20080930_lab.xml'
  # pat = '../data/msft/msft-20080930_pre.xml'
  # pat = '../data/msft/msft-20080930_cal.xml'
  # pat = '../data/msft/msft-20080930_def.xml'
  # pat = '../data/msft/msft-20080930_*.xml'

  # pat = '../data/td-net/081220090203088072/tdnet-qcedjpfr-33500-2008-11-30-01-2009-02-20-label.xml'
  # pat = '../data/td-net/081220090203088072/tdnet-qcedjpfr-33500-2008-11-30-01-2009-02-20-label-en.xml'
  # pat = '../data/td-net/081220090203088072/tdnet-qcedjpfr-33500-2008-11-30-01-2009-02-20-pres*.xml'
  # pat = '../data/td-net/081220090203088072/tdnet-qcedjpfr-33500-2008-11-30-01-2009-02-20-cal*.xml'
  # pat = '../data/td-net/081220090203088072/tdnet-qcedjpfr-33500-2008-11-30-01-2009-02-20-def*.xml'
  pat = '../data/td-net/081220090203088072/tdnet-qcedjpfr-33500-2008-11-30-01-2009-02-20-*.xml'

  # pat = ARGV[0]

  puts Benchmark.measure {

    linkbase = Linkbase.new
    Dir.glob(pat).each do |f|
      linkbase.parse(f)
    end

    puts '-------- labellink '
    linkbase.labellinks.each do |link|
      #      pp link.locs.size
      #      pp link.arcs.size
      #      pp link.labels.size
      pp link.id2labels
    end

    puts '-------- presentationlink '
    linkbase.presentationlinks.each do |link|
      #      pp link.locs.size
      #      pp link.arcs.size
      pp link.id2labels
    end

    puts '-------- calculationlink '
    linkbase.calculationlinks.each do |link|
      #      pp link.locs.size
      #      pp link.arcs.size
      pp link.id2labels
    end

    puts '-------- definitionlink '
    linkbase.definitionlinks.each do |link|
      #      pp link.locs.size
      #      pp link.arcs.size
      pp link.id2labels
    end

    puts '-------- rolerefs '
    #    puts linkbase.rolerefs.size
    linkbase.rolerefs.each do |role|
      pp role
    end

  }
end
