#!ruby -KS
# web_init.rb
# by YOSHIDA Kazuhiro (moriq@moriq.com)
#
# loaded from Apache module
#
$KCODE = 'SJIS'

require 'phi'
require 'web'

Phi.debug = true
Thread.critical = true

module Web
  # Web::BASEDIR
  #   コンテンツを置いているフォルダ
  basedir = File.dirname(__FILE__.gsub(/\\/,'/')) + '/../htdocs'
  BASEDIR = File.expand_path(basedir)

  # Web::OUTPATH
  #   Apollo.so が出力するログのパス
  #   絶対パスにすべきです。
# OUTPATH = '/Apache/logs/apollo.log'
  OUTPATH = 'logs/apollo.log'

  @debug = nil
  @debug = true
  attr :debug

  def load(path)
    path = BASEDIR + File.join(File.dirname(MODULE.request.path_info), path)
    eval(open(path).read, TOPLEVEL_BINDING)
  end
  
  module_function :debug, :load

end

# Global counter
$count = 0 if not defined? $count
$count+= 1
p $count

def no_cache(response)
  response.expires = -1
  response.custom_headers['Cache-Control'] = 'no-cache'
  response.custom_headers['Pragma'] = 'no-cache'
  nil
end

# Embed check
p Phi::APPLICATION
p Web::APPLICATION
# p Web::APPLICATION.active_count
p Web::MODULE
p Web::PRODUCER

Phi::APPLICATION.on_exception = proc{|args|
begin
p 'haun moriq'
p args
rescue
p 'haun thany'
p $!
end
}

def absolute_path(path)
  path.sub!(/\/$/, '/index')
  File.expand_path(Web::BASEDIR + path)
end

@err_info = nil
@htmlext = '.html'
@rubyext = '.rb'

def html_escape(s)
  s.gsub!( /&/, "&amp;" )
  s.gsub!( /</, "&lt;" )
  s.gsub!( />/, "&gt;" )
  s.gsub!( /"/, "&quot;" )
  s.gsub!( /%link:(.*?)%/ ){ src=$1.strip; %%<a href="#{src}">#{src}</a>% }
  s
end

def error_notify
  html_file = absolute_path('/error') + @htmlext
  Web::PRODUCER.html_file = html_file
end

def erb_exec(src)
  # Erb use Ruby Threads but ERbLight not use.
  erb = ERbLight.new(src)
  Web::PRODUCER.html_doc.text = erb.result(binding)
  if @E
    @err_info = "error: #{html_escape(@E.to_s)}(#{@E.type})\n"
    @E.backtrace.each{|str|
      @err_info+= "\t#{html_escape(str)}\n"
    }
    erb.src.each_with_index{|line, index|
      @err_info+= "#{index+1}: #{html_escape(line)}"
    }
    error_notify
  end
end

def set_html_file(html_file)
  begin
    require 'erb/erbl'
    erb_exec <<'EOT_begin' + open(html_file){|f| f.read } + <<'EOT_end'
<% begin %>
EOT_begin
<% rescue SystemExit
     #
   rescue Phi::DelphiError
  if Web.debug
     @E = $!
#    @ro.send_response
#    exit!
  else
     # BUG??
     # @ro.send_redirect @ri.script_name + @ri.path_info
     # redirect '_'
#    error_notify
#    @ro.send_response
#    exit!
  end
   rescue Exception
     @E = $!
   end   %>
EOT_end
  rescue LoadError
    # erb not installed
    Web::PRODUCER.html_file = html_file
  end
end

def html_dispatch(path)
  html_file = absolute_path(path) + @htmlext
  puts "HTML File: %link:#{html_file}%"
  if test ?e, html_file
    set_html_file(html_file)
  else
    @err_info = "#{html_file} not exist"
    error_notify
  end
end

def ruby_dispatch(path)
  rubyfile = absolute_path(path) + @rubyext
  puts "Ruby File: %link:#{rubyfile}%"
  if test ?e, rubyfile
  # load rubyfile  # BUG??
    eval(open(rubyfile).read, TOPLEVEL_BINDING)
  end
end

def set_useful_ivars
p @mod = Web::MODULE
p @ri = @mod.request
p @ro = @mod.response
p @contents = @ri.content_fields.to_hash.reject{|key, val| val.empty?}
p @cookies  = @ri. cookie_fields.to_hash.reject{|key, val| val.empty?}
p @queries  = @ri.  query_fields.to_hash.reject{|key, val| val.empty?}
  case @ri.method_type
  when Web::MT_GET
    @rh = @queries
  when Web::MT_POST
    @rh = @contents
  end
end

def redirect(path)
  @ro.send_redirect \
    @ri.script_name +
    File.join(File.dirname(@ri.path_info), path)
end

def create_new_logfile
  open(Web::OUTPATH, 'w'){|f|
    # for create new file
    f.print ": create_new_logfile\n"
  }
end

Web::MODULE.before_dispatch = proc {
  |sender, handled, request, response|
  create_new_logfile
  set_useful_ivars
  begin
    no_cache(response)
    path = request.internal_path_info
    html_dispatch(path)
    ruby_dispatch(path)
  rescue SystemStackError
    exit!
# rescue SystemExit
#   #
# rescue Exception
#   p $!
  end
# GC.start
  nil # return handled param
}

def reset_html_file
  Web::PRODUCER.html_file = ''
end

def error_reset
  @E = nil
  @err_info = nil
end

Web::MODULE.after_dispatch = proc {
  |sender, handled, request, response|
  begin
    response.content = <<EOT +
<pre>#{html_escape(open(Web::OUTPATH).read)}</pre>
EOT
    response.content if Web.debug
    reset_html_file
    error_reset
  rescue SystemStackError
    exit!
# rescue SystemExit
#   #
# rescue Exception
#   p $!
  end
# GC.start
  nil # return handled param
}

Web::PRODUCER.on_html_tag = proc {
  |sender, replace, spec, name, params|
  case name
  when 'date'
    Time.now.to_s
  when 'err_info'
    @err_info || "error: #{html_escape($!.to_s)}(#{$!.type})"
  else
    nil
  end
}
