#!/usr/bin/env ruby
#  Copyright (C) 1999 Kikutani Makoto <g@kondara.org>
#  Copyright (C) 2000 Kondara Project <http://www.kondara.org>
#
#  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 "parsearg"
require "slang"
include Slang

Xinit = '/etc/X11/xinit'
Outs = ['lang', 'xim', 'session']
Outdir = File.expand_path('~/.xinit.d')

$deflt_vars = {}
$mouse_region = []
$selecters = []

$files = {}
$cbs = {}
$labels = {}
$labels['lang'] = 'Language'
$labels['xim'] = 'Input Method'
$labels['session'] = 'Session'
$hash = {}
$hash2 = {}

  def save
    # unless FileTest.directory?(Outdir)
    #  len, str = sl_read_mini(sprintf("want to create %s ? (Y/n)", Outdir))
    #  if len == 0 or str !~ /^[Nn]/
    #    Dir.mkdir(Outdir)
    #  end
    # end
    Outs.each do |category|
      v = $cbs[category].entry.text
      outpath = Outdir + '/' + category
      open(outpath, "w") do |out|
        printf(out, "%s\n", $hash2[v])
      end
    end
  end

  def about
    d = Gtk::Dialog::new()
    d.set_title("About")

    mtextwin = Gtk::ScrolledWindow.new(nil,nil)
    d.vbox.pack_start(mtextwin, TRUE, TRUE, 0)
    mtextwin.show

    mtext = Gtk::TextView.new(nil)
    mtext.editable = false
    mtextwin.add(mtext)
    mtext.buffer.insert(mtext.buffer.get_iter_at_offset(0),
                   "SDR 0.9.5\n" +
                   "Copyright (C) 1999 Kikutani Makoto <g@kondara.org>\n" +
                   "Copyright (C) 2000 Kondara Project <http://www.kondara.org>\n" +
                   "\n" +
                   "This program is free software; you can redistribute it and/or modify\n" +
                   "it under the terms of the GNU General Public License as published by\n" +
                   "the Free Software Foundation; either version 2 of the License, or\n" +
                   "(at your option) any later version.\n" +
                   "\n" +
                   "This program is distributed in the hope that it will be useful,\n" +
                   "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +
                   "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" +
                   "GNU General Public License for more details.\n" +
                   "\n" +
                   "You should have received a copy of the GNU General Public License\n" +
                   "along with this program; if not, write to the Free Software\n" +
                   "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n" +
                   "\n" +
                   "$Id: sdr.rb,v 1.34 2000/11/02 03:57:24 g Exp $\n")
    mtext.show

    button = Gtk::Button::new("OK")
    d.action_area.pack_start(button, TRUE, TRUE, 0)
    button.signal_connect("clicked") { Gtk::main_quit() }
    button.set_flags(Gtk::Widget::CAN_DEFAULT)
    button.grab_default
    button.show

    d.set_default_size(640, 480)
    d.show
  
    d.set_modal(TRUE);
    Gtk.main
    d.destroy
  end

  def gtkmain
    Outs.each do |f|
      inpath = Outdir + '/' + f
      begin
        dflt = nil
        open(inpath, "r") do |inp|
          dflt = inp.read.chop
        end
        $deflt_vars[f] = dflt
      rescue
        # do nothing
      end
    end

    w = Gtk::Window::new(Gtk::Window::TOPLEVEL)
    w.set_default_size(384, 240)
    w.signal_connect("delete_event") { exit }
    w.signal_connect("destroy") { exit }
    w.set_title("SDR")
#    w.set_policy(false, true, false)

    main = Gtk::VBox::new(false, 0)
    main.set_border_width(1)
    w.add(main)
    main.show

    menubar = Gtk::MenuBar::new()
    main.pack_start(menubar, false, true, 0)
    menubar.show

    menu = Gtk::Menu::new()
    menuitem = Gtk::MenuItem::new("File")
    menuitem.set_submenu(menu)
    menubar.append(menuitem)
    menuitem.show

    menuitem = Gtk::MenuItem::new("Exit")
    menuitem.signal_connect("activate") { exit }
    menu.append(menuitem)
    menuitem.show
    menu.show

    menu3 = Gtk::Menu::new()
    menuitem3 = Gtk::MenuItem::new("Help")
    menuitem3.set_submenu(menu3)
    menubar.append(menuitem3)
    menuitem3.show
    
    menuitem3 = Gtk::MenuItem::new("About SDR...")
    menuitem3.signal_connect("activate") { about }
    menu3.append(menuitem3)
    menuitem3.show
    menu3.show

    table = Gtk::Table::new(3, 2, FALSE)
    table.set_row_spacings(20)
    table.set_column_spacings(30)
    table.set_border_width(20)

    main.pack_start(table, true, true, 0)
    table.show

    i = 0
    Outs.each do |category|
      label = Gtk::Label::new($labels[category])
      label.set_alignment(0, 0.5)
      table.attach(label, 0, 1, i, i + 1, Gtk::FILL, Gtk::FILL, 0, 0)
      label.show

      $cbs[category]= Gtk::Combo::new()
      table.attach($cbs[category], 1, 2, i, i + 1, nil, nil, 0, 0)
      $cbs[category].show
      i = i + 1
    end

    hsep = Gtk::HSeparator::new()
    main.pack_start(hsep, false, false, 0)
    hsep.show

    hbox = Gtk::HButtonBox::new()
    hbox.set_border_width(10)
    main.pack_start(hbox, false, false, 0)
    hbox.show

    button = Gtk::Button::new("OK")
    button.signal_connect("clicked") { save(); exit }
    hbox.add(button)
    button.set_flags(Gtk::Widget::CAN_DEFAULT)
    button.grab_default
    button.show

    button = Gtk::Button::new("Cancel")
    button.signal_connect("clicked") { exit }
    hbox.pack_end(button, true, true, 0)
    button.set_flags(Gtk::Widget::CAN_DEFAULT)
    button.show

    Outs.each do |category|
      $files[category] = []
      if /^session$/ =~ category then
        f = "UserDefined"
      else
        f = "None"
      end
      $files[category] << f
      $hash[f] = f
      $hash2[f] = f;
      Dir.foreach(Xinit + '/' + category + '.d') do |f|
        next if f == '.' or f == '..'
        name = f
        ifexists = []
        File.foreach(Xinit + '/' + category + '.d/' + f) do |line|
          if /^NAME="(.*)"$/ =~ line then
            name = $1
          elsif /^NAME=(.*)$/ =~ line then
            name = $1
	  elsif /^IFEXISTS="(.*)"$/ =~ line then
	    ifexists = $1.split(/:/)
          elsif /^IFEXISTS=(.*)$/ =~ line then
	    ifexists = $1.split(/:/)
	  end
        end
        next if ifexists.find{|ff| !FileTest.exist?(ff)}
	$files[category] << name
	$hash[f] = name;
	$hash2[name] = f;
      end
      $files[category].sort!
      $cbs[category].set_popdown_strings($files[category])
      if $deflt_vars.has_key?(category)
	if dflt = $hash[$deflt_vars[category]]
	  $cbs[category].entry.set_text(dflt) if dflt != nil
	end
      end
    end

    main.show
    w.show
    Gtk::main()
  end

class Help < Pager
  def initialize(r0,r1,c0,c1)
    @help_japanese = [
  "  q                      sdrνλ(ѹ򥻡֤뤫ʹ)",
  "",
  "ޥ",
  "  ܥ               ",
  "",
  "  k, 奫          ˰ư",
  "  j,           ˰ư",
  "",
  "  /                      ",
  "  n                      Υ",
  "",

  "  h                      ΥإפФ",
  "",
  "*Note:  ХݡȤϡg@kondara.orgľ뤫",
  "  Ǽ(http://www.kondara.org/bbs/kondara.html)ޤǤꤤޤ"
  ]

    @help_english = [
  "  q                      quit sdr(be asked whether you want to save or not)",
  "",
  "Mouse",
  "  left button            select",
  "",
  "  k, up-cursor           move to the previous line and select",
  "  j, down-cursor         move to the next line and select",
  "",
  "  /                      search",
  "  n                      search next",
  "",
  "  h                      this help",
  "",
  "*Note:  please send your bug reports or questions to g@kondara.org",
  "   or write to Kondara-BBS (http://www.kondara.org/bbs/kondara.html)"
  ]
    super(r0,r1,c0,c1)
  end

  def build_lines
    if ENV['LANG'].nil? or ENV['LANG'] != 'ja_JP.eucJP'
      help = @help_english
    else
      help = @help_japanese
    end
    num_lines = 0;
    help.each{|s|
      return FALSE unless add_line(s)
    }
    init_lines
    return TRUE;
  end

  def draw_bottom
    r = @rmax
    c = @cmin
    slsmg_gotorc(r, c)
    reverse_color
    slsmg_write_string("Press 'q' to continue.")
    slsmg_erase_eol
  end

  def special_key_actions    
    key_actions_add([?q]) do
      @do_break = true
    end
  end
end

def redraw
  slsmg_gotorc(0,0)
  slsmg_set_color(SL_BG_BLUE + SL_YELLOW)
  slsmg_write_string(sprintf(
      "Sdr: q:Save/Quit <tab>:move category h:Help [%s]", Outdir))
  slsmg_erase_eol
  slsmg_set_color(SL_BG_LGRAY + SL_BLACK)
  slsmg_gotorc(sltt_screen_rows-1, 0)
  slsmg_erase_eol
end
    
class Selector < Pager
  OFFSET = 2
  Q_ROW = 0
  Q_COL_MIN = 6
  Q_COL_MAX = 16

  def initialize(c0, c1, d)
    @d = d  + '.d'
    @files = []
    @selected = nil
    super(OFFSET, sltt_screen_rows-OFFSET, c0, c1)
    @inhibit_horiz_scroll = true
    set_cursor(TRUE, OFFSET, sltt_screen_rows - OFFSET - 1)
    set_mini_buffer(false)
    set_bar(1)
    if $deflt_vars.has_key?(d) and (v = $deflt_vars[d])
      if r = @files.index(v)
	if @current_row + r <= @cursor_max 
	  @current_row = r + OFFSET
	else
	  (1..r).each do 
	    scroll_next_n(1)
	  end
	end	  
      else
	
      end
    end
    choose()
  end

  attr :selected
  attr :current_row, true

  def build_lines
    names = []
    if /^session.d$/ =~ @d then
      f = "UserDefined"
    else
      f = "None"
    end
    names << [f, f]
    Dir.foreach(Xinit + '/' + @d) do |f|
      next if f == '.' or f == '..'
      name = f
      ifexists = []
      File.foreach(Xinit + '/' + @d + '/' + f) do |line|
        if /^NAME="(.*)"$/ =~ line then
          name = $1
        elsif /^NAME=(.*)$/ =~ line then
          name = $1
	elsif /^IFEXISTS="(.*)"$/ =~ line then
	  ifexists = $1.split(/:/)
        elsif /^IFEXISTS=(.*)$/ =~ line then
	  ifexists = $1.split(/:/)
	end
      end
      next if ifexists.find{|ff| !FileTest.exist?(ff)}
      names << [name, f]
    end
    names.sort!{|a, b| a[0] <=> b[0]}
    @files = names.collect{|a| a[1]}
    names.each do |a|
      add_line(a[0])
    end
    init_lines
    # @selected = @files[0]
  end
  
  def draw_bottom
    slsmg_gotorc(@rmin-1, @cmin)
    slsmg_set_color(SL_BG_COLORS+SL_GREEN+SL_BLACK)
    slsmg_printf(sprintf("        %s", @d))
    slsmg_erase_eol2(@cmax, 1)
    normal_color
    slsmg_gotorc(@rmax, @cmin)
    reverse_color
    slsmg_printf(@selected ? File.basename(@selected) : '' )
    slsmg_erase_eol2(@cmax, 1)
    normal_color
  end
  
  def choose
    num = line_num() + @current_row - OFFSET - 1
    f = @files[num]
    if f
      @selected = f
    end
  end

  def special_key_actions    
      key_actions_add([SL_KEY_UP, PAGER_KEY_UP]) do
	back_scr
	choose
      end

      key_actions_add([SL_KEY_DOWN, PAGER_KEY_DOWN]) do
	forw_scr
	choose
      end

    key_actions_add([SL_MOUSE_B0]) do # LEFT buttun
      c, r = sl_get_mouse_rc
      if r == Q_ROW and
         (Q_COL_MIN <= c and c <= Q_COL_MAX)
        @do_break = true
        $move = nil
      elsif r < @rmax and r >= @rmin
	if $mouse_region[c] == self
	  if  @files[line_num() + r - OFFSET - 1]
	    @current_row = r
	    choose
	  end
	elsif (s = $mouse_region[c]) # other category ?
	  $jump = s
	  $jump_row = r
	  @do_break = true
	end
      end
    end

    key_actions_add([SL_KEY_HOME, PAGER_BOB]) do
      goto_bob
      choose
    end

    key_actions_add([SL_KEY_END, PAGER_EOB]) do
      goto_eob
      choose
    end

    key_actions_add([SL_KEY_NPAGE, PAGER_NPAGE]) do
      next_page
      choose
    end
    
    key_actions_add([SL_KEY_PPAGE, PAGER_PPAGE]) do
      prev_page
      choose
    end

    key_actions_add([PAGER_SEARCH_FWD]) do
      begin
	do_search_fwd
	slsmg_gotorc(sltt_screen_rows - 1, 0)
	slsmg_erase_eol 
      rescue SlangSearch
	sl_put_mini_message("not found", TRUE)
      end
      choose
    end

    key_actions_add([PAGER_SEARCH_NEXT]) do
      begin
	do_search_next(TRUE)
      rescue SlangSearch
	sl_put_mini_message("not found", TRUE)
      end
      choose
    end
    
    key_actions_add([0x9]) do # TAB
      @do_break = true
      $move = true
    end

    key_actions_add([?q]) do
      @do_break = true
      $move = nil
    end

    key_actions_add([?h]) do
      $help_win.main_loop
      redraw
      $selecters.each{|s| s.update_display}
    end

    key_actions_add([0xc]) do # CTL_L redraw
      slsmg_cls
      redraw
      $selecters.each{|s| s.update_display}
    end
  end
end

def slangmain
  mouse_on
  exit unless init_terminal(1, 1)
  
  # slkp_define_keysym("q", PAGER_QUIT)
  slkp_define_keysym("b", PAGER_PPAGE)
  slkp_define_keysym("k", PAGER_KEY_UP)
  slkp_define_keysym("j", PAGER_KEY_DOWN)
  slkp_define_keysym("\033[M\040", SL_MOUSE_B0)
  slkp_define_keysym("/", PAGER_SEARCH_FWD)
  slkp_define_keysym("n", PAGER_SEARCH_NEXT)
  
  # read initial value from users' directory
  Outs.each do |f|
    inpath = Outdir + '/' + f
    begin
      dflt = nil
      open(inpath, "r") do |inp|
	dflt = inp.read.chop
      end
      $deflt_vars[f] = dflt
    rescue
      # do nothing
    end
  end
  
  $help_win = Help.new(0, sltt_screen_rows-1, 0, sltt_screen_cols-1)
  
  w = sltt_screen_cols / Outs.size
  out_sels = {}
  wl = 0
  Outs.each do |f|
    $selecters << (s = Selector.new(wl, wl+w, f))
    s.update_display
    out_sels[f] = s
    (wl..wl+w).each {|i| $mouse_region[i] = s}
    wl += w + 2
  end
  
  redraw
  
  grp = 0
  while true
    $move = nil
    $jump = nil
    $selecters[grp].main_loop
    break if $move.nil? and $jump.nil?
    if $move
      grp += 1
      grp = 0 if grp >= $selecters.size
    elsif $jump
      if n = $selecters.index($jump)
	grp = n
	$jump.current_row = $jump_row
	$jump.choose
      end
    end
  end

  save = nil
  # check if changed from old value
  n = 0
  Outs.each do |f|
    if $deflt_vars[f] != $selecters[n].selected
      save = true
      break
    end
    n += 1
  end

  if save
    len, str = sl_read_mini("Really want to write ? (Y/n)")
    if len == 0 or str !~ /^[Nn]/
      unless FileTest.directory?(Outdir)
	len, str = sl_read_mini(sprintf("want to create %s ? (Y/n)", Outdir))
	if len == 0 or str !~ /^[Nn]/
	  Dir.mkdir(Outdir)
	end
      end
      out_sels.each do |k, v|
	outpath = Outdir + '/' + k
	open(outpath, "w") do |out|
	  printf(out, "%s\n", v.selected)
	end
      end
    end
  end
  sl_reset
end

def show_usage()
  printf("Usage: %s [-c]\n", $0)
  printf("Option:
	-c        console(force slang interface)\n")
end
$USAGE='show_usage'
parseArgs(0, nil, "c")

gtk = nil

begin
  gtk = true if ENV['DISPLAY'] =~ /.+/
rescue
  # do nothing
end

if $OPT_c or gtk.nil?
  slangmain
else
  require 'gtk2'
  Gtk.init
  gtkmain
end
