/*{{{}}}*/
/*{{{  #includes*/
#ifdef CONFIG_H
#   include "config.h"
#endif

#include <sys/types.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define KEYTAB_C
#define I_BUFFLOOP_C
#define I_DISPLAY_C
#define I_FIELDEDIT_C
#define I_FINDS_C
#define I_FOLDING_C
#define I_GETMSG_C
#define I_GETTK_C
#define I_KEYBOARD_C
#define I_LOOP_C
#define I_MAIN_C
#define I_PROMPT_C
#define I_SCREEN_C
#define I_SIGNALS_C
#define I_VIRTUAL_C

#include "origami.h"
#include <lib/ori_add_lib.h>
#include <h/envvar_str.h>
/*}}}  */

/*{{{  variables*/
private KEY const *find_current;
private KEY const *top_list;
private int const *mark_list;
public int const *bind_mark=0;
public int curr_kbd=0;
#ifdef MOUSY
  public TOKEN *mouse_mapping=0;
#endif
public boolean quote_used=False;
public int mouse_number=0;
/*}}}  */
/*{{{  key_infos key_info*/
#include "permlist.h"
/*}}}  */

/*{{{  kbd_change*/
public void kbd_change(int const no)
{
  if
   (    (unsigned int)no>=ktb_count
     || !(find_current=top_list+(curr_kbd=no))
   )
     exit_origami(r_ocl_err,get_msg(F_INT_OCL,STR_KEYTABLE));
  bind_mark= mark_list+no;
}
/*}}}  */
/*{{{  set_key_top*/
public void set_key_top (KEY const * const top,int const * const marks)
{
  ori_assert(top,"kbd missing");
  find_current=top_list=top;
  bind_mark=mark_list=marks;
  kbd_change(curr_kbd);
}
/*}}}  */
/*{{{  find_key*/
public int find_key (int const key)
{
  KEY const *find;

  /*{{{  quoting???*/
  if (find_current==(KEY*)0)
   { find_current=top_list+curr_kbd;
     quote_used=True;
     return((key&(O_NOP-1)));
   }
  /*}}}  */
  quote_used=False;
  /*{{{  search in tree*/
  for (find = key_level_ptr(find_current);find;)
   { if (key_match(find,key))
        break;
     find=key_next_ptr(find);
     while (key_far_next(find))
        find=key_level_ptr(find);
   }
  /*}}}  */
  switch (key_code(find))
   { case 0:
        if (key_level_ptr(find))
         /*{{{  search continues*/
         { find_current = find;
           return (keytabcont);
         }
         /*}}}  */
        else
         /*{{{  no level below this, the search ends*/
         { find_current=top_list+curr_kbd;
           return(keytabend);
         }
         /*}}}  */
     case K_QUOTE:
        /*{{{  return continue, store quote*/
        find_current=0;
        return(keytabcont);
        /*}}}  */
     default:
        /*{{{  return found TOKEN, maybe shifted*/
        { find_current=top_list+curr_kbd;
          return (find->code);
        }
        /*}}}  */
   }
}
/*}}}  */
/*{{{  valid_key*/
public boolean valid_key(TOKEN const ch)
{
  if
   (!(    (   ch==O_CREATE_FOLD
           && (   (    ocl_var[var_mod_beh].v!=(fold_selection-1)
                    && ocl_var[var_mod_beh].v!=(unmark_fold_selection-1)
                  )
               || (    bd.m.select_mode!=no_selection
                    && bd.m.select_mode!=fold_selection
                    && bd.m.select_mode!=unmark_fold_selection
                  )
              )
          )
       || (   ch>=O_NOP
           && ch<K_QUOTE
           && key_info[ch-O_NOP]&KTI_B
          )
     )
   )
     if (bd.m.read_only)
      { msg_message(M_VIEW);
        ocl_var[var_ocl_arg].v=ch;
        if (view_macro)
           call_number_macro(view_macro);
        return False;
      }
     else
      { if (bd.m.file_changed_status!=changed_file)
         { bd.m.file_changed_status++;
           title_op(CHGTITLE);
         }
      }
  return True;
}
/*}}}  */
/*{{{  valid_field_key check if token is a correct field_key*/
public boolean valid_field_key(TOKEN const ch)
{
  return(ch<O_NOP || (ch<K_QUOTE && key_info[ch - O_NOP]&KTI_F));
}
/*}}}  */
/*{{{  valid_screen_key*/
public int valid_screen_key(TOKEN const ch)
{
  if (ch>=O_NOP && ch<K_QUOTE && !(key_info[ch-O_NOP]&KTI_S))
     switch (bd.m.select_mode)
      { default:                     return(0);

        case no_selection: break;/* =return(1) */

        case pseudo_fold_selection:
        case block_selection:
        case reg_selection:
        case nodrawn_selection:      return(-1);
      }

  return(1);
}
/*}}}  */
/*{{{  invalid_prompt_key*/
public boolean invalid_prompt_key(TOKEN const c)
{
  if (c>=O_NOP && c<K_QUOTE && !(key_info[c-O_NOP]&KTI_P))
   /*{{{  maybe get unhandled OCL-args*/
   { switch (GET_T(c))
      { case COM_II:
           get_arg("skip II");
        case COM_I:
        case COM_C:
        case COM_A:
           get_arg("skip ICA");
        case COM:
           break;
        case COM_IIP:
           get_arg("skip IIP");
        case COM_IP:
           get_arg("skip IP");
        case COM_P:
           for (;;)
            { switch (get_arg("skip P"))
               { case M_END_MACRO:
                    break;
                 case M_INT_STRING:
                    get_arg("skip counter");
                 default:
                    continue;
               }
              break;
            }
           break;
      }
     return(True);
   }
   /*}}}  */
  if (executing_macro && c==O_FLUSH)
     get_arg("skip unused flush arg");

  return(False);
}
/*}}}  */
#ifdef MOUSY
  /*{{{  get clickposition and return correct token*/
  /*{{{  MOUSE_UP*/
#  ifdef XTERM
#    define TEST_XTERM(but) (use_mouse==xterm && XTERM_MOUSE_UP(but))
#  else
#    define TEST_XTERM(but) 0
#  endif
#  ifdef MGR
#    define TEST_MGR(but) (use_mouse==mgr && MGR_MOUSE_UP(but))
#  else
#    define TEST_MGR(but) 0
#  endif
#  ifdef OS_MOUSE_TAG
#    define TEST_OS_MOUSE_TAG(but) (use_mouse==OS_MOUSE_TAG && OS_MOUSE_TAG_MOUSE_UP(but))
#  else
#    define TEST_OS_MOUSE_TAG(but) 0
#  endif
#  define MOUSE_UP(b) (TEST_XTERM(b)||TEST_MGR(b)||TEST_OS_MOUSE_TAG(b))
  /*}}}  */

  TOKEN handle_click(int const x,int const y, int const but)
  { TOKEN menu_char;

    if (bd.f.current==(element*)0)
       return(O_NOP);
    /*{{{  set mouse-vars*/
    decode_buffer_mouse(x,y,True);
    /*{{{  maybe set menu character*/
    if (menu_string)
     { menu_char=O_NOP;
       if (MOUSE_UP(but) && y==screen.h-root_dont_use.h)
        { unsigned char const *s;
          int i;
          int no;

          for (i=x,s=menu_string,no=menu_current;i>0;i--)
           { unsigned char c;

             switch((c= *s))
              { case ' ':
                   if (no==-1)
                    { no--;
                      i--;
                    }
                   s++;
                case '\0':
                   menu_char=O_NOP;
                   break;
                case SPACE_CHAR:
                   i-=sizeof(SPACE)-2;
                   c=' ';
                default:
                   s++;
                   if (menu_char==O_NOP)
                    { no--;
                      menu_char=c;
                    }
              }
           }

        }
     }
    /*}}}  */
    ocl_var[var_m_but].v=but;
    /*}}}  */
    /*{{{  reset keytab search -> started keysequences are cut*/
    find_current=top_list+curr_kbd;
    /*}}}  */
    if (menu_string)
     /*{{{  return code for clicked menu entry, or O_NOP*/
       return(menu_char);
     /*}}}  */
    else
     /*{{{  return the mapped token, if correct value, else O_PROMPT*/
     { TOKEN c=O_PROMPT;

       if ((but>=0)&&(but<mouse_number)) c=mouse_mapping[but];
       return(c==O_NOP?O_PROMPT:c);
     }
     /*}}}  */
  }
  /*}}}  */
#endif
