
require 'rubygems'
require 'optparse'
require 'XbrlDatamap'
require 'xml/libxml'
require 'parserunit'
require 'parsercontext'
require 'parserfootnote'
require 'parseritem'

require 'date'
require 'benchmark'

def read_data(file, dir='')
  units = {}
  contexts = {}
  inst = Xbrlinstance.find_or_create(:fpath => file)

  GC.start
  reader = XML::Reader.file(file)
  while reader.read
    name = "#{reader.namespace_uri}:#{reader.local_name}"

    case name
    when 'http://www.xbrl.org/2003/instance:xbrl'
    when ':#text'
    when ':#comment'

    when 'http://www.xbrl.org/2003/linkbase:schemaRef'
      # schema << Schema.new.parse(reader, file, dir)
    when 'http://www.xbrl.org/2003/linkbase:roleRef'
      # r = RoleRef.new.parse(reader, file, dir)
      # roles[r[:roleuri]] = r[:role]
    when 'http://www.xbrl.org/2003/instance:context'
      c = ParserContext.new.parse(reader, file, dir)
      c_data = inst.contexts.build(:name => c[:id],
        :identifier => c[:context].identifier,
        :period_startDate => c[:context].startdate == nil ? nil: Date.parse(c[:context].startdate.to_s),
        :period_endDate => c[:context].enddate == nil ? nil: Date.parse(c[:context].enddate.to_s),
        :period_instant => c[:context].instant == nil ? nil: Date.parse(c[:context].instant.to_s),
        :period_forever => c[:context].forever != nil)
      contexts[c[:id]] = c_data
    when 'http://www.xbrl.org/2003/instance:unit'
      u = ParserUnit.new.parse(reader, file, dir)
      u_data = inst.units.build(:name => u[:id],
        :measure => u[:unit].measure,
        :numerator =>u[:unit].unitNumerator , :measure => u[:unit].measure,
        :denominator => u[:unit].unitDenominator)
      units[u[:id]] = u_data
    when 'http://www.xbrl.org/2003/linkbase:footnoteLink'
      foot = ParserFootnote.new.parse(reader, file, dir)
      #footnotelinks[foot.role] = foot
    else
      ParserItem.new.parse(reader, file, dir)
    end
  end
  reader.close
  reader = nil

  # pp "----- pass 2 -----"
  GC.start
  reader = XML::Reader.file(file)
  while reader.read
    name = "#{reader.namespace_uri}:#{reader.local_name}"
    # pp "---- #{name} -----"

    case name
    when 'http://www.xbrl.org/2003/instance:xbrl'
    when ':#text'
    when ':#comment'

    when 'http://www.xbrl.org/2003/linkbase:schemaRef'
      # schema << Schema.new.parse(reader, file, dir)
    when 'http://www.xbrl.org/2003/linkbase:roleRef'
      # r = RoleRef.new.parse(reader, file, dir)
      # roles[r[:roleuri]] = r[:role]
    when 'http://www.xbrl.org/2003/instance:context'
      ParserContext.new.parse(reader, file, dir)
    when 'http://www.xbrl.org/2003/instance:unit'
      u = ParserUnit.new.parse(reader, file, dir)
    when 'http://www.xbrl.org/2003/linkbase:footnoteLink'
      foot = ParserFootnote.new.parse(reader, file, dir)
      #footnotelinks[foot.role] = foot
    else
      name
      item = ParserItem.new.parse(reader, file, dir)
      f = inst.facts.build(:element => "#{item.uri}:#{item.name}", :val => item.fact)
      if item.unitref
        units[item.unitref].facts << f if units[item.unitref] != nil
      end
      if item.contextref
        contexts[item.contextref].facts << f if contexts[item.contextref] != nil
      end
      # pp f.inspect
    end
  end
  inst.save

  reader.close
  units = {}
  contexts = {}
end

def num_fmt(num)
  num.to_s.reverse.gsub( /(\d{3})(?=\d)/, '\1,' ).reverse
end

DATE_FMT = '%Y-%m-%d'
def get_datestr(fact)
  if fact.context != nil
    if (fact.context.period_startDate != nil) and (fact.context.period_endDate != nil)
      date_str = "#{fact.context.period_startDate.strftime(DATE_FMT)} - #{fact.context.period_endDate.strftime(DATE_FMT)}"
    elsif fact.context.period_instant != nil
      date_str = "#{fact.context.period_instant.strftime(DATE_FMT)}"
    elsif fact.context.period_forever
      date_str = "forever"
    else
      date_str = 'nil'
    end
  end
  date_str
end

mem_p = false
init_p = false

puts Benchmark.measure {

  opt = OptionParser.new

  opt.on('-m', 'use memory db') {|v| mem_p = true }
  opt.on('-i', 'init db') {|v| init_p = true }

  opt.parse!(ARGV)

  if mem_p
    pp "--- using memory"
    DataMapper.setup(:default, 'sqlite3::memory:''')
    DataMapper.auto_migrate!
    init_p = true
  else
    # DataMapper.setup(:default, "sqlite3://#{File.dirname(File.expand_path(__FILE__))}/db.sqlite3")
    # Database を作成しておく必要がある。
    # $ mysql -u root -p
    # > create database dm_test;
    # > quit
    DataMapper.setup(:default, "mysql://root:root@localhost/dm_test")

    if init_p
      pp "--- init DB"
      DataMapper.auto_migrate!
    else
      pp "--- open DB"
      DataMapper.auto_upgrade!
    end
  end

  if init_p
    fcount = 0
    while(ARGV.size > 0)
      fpath = ARGV.shift
      fcount += 1
      puts "reading #{fcount}:\t#{fpath}"
      read_data(fpath)  if File::exist?(fpath)
    end
  end

  pp "instances: #{Xbrlinstance.all.size}"
  Xbrlinstance.all.each_with_index {|inst, index|
    puts "#{index}: #{inst.fpath}"
    puts "\t#{Fact.all('xbrlinstance.fpath' => inst.fpath).size}" +
      ", #{Unit.all('xbrlinstance.fpath' => inst.fpath).size}" +
      ", #{Context.all('xbrlinstance.fpath' => inst.fpath).size}"
  }
  # pp Xbrlinstance.all('fpath' => fpath0)
  # pp Unit.all
  # pp Context.all
  # pp Fact.all
  pp "facts:    #{Fact.all.size}"
  pp "units:    #{Unit.all.size}"
  pp "contexts: #{Context.all.size}"

  pp "---- Search http://xbrl.us/us-gaap/2008-03-31:NetIncomeLoss --"
  pp "----        http://xbrl.us/us-gaap/2008-01-31:NetIncomeLoss --"
  num = 0
  Fact.all("element" => 'http://xbrl.us/us-gaap/2008-03-31:NetIncomeLoss').each {|f|
    num += 1
    date_str = get_datestr(f)
    printf("%3d: %s\t %s %s\n",
      num,
      f.xbrlinstance.fpath, num_fmt(f.val).rjust(20), date_str)
  }
  Fact.all("element" => 'http://xbrl.us/us-gaap/2008-01-31:NetIncomeLoss').each {|f|
    num += 1
    date_str = get_datestr(f)
    printf("%3d: %s\t %s %s\n",
      num,
      f.xbrlinstance.fpath, num_fmt(f.val).rjust(20), date_str)
  }
}