#!/usr/bin/ruby -w
##
## SMB Search: EstraierPure extension
## Copyright (c) 2007 OSS Technology Co., Japan
##                    <http://www.osstech.co.jp/>
##
## Date: 2007-06-18, since 2007-06-18
## Author: SATOH Fumiyasu
##

require 'estraierpure'
require 'time'
require 'digest/sha1'

module EstraierPure

## NodeMaster class
## ======================================================================

  class NodeMaster < Node
    def list_node
      @status = -1
      return nil unless @url
      reqheads = [ "Content-Type: application/x-www-form-urlencoded" ]
      reqheads.push("Authorization: Basic " + Utility::base_encode(@auth)) if @auth
      reqbody = "action=nodelist"
      resbody = StringIO::new
      rv = Utility::shuttle_url(@url, @pxhost, @pxport, @timeout, reqheads, reqbody, nil, resbody)
      @status = rv
      return nil if rv != 200
      nodes = Array.new
      resbody.rewind
      resbody.each do |line|
	name, label, doc_num, word_num, size = line.chomp.split(/\t/)
	nodes.push(get_node(name))
      end
      return nodes
    end

    def get_node(name)
      Utility::check_types({ name=>String }) if $DEBUG
      node = Node.new
      node.set_url(@url.sub(/\w+$/, 'node/') + CGI::escape(name))
      node.set_auth(*@auth.split(/:/, 2)) if @auth
      node.set_timeout(@timeout) if @timeout
      node.set_proxy(@pxhost, @pxport) if @pxhost && @pxport
      return node
    end

    def add_node(name, label)
      Utility::check_types({ name=>String, label=>String }) if $DEBUG
      @status = -1
      return nil unless @url
      reqheads = [ "Content-Type: application/x-www-form-urlencoded" ]
      reqheads.push("Authorization: Basic " + Utility::base_encode(@auth)) if @auth
      reqbody = "action=nodeadd&name=" + CGI::escape(name) + "&label=" + CGI::escape(label)
      rv = Utility::shuttle_url(@url, @pxhost, @pxport, @timeout, reqheads, reqbody, nil, nil)
      @status = rv
      return rv == 200
    end

    def clear_node(name)
      Utility::check_types({ name=>String }) if $DEBUG
      @status = -1
      return nil unless @url
      reqheads = [ "Content-Type: application/x-www-form-urlencoded" ]
      reqheads.push("Authorization: Basic " + Utility::base_encode(@auth)) if @auth
      reqbody = "action=nodeclr&name=" + CGI::escape(name)
      rv = Utility::shuttle_url(@url, @pxhost, @pxport, @timeout, reqheads, reqbody, nil, nil)
      @status = rv
      return rv == 200
    end

    def delete_node(name)
      Utility::check_types({ name=>String }) if $DEBUG
      @status = -1
      return nil unless @url
      reqheads = [ "Content-Type: application/x-www-form-urlencoded" ]
      reqheads.push("Authorization: Basic " + Utility::base_encode(@auth)) if @auth
      reqbody = "action=nodedel&name=" + CGI::escape(name)
      rv = Utility::shuttle_url(@url, @pxhost, @pxport, @timeout, reqheads, reqbody, nil, nil)
      @status = rv
      return rv == 200
    end

    ## FIXME
    #def list_user
    #Request: http://localhost:1978/master?action=userlist
    #Response (TSV): name password flags fname(fullname) misc
    #end

    def add_user(name, pass, *opts)
      Utility::check_types({ name=>String, pass=>String }) if $DEBUG
      @status = -1
      return nil unless @url
      reqheads = [ "Content-Type: application/x-www-form-urlencoded" ]
      reqheads.push("Authorization: Basic " + Utility::base_encode(@auth)) if @auth
      reqbody = "action=useradd&name=#{CGI::escape(name)}&passwd=#{CGI::escape(pass)}"
      reqbody += "&flags=#{CGI::escape(opts[0])}" if opts[0]
      reqbody += "&fname=#{CGI::escape(opts[1])}" if opts[1]
      reqbody += "&misc=#{CGI::escape(opts[2])}" if opts[2]
      rv = Utility::shuttle_url(@url, @pxhost, @pxport, @timeout, reqheads, reqbody, nil, nil)
      @status = rv
      return rv == 200
    end

    def delete_user(name)
      Utility::check_types({ name=>String }) if $DEBUG
      @status = -1
      return nil unless @url
      reqheads = [ "Content-Type: application/x-www-form-urlencoded" ]
      reqheads.push("Authorization: Basic " + Utility::base_encode(@auth)) if @auth
      reqbody = "action=userdel&name=" + CGI::escape(name)
      rv = Utility::shuttle_url(@url, @pxhost, @pxport, @timeout, reqheads, reqbody, nil, nil)
      @status = rv
      return rv == 200
    end

    def sync
      @status = -1
      return nil unless @url
      reqheads = [ "Content-Type: application/x-www-form-urlencoded" ]
      reqheads.push("Authorization: Basic " + Utility::base_encode(@auth)) if @auth
      reqbody = "action=sync"
      rv = Utility::shuttle_url(@url, @pxhost, @pxport, @timeout, reqheads, reqbody, nil, nil)
      @status = rv
      return rv == 200
    end

    def rotate_log
      @status = -1
      return nil unless @url
      reqheads = [ "Content-Type: application/x-www-form-urlencoded" ]
      reqheads.push("Authorization: Basic " + Utility::base_encode(@auth)) if @auth
      reqbody = "action=logrtt"
      rv = Utility::shuttle_url(@url, @pxhost, @pxport, @timeout, reqheads, reqbody, nil, nil)
      @status = rv
      return rv == 200
    end

    def backup
      @status = -1
      return nil unless @url
      reqheads = [ "Content-Type: application/x-www-form-urlencoded" ]
      reqheads.push("Authorization: Basic " + Utility::base_encode(@auth)) if @auth
      reqbody = "action=backup"
      rv = Utility::shuttle_url(@url, @pxhost, @pxport, @timeout, reqheads, reqbody, nil, nil)
      @status = rv
      return rv == 200
    end
  end

  class Node
    def self.name_for_uri(uri)
      uri.downcase!
      unless match = uri.match(%r#^([^/:]+)://([^/]+)#)
	raise "invalid URI: #{uri}"
      end
      ## FIXME: How to avoid node_name conflict?
      return "#{match[1]}-#{match[2]}-#{Digest::SHA1.hexdigest(uri)}"
    end

    def set_url_for_uri(node_url, uri)
      return set_url("#{node_url}/#{CGI.escape(Node.name_for_uri(uri))}")
    end

    def get_doc_attr_int(id, name)
      value = self.get_doc_attr(id, name)
      return value ? value.to_i : nil
    end

    def get_doc_attr_time(id, name)
      value = self.get_doc_attr(id, name)
      return value ? Time.xmlschema(value) : nil
    end
  end

  class Document
    def attr_int(name)
      value = self.attr(name)
      return value ? value.to_i : nil
    end

    def attr_time(name)
      value = self.attr(name)
      return value ? Time.xmlschema(value) : nil
    end

    def add_attr_int(name, value)
      return self.add_attr(name, value.to_s)
    end

    def add_attr_time(name, value)
      return self.add_attr(name, value.utc.xmlschema)
    end
  end
end

