#########################################################################
##                                                                     ##
##  I N T E R S T E L L A R   C O N S O L E                            ##
##            Copyright (C) 2025- Misato Observatory, Wakayama, Japan  ##
##                                                                     ##
##  This software is available under the GPL (General Public License)  ##
##                                                                     ##
#########################################################################

####################################################################
##                                                                ##
##              G E N E R I C   P R O C E D U R E S               ##
##                                                                ##
####################################################################

##                                         ##
## ISC オリジナルのダイアログ              ##
##   -- MacOS のボタンがダメダメな件の対策 ##
##                                         ##

# ダイアログの返り値
set isc_dialog_return_val 0

# これは callback proc で利用する。ダイアログを抜けるときに callback 側で何かを書き込む
set isc_dialog_destroy_flag 0

# private proc (ダイアログ内部専用)
proc set_val_of_isc_dialog { top arg_result } {

  global isc_dialog_return_val

  set isc_dialog_return_val $arg_result

  destroy $top

}

#
# ダイアログを開く (選択肢は4つまで対応)
#  top: 新規のtoplevelウィンドウ名。"" の場合は新規に作らず、
#       既存のメインウィンドウを使用する
#  arg_title: ウィンドウのタイトル文字列
#  arg_msg: メッセージ文字列
#  arg_topmost: -topmost に与える引数 (0 or 1)
#  callback: コールバック関数 ("" を与えると無効)
#  arg_default: デフォルトのボタン (0 から 3)
#  arg_x: ボタン文字列
#
#  【注意】
#    ・進捗状況表示にも使うことができ、その場合には選択肢(arg_0 から arg_3)
#      をすべて "" とする。この場合には、ダイアログを開いてすぐに呼び出し元へ
#      戻るため、呼び出し元で destory すること
#
proc isc_dialog { top arg_title arg_msg arg_topmost callback arg_default arg_0 arg_1 arg_2 arg_3 } {

  global isc_dialog_return_val
  global isc_dialog_destroy_flag

  set isc_dialog_destroy_flag 0

  toplevel $top
  wm title $top $arg_title
  wm resizable $top 0 0

  # 「X」で閉じるとデフォルト値がセットされる
  set isc_dialog_return_val $arg_default

  frame $top.fr_dlg_relief -relief raised -bd [scaled_thick_border 2]

  frame $top.fr_dlg

  label $top.l_dlg -text $arg_msg

  frame $top.fr_dlg_0

  set count_button 0

  if { $arg_0 != "" } {
    ttk::button $top.b_dlg_0 -text $arg_0 -command "set_val_of_isc_dialog $top 0"
    pack $top.b_dlg_0 -side left -expand 1 -padx [scaled_px 12] -in $top.fr_dlg_0
    bind $top.b_dlg_0 <Return> {%W invoke}
    incr count_button
  }

  if { $arg_1 != "" } {
    ttk::button $top.b_dlg_1 -text $arg_1 -command "set_val_of_isc_dialog $top 1"
    pack $top.b_dlg_1 -side left -expand 1 -padx [scaled_px 12] -in $top.fr_dlg_0
    bind $top.b_dlg_1 <Return> {%W invoke}
    incr count_button
  }

  if { $arg_2 != "" } {
    ttk::button $top.b_dlg_2 -text $arg_2 -command "set_val_of_isc_dialog $top 2"
    pack $top.b_dlg_2 -side left -expand 1 -padx [scaled_px 12] -in $top.fr_dlg_0
    bind $top.b_dlg_2 <Return> {%W invoke}
    incr count_button
  }

  if { $arg_3 != "" } {
    ttk::button $top.b_dlg_3 -text $arg_3 -command "set_val_of_isc_dialog $top 3"
    pack $top.b_dlg_3 -side left -expand 1 -padx [scaled_px 12] -in $top.fr_dlg_0
    bind $top.b_dlg_3 <Return> {%W invoke}
    incr count_button
  }

  pack $top.l_dlg -fill x -expand 1 -padx [scaled_px 2] -pady [scaled_px 10] -in $top.fr_dlg
  pack $top.fr_dlg_0 -fill x -expand 1 -padx [scaled_px 2] -pady [scaled_px 4] -in $top.fr_dlg

  pack $top.fr_dlg -padx [scaled_px 16] -pady [scaled_px 8] -in $top.fr_dlg_relief

  pack $top.fr_dlg_relief

  wm withdraw $top
  update

  set dlg_width [winfo width $top]
  set dlg_height [winfo height $top]
  set pos_x [ expr {( [winfo screenwidth .] - $dlg_width ) / 2 } ]
  set pos_y [ expr {( [winfo screenheight .] - $dlg_height ) / 2 } ]

  wm geometry $top +$pos_x+$pos_y
  wm transient $top .
  wm deiconify $top
  wm state $top normal

  raise $top
  wm attributes $top -topmost $arg_topmost

  if { 0 < $count_button } {
    focus $top.b_dlg_$arg_default
  }

  # 他のウィンドゥの操作を禁止
  grab set $top

  update

  if { 0 < $count_button } {
    if { $callback eq "" } {
      # destroy されるまで待つ
      tkwait window $top
    } else {
      eval $callback $top
      tkwait variable isc_dialog_destroy_flag
    }
  }

  return $isc_dialog_return_val

}


##                           ##
## ISC オリジナルのエディタ  ##
##   -- タッチパネルへの対策 ##
##                           ##

# private proc (Editor内部専用): 上書き保存用のproc
proc save_proc_of_text_editor { top filename } {

  set data [$top.t_editor get 1.0 end]

  set l [string length $data]
  if { $l == 0 } {
    set w_data $data
  } elseif { $l == 1 } {
    if { $data eq "\n" } {
      set w_data ""
    } else {
      set w_data $data
    }
  } else {
    incr l -1
    if { [string index $data $l] eq "\n" } {
      set ix [expr $l - 1]
      set w_data [string range $data 0 $ix]
    } else {
      set w_data $data
    }
  }

  save_text_file $w_data $filename
  #save_text_file $w_data "_hoge.txt"

  # 内容変更フラグをリセット
  $top.t_editor edit modified 0

}

# private proc (Editor内部専用): 終了用のproc
proc quit_proc_of_text_editor { top filename } {

  set d_top $top
  append d_top "_dlg_ed_quit"

  set flg [$top.t_editor edit modified] 

  if { $flg } {

    set ans [isc_dialog $d_top "Question" "終了前に上書き保存しますか？" 0 ""  2 "保存して終了" "保存せず終了" "戻る" ""]

    if { $ans == 0 } {
      save_proc_of_text_editor $top $filename
    } elseif { $ans == 2 } {
      return
    }

  }

  destroy $top

}

array set filenames_of_text_editor {}

# private proc (Editor内部専用): 内容変更時のコールバックproc
proc modified_cb_of_text_editor { top filename } {

  global filenames_of_text_editor

  set flg [$top.t_editor edit modified] 

  if { $flg } {
    set filenames_of_text_editor($top) "(変更)"
  } else {
    set filenames_of_text_editor($top) ""
  }
  append filenames_of_text_editor($top) [file tail $filename]

}

#
# ISC ビルトイン Editor のオープン
#  top: 新規のtoplevelウィンドウ名。"" の場合は新規に作らず、
#       既存のメインウィンドウを使用する
#  filename: loadされるテキストファイル
#            存在しない場合は新規に作成される
#
proc open_isc_text_editor { top filename } {

  global font_small
  global editor_foreground
  global font_codefield
  global filenames_of_text_editor

  if { $filename eq "" } {
    return
  }

  set status 0
  if { $top ne "" } {
    set status [catch {toplevel $top} ret]
  }

  if { $status != 0 } {

    raise $top
    focus $top.t_editor

  } else {

    set lines ""
    set maxcol 80

    set status_load [load_text_file $filename lines maxcol]
    if { $status_load == 0 } {
      incr maxcol
      incr maxcol
    } else {
      if { [catch {open $filename a} fid] } {
        # ERROR
        return
      } else {
        fconfigure $fid -translation binary
        catch {close $fid}
      }
    }

    set filenames_of_text_editor($top) [file tail $filename]

    # ウィンドゥ名称,属性の設定
    set title_str "Interstellar Console :: text editor"
    #set title_str [file tail $filename]

    if { $top eq "" } {
      wm title . $title_str
      # Xボタンを押された時に呼ばれるprocを登録
      wm protocol . WM_DELETE_WINDOW [list quit_proc_of_text_editor . $filename]
    } else {
      wm title $top $title_str
      # Xボタンを押された時に呼ばれるprocを登録
      wm protocol $top WM_DELETE_WINDOW [list quit_proc_of_text_editor $top $filename]
    }

    ########################################################################

    frame $top.fr_rootwin

    ########################################################################

    frame $top.fr_btns

    ttk::button $top.b_exit -style Small.TButton -text "終了" -command "quit_proc_of_text_editor $top $filename"
    ttk::button $top.b_save -style Small.TButton -text "上書き保存" -command "save_proc_of_text_editor $top $filename"
    #label $top.l_filename -font $font_small -text [file tail $filename]
    label $top.l_filename -font $font_small -textvariable filenames_of_text_editor($top)

    pack $top.b_exit $top.b_save -side left -expand 0 -padx [scaled_px 2] -pady [scaled_px 2] -in $top.fr_btns
    pack $top.l_filename -side left -expand 1 -fill x -in $top.fr_btns

    pack $top.fr_btns -fill x -in $top.fr_rootwin

    text $top.t_editor -font $font_small -fg $editor_foreground -width $maxcol -height 24 -yscrollcommand "$top.sb_editor set" -wrap char -undo 1
    scrollbar $top.sb_editor -command "$top.t_editor yview"

    pack $top.t_editor -side left -expand 1 -fill both -in $top.fr_rootwin
    pack $top.sb_editor -side left -expand 0 -fill y -in $top.fr_rootwin

    ########################################################################

    pack $top.fr_rootwin -expand 1 -fill both

    $top.t_editor delete 1.0 end
    $top.t_editor insert end "$lines"
    # reset UNDO stack
    $top.t_editor edit reset
    # 内容変更フラグをリセット
    $top.t_editor edit modified 0
    # カーソルを先頭へ
    $top.t_editor mark set insert 0.0

    bind $top.t_editor <Control-s> [list save_proc_of_text_editor $top $filename]

    # 内容変更時のコールバックprocを登録
    bind $top.t_editor <<Modified>> [list modified_cb_of_text_editor $top $filename]

    focus $top.t_editor

  }

  return

}

#
# Editor のオープン
#  top: 新規のtoplevelウィンドウ名。"" の場合は新規に作らず、
#       既存のメインウィンドウを使用する
#  filename: loadされるテキストファイル
#
proc open_text_editor { top filename } {

  global flag_external_editor
  global text_editor

  if { $flag_external_editor != 0 } {
    exec -ignorestderr $text_editor $filename &
  } else {
    open_isc_text_editor $top $filename
  }

}

