require "time"
require "uri"

module Web
  class Agent
    class Hina_di
      include Enumerable
      def initialize
        @user_agent = "NoraAgent/0.1"
        @content_type = nil
        @date = nil
        @records = []
      end
      attr_accessor :user_agent, :date, :records

      def each
        @records.each {|rec|
          yield rec
        }
      end

      def merge(hina)
        hina.each {|rec|
          my_rec = @records.find() {|r|
            rec.url == r.url
          }
          if my_rec
            if rec.last_modified > my_rec.last_modified
              my_rec.url = rec.url
              my_rec.hina_version = rec.hina_version
              my_rec.virtual = rec.virtual
              my_rec.content_type = rec.content_type
              my_rec.date = rec.date
              my_rec.title = rec.title
              my_rec.author_name = rec.author_name
              my_rec.expires = rec.expires
              my_rec.expire = rec.expire
              my_rec.last_modified = rec.last_modified
              my_rec.last_modified_detected = rec.last_modified_detected
              my_rec.server = rec.server
              my_rec.authorized = rec.authorized
              my_rec.authorized_url = rec.authorized_url
              my_rec.method = rec.method
              my_rec.keyword = rec.keyword
              my_rec.image_width = rec.image_width
              my_rec.image_height = rec.hina_version
            end
          else
            @records << rec
          end
        }
      end
      
      def parse(io)
        # Header-block
        hina = io.gets
        raise SyntaxError unless hina=~/\AHINA\/[0-9a-z\.]+\r?\n/nm
        while text=io.gets
          case text
          when /\A\r?\n\z/
            break
          when /\AContent-Type:\s*(Content-Type:\s*[a-z]+\/[0-9a-z\-\_]+)\r?\n\z/imn
            @content_type = $1
          when /\ADate:\s*([0-9a-z\/:\-]+)\r?\n\z/imni
            @date = $1
          when /\AUser-Agent:\s*([^\x00-\x08\x0a-\x20\x7f]+)\r?\n\z/imn
            @user_agent = $1
          end
        end
        # Entity-block
        record = nil
        while text=io.gets
          case text
          when /\A\r?\n\z/in
            @records << record if record
            record = nil
          when /\AURL:\s*(.+)\r?\n\z/in
            record = Record.new unless record
            record.url = URI.parse($1).normalize.to_s
          when /\AHINA-Version:\s*(HINA\/\d+\.\d+)\r?\n\z/in
            record = Record.new unless record
            record.hina_version = $1
          when /\AVirtual:\s*(.+)\r?\n\z/in
            record = Record.new unless record
            record.virtual=$1
          when /\AContent-Type:\s*(.+)\r?\n\z/in
            record = Record.new unless record
            record.content_type=$1
          when /\ADate:\s*(.+)\r?\n\z/in
            record = Record.new unless record
            record.date=$1
          when /\ATitle:\s*(.+)\r?\n\z/in
            record = Record.new unless record
            record.title=$1
          when /\AAuthor-Name:\s*(.+)\r?\n\z/in
            record = Record.new unless record
            record.author_name=$1
          when /\AExpires:\s*(.+)\r?\n\z/in
            record = Record.new unless record
            record.expires=Time.parse($1)
          when /\AExpire:\s*(.+)\r?\n\z/in
            record = Record.new unless record
            record.expire=Time.parse($1)
          when /\ALast-Modified:\s*(.+)\r?\n\z/in
            record = Record.new unless record
            record.last_modified=Time.parse($1)
          when /\ALast-Modified-Detected:\s*(.+)\r?\n\z/in
            record = Record.new unless record
            record.last_modified_detected=Time.parse($1)
          when /\AServer:\s*(.+)\r?\n\z/
            record = Record.new unless record
            record.server=$1
          when /\AAuthorized:\s*(.+)\r?\n\z/in
            record = Record.new unless record
            record.authorized=$1
          when /\AAuthorized-url:\s*(.+)\r?\n\z/in
            record = Record.new unless record
            record.authorized_url=$1
          when /\AMethod:\s*(.+)\r?\n\z/in
            record = Record.new unless record
            record.method=$1
          when /\AKeyword:\s*(.+)\r?\n\z/in
            record = Record.new unless record
            record.keyword=$1
          when /\AImage-Width:\s*(\d+)\r?\n\z/in
            record = Record.new unless record
            record.image_width=$1.to_i
          when /\AImage-Height:\s*(\d+)\r?\n\z/in
            record = Record.new unless record
            record.image_height=$1.to_i
          end
        end
        @records << record if record
      end # parse
      
      
      def write(io)
        io << "HINA/2.2beta\r\n"
        io << "User-agent:"   << @user_agent   << "\r\n" if @user_agent
        io << "Content-Type:" << @content_type << "\r\n" if @content_type
        io << "Date:"         << @date         << "\r\n" if @date
        io << "\r\n"
        @records.each {|rec|
          io << rec.to_s
        }
      end
      
      def to_s
        s=""
        write(s)
        s
      end
      
      class Record
        def initialize
          @url = nil
          @hina_version = nil
          @virtual = nil
          @content_type = nil
          @date = nil
          @title = nil
          @author_name = nil
          @expires = nil
          @expire = nil
          @last_modified = nil
          @last_modified_detected = nil
          @server = nil
          @authorized = nil
          @authorized_url = nil
          @method = nil
          @keyword = nil
          @image_width = nil
          @image_height = nil
        end
        attr_accessor :url, :hina_version, :virtual, :content_type
        attr_accessor :date, :title, :author_name, :expires, :expire
        attr_accessor :last_modified, :last_modified_detected, :server
        attr_accessor :authorized, :authorized_url, :method, :keyword, :image_width, :image_height
        
        def to_s
          s = ""
          s << "URL:"                    << @url                    << "\r\n" if @url
          s << "HINA-Version:"           << @hina_version           << "\r\n" if @hina_version
          s << "Virtual:"                << @virtual                << "\r\n" if @virtual
          s << "Content-Type:"           << @content_type           << "\r\n" if @content_type
          s << "Date:"                   << @date                   << "\r\n" if @date
          s << "Title:"                  << @title                  << "\r\n" if @title
          s << "Author-Name:"            << @author_name            << "\r\n" if @author_name
          s << "Expires:"                << @expires.strftime('%a, %d %b %Y %H:%M:%S GMT')                << "\r\n" if @expires
          s << "Expire:"                 << @expire.strftime('%a, %d %b %Y %H:%M:%S GMT')                 << "\r\n" if @expire
          s << "Last-Modified:"          << @last_modified.strftime('%a, %d %b %Y %H:%M:%S GMT')          << "\r\n" if @last_modified
          s << "Last-Modified-Detected:" << @last_modified_detected.strftime('%a, %d %b %Y %H:%M:%S GMT') << "\r\n" if @last_modified_detected
          s << "Server:"                 << @server                 << "\r\n" if @server
          s << "Authorized:"             << @authorized             << "\r\n" if @authorized
          s << "Authorized-url:"         << @authorized_url         << "\r\n" if @authorized_url
          s << "Method:"                 << @method                 << "\r\n" if @method
          s << "Keyword:"                << @keyword                << "\r\n" if @keyword
          s << "Image-Width:"            << @image_width.to_s       << "\r\n" if @image_width
          s << "Image-Height:"           << @image_height.to_s      << "\r\n" if @image_height
          s << "\r\n"
        end
      end # Record
    end # Hina_di
  end # Agent
end # Web
