#!/usr/bin/ruby1.8
# Copyright (C) 2004 Gregoire Lejeune <gregoire.lejeune@free.fr>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA

require 'net/smtp'
#require 'stringio'
require 'asp'
require 'asp/common'
#require 'asp/goto'

class ASPCGI
  def initialize( f, fname = "-" )
    @file = fname
    @asp = nil
	@request = nil
    @body = ''
    @head = {}
    @xBody = ""
	@bHeaderSend = false
    begin
      @src = read_script(f)
	rescue => e
	  @src = ""
	end
  end
  attr_accessor(:file)
  attr_accessor(:asp)
  attr_accessor(:request)
  attr_accessor(:body)
  attr_accessor(:head)
  attr_reader(:src)

  def put
    run_state = 0
    if @body.nil? == true
	  debug(@request, Asp::compiler.error_code, @file, run_state, sprintf( "Line %d : %s", Asp::compiler.error_line, Asp::compiler.error_message ) )
	end
	begin
	  run_state = 1
      get_body
	  run_state = 2
      put_head
	  run_state = 3
      prerun
	  run_state = 4
      put_body
	  run_state = 5
      postrun
	rescue LoadError, NoMethodError => e
	  debug(@request, Asp::compiler.error_code, @file, run_state, e.message )
	end
  end

  private
  def read_script(f)
    cmd = f.gets        # #!/usr/local/bin/ruby ...
    src = f.read
    src = cmd + src unless cmd =~ /^#/
    raise 'source: not found' unless src
    src
  end

  def put_head
    xContentType = $Response.contentType or "text/html"
    @head.each do |k, v|
	  if k == 'Content-Type'
	    xContentType = v
	  else
        if String( v.class ) == "Array"
          v.each{ |vv|
            $stderr.puts "[ARR] #{k}: #{vv}\r\n"
            puts "#{k}: #{vv}\r\n"
          }
        else
          $stderr.puts "[DBG] #{k}: #{v}\r\n"
          puts "#{k}: #{v}\r\n"
		  if k == "location"
		    $stderr.puts "[DBG] Status: #{@request.status}\r\n"
		    puts "Status: #{@request.status}\r\n"
		  end
        end
	  end
    end
	$stderr.puts "[DBG] Content-Type: #{xContentType}\r\n"
	puts "Content-Type: #{xContentType}\r\n"
    puts "\r\n"
	
	@bHeaderSend = true
  end

  def prerun
    if @asp.public_methods.member?( "script_OnStart" ) == true
      @asp.script_OnStart
    end
  end

#  def redirect
#    orig_defout = $stdout
#    $stdout = StringIO.new
#    frame_start
#    label(:a){
#      yield
#    }
#    label(:e) {}
#    frame_end
#    $stdout.string
#  ensure
#    $stdout = orig_defout
#  end
#  # evalstr = 'puts "this is the string"'
#  # outputStr = redirect { eval evalstr }
#  # p outputStr

  def put_body
    print @xBody
  end
  
  def get_body
#    @xBody = redirect { eval @body }
    @xBody = Asp::Common::redirect { eval @body }
    
    ## Act: Get Head Data
    $Response.getHeader.each_pair{ |key,value|
      @head[key] = value
    }
    @head['Set-Cookie'] = Array::new()
    $Response.addCookiesHeader.each { |cookie|
      @head['Set-Cookie'].push( cookie )
    }
    sessionCookie = $Session.addSessionCookieHeader
    if sessionCookie.nil? == false
      @head['Set-Cookie'].push( sessionCookie )
    end
	#@head['Content-Type'].push( $Response.contentType ) if $Response.contentType.nil? == false and $Response.contentType.length > 0

	$stderr.puts( "[DBG - get_body] : $Response.contentType = #{$Response.contentType}\r\n" )
  end
  
  def postrun
    if @asp.public_methods.member?( "script_OnEnd" ) == true
      @asp.script_OnEnd
    end
  end

  public
  def debug(r, code, filename, run_state, message)
      
    error_page  = Asp::Common::getEnv( "ErrorFile" )
    smtp_server = Asp::Common::getEnv( "MailHost" )
    smtp_port   = Asp::Common::getEnv( "MailPort" ) || 25
    smtp_from   = Asp::Common::getEnv( "MailErrorsFrom" )
    smtp_to     = Asp::Common::getEnv( "MailErrorsTo" )
    mail_send   = false
  
    if Asp::Common::debug == 1 
      result = r.escape_html(message)
      r.server.log_error( "[Ruby/ASP] [%d] : (%s) : %s", $$, __FILE__, result )
    end
    
    if smtp_server.nil? == false and smtp_from.nil? == false and smtp_to.nil? == false
      smtp = Net::SMTP.new( smtp_server, smtp_port )
      smtp.start()
      smtp.ready( smtp_from, smtp_to ) do |m|
        m.write "From: \"WWW Error Report\" <#{smtp_from}>\r\n"
        m.write "To: \"WWW Error Reporting\" <#{smtp_to}>\r\n"
        m.write "Subject: WWW Error Report: #{r.unparsed_uri}\r\n"
        m.write "\r\n"
        m.puts "Ruby/Asp v#{Asp::Common::version}"
        m.puts "ERROR State ##{run_state} : " + message
        m.puts "----------------------------------------------------------"
        m.puts "File " + filename
        m.puts "----------------------------------------------------------"
        i = 0
        code.each_line { |l|
          i += 1
          m.puts( format( "%04d : %s", i, l.chomp ) )
        }
        m.puts "----------------------------------------------------------"
      end # smtp.ready()
  
      mail_send = true
    end
  
    if error_page.nil? == true
	  if @bHeaderSend == false
	    put_head
	  end

      print "<DIV STYLE='background-color: #ffffff; font-family: sans-serif; border: 1px solid #646464; margin-left: 1em; margin-right: 2em; padding: 0.5em;'>\n"
      print "<B>Ruby/Asp v",Asp::Common::version,"</B><BR>\n"
      print "ERROR State #",run_state," : \n"
      print "<B>",r.escape_html(message),"</B><BR>\n"
      print "<PRE STYLE='background-color: #e6e6e6; border: 1px solid #646464; margin-left: 1em; margin-right: 2em; padding: 0.5em;'>\n"
      print "<B>File ",r.uri,"</B>\n"
      i = 0
      r.escape_html(code).each_line { |l|
        i += 1
        printf( "%04d : %s\n", i, l.chomp )
      }
      print "</PRE>\n"
      print "Bad things happened. An email has been sent to #{smtp_to} with diagnostic information and details of your request.\n" if mail_send == true
      print "</DIV>\n"
    else
      r.status = 302
      @head["location"] = error_page
      put_head
    end
  
    exit( 0 )
  end

end

if __FILE__ == $0
  btime = Time::now

  begin
    fname = ARGV[0]
    f = $<
    if ENV['PATH_TRANSLATED']
      f = open( ENV['PATH_TRANSLATED'] )
      fname = f.path
      $:.unshift(File.dirname(ENV['PATH_TRANSLATED']))
    elsif ENV['SCRIPT_FILENAME']
      $:.unshift(File.dirname(ENV['SCRIPT_FILENAME']))
    end

    xConfFile = File::dirname( fname ) + "/asp.conf"
    load( xConfFile )
    Config.each{ |k, v|
      ENV[k] = v
    }

    Dir::chdir( File::dirname( fname ) )
    
    _asp = ASPCGI.new( f, fname )
    Asp::serve( _asp )
    _asp.put
  rescue NoMethodError, TypeError => e
    _asp.debug( _asp.request, _asp.body, fname, -1, e.message)
  end
  etime = Time::now
  ctime = etime - btime
  printf( "<!-- Ruby/ASP-CGI v%s served page in %s seconds -->\n", Asp::Common::version, ctime )
end
