/*
**  $Id: config-editor.rexx,v 1.1 1995/02/12 22:13:08 rkr Exp $
**
**  config-editor provides you with a means to edit the config-server
**  database.
**
*/
    call init( )
    address value host
    options results
    do while ~done
        call do_app_list( )
    end
exuent:
    call cls( )
    address command 'set_con'
exit prog_ret


init:
    host = 'config-server'
    if ~show( 'p', host ) then
    do
        say 'Could not find configuration host, {'config-server'}.'
        say 'Exiting.'
        prog_ret = 10
        signal exuent
    end
    address command 'set_raw'
    prog_ret = 0
    done = 0
    call init_display( )
return



do_app_list:
    call list_apps( )
    current_app = 1
    call sync_disp_apps( )

    dal_done = 0
    do until dal_done
        dal_event = get_key( )

        select
            when 'UP' == dal_event then
                call adjust_current_app( -1 )

            when 'DOWN' == dal_event then
                call adjust_current_app( +1 )

            when 'RIGHT' == dal_event | '0d'x == dal_event then
                dal_done = do_app( )

            when 'LEFT' == dal_event then
                call beep( )

            when 'Q' = upper( dal_event ) then
                dal_done = 1

            when 'R' == upper( dal_event ) then
            do
                'reload'
                call list_apps( )
                current_app = 1
                call sync_disp_apps( )
            end

            when 'S' == upper( dal_event ) then
                'save'

            when '7f'x == dal_event | 'D' = upper( dal_event ) then
                call delete_current_app( )

            otherwise
                nop

        end

    end
    done = 1
return

list_apps:
    apps. = ''
    'getattr apps'
    parse var result 'TEXT:' apps
    apps_clone = apps
    apps.count = length( apps ) - length( compress( apps, ':' ) )
    apps.max_len = 0
    do i = 1 for apps.count
        parse var apps app ':' apps
        apps.i = app
        apps.max_len = max( length( app ), apps.max_len )
    end
    apps.i = '::Quit::'
    apps.count = i
    apps.max_len = max( length( apps.i ), apps.max_len )
return

sync_disp_apps:
    call show_apps( )
    call highlight_current_app( )
return

show_apps:
    call cls( )
    say '::Applications::'
    say
    call push_mode( 'inverse' )
    sa_max_len = apps.max_len + 2
    do i = 1 for apps.count
        say '' left( apps.i, sa_max_len )
    end
    call pop_mode( )
return

show_current_app:
    call pos_cursor( current_app + 2, 2 )
    call writech( 'STDOUT', apps.current_app )
    call pos_cursor( current_app + 2, 2 )
return

highlight_current_app:
    call push_mode( 'inverse underline' )
    call show_current_app( )
    call pop_mode( )
return

adjust_current_app:
parse arg aca_adj
    aca_new = current_app + aca_adj
    aca_new = max( min( apps.count, aca_new ), 1 )
    if aca_new = current_app then
        call beep( )
    else
    do
        call push_mode( 'inverse' )
        call show_current_app( )
        current_app = aca_new
        call highlight_current_app( )
        call pop_mode( )
    end
return

delete_current_app:
    'remattr app' apps.current_app
    call list_apps( )
    call sync_disp_apps( )
return



do_app:
    da_ret = 0
    if '::Quit::' = apps.current_app then
        da_ret = 1
    else
    do
        current_app_name = apps.current_app
        call list_tags( )
        current_tag = 1
        call sync_disp_tags( )
        da_done = 0
        do until da_done
            da_event = get_key( )
            select
                when 'UP' == da_event then
                    call adjust_current_tag( -1 )

                when 'DOWN' == da_event then
                    call adjust_current_tag( +1 )

                when 'RIGHT' == da_event | '0d'x == da_event then
                    da_done = do_tag_subs( )

                when 'LEFT' == da_event | 'Q' == upper( da_event ) then
                    da_done = 1

                when '7f'x == da_event | 'D' == upper( da_event ) then
                    call delete_current_tag( )

                otherwise
                    nop
            end
        end
        call list_apps( )
        call sync_disp_apps( )
    end
return da_ret

list_tags:
    tags. = ''
    'getattr tags' current_app_name
    parse var result 'TEXT:' tags
    tags_clone = tags
    tags.count = length( tags ) - length( compress( tags, ':' ) )
    tags.max_len = 0
    do i = 1 for tags.count
        parse var tags tag ':' tags
        tags.i = tag
        tags.max_len = max( length( tag ), tags.max_len )
    end
    tags.i = '::Quit::'
    tags.count = i
    tags.max_len = max( length( '::Quit::' ), tags.max_len )
return

sync_disp_tags:
    call show_tags( )
    call highlight_current_tag( )
return

show_tags:
    call cls( )
    say '::Tags for' current_app_name'::'
    say
    call push_mode( 'inverse' )
    st_max_len = tags.max_len + 2
    do i = 1 for tags.count
        say '' left( tags.i, st_max_len )
    end
    call pop_mode( )
return

show_current_tag:
    call pos_cursor( current_tag + 2, 2 )
    call writech( 'STDOUT', tags.current_tag )
    call pos_cursor( current_tag + 2, 2 )
return

highlight_current_tag:
    call push_mode( 'inverse underline' )
    call show_current_tag( )
    call pop_mode( )
return

adjust_current_tag:
parse arg act_adj
    act_new = current_tag + act_adj
    act_new = max( min( tags.count, act_new ), 1 )
    if act_new = current_tag then
        call beep( )
    else
    do
        call push_mode( 'inverse' )
        call show_current_tag( )
        current_tag = act_new
        call highlight_current_tag( )
        call pop_mode( )
    end
return

delete_current_tag:
    dct_tag = tags.current_tag
    dct_app_tag = current_app_name':'dct_tag"'S"
    'remattr tag' dct_app_tag
    call list_tags( )
    call sync_disp_tags( )
return



do_tag_subs:
    dts_ret = 0
    if '::Quit::' = tags.current_tag then
        dts_ret = 1
    else
    do
        current_tag_name = tags.current_tag
        call list_tag_subs( )
        current_tag_sub = 1
        call sync_disp_tag_subs( )
        dts_done = 0
        do until dts_done
            dts_event = get_key( )
            select
                when 'UP' == dts_event then
                    call adjust_current_tag_sub( -1 )

                when 'DOWN' == dts_event then
                    call adjust_current_tag_sub( +1 )

                when 'RIGHT' == dts_event | '0d'x == dts_event then
                    dts_done = do_specific_tag( )

                when 'LEFT' == dts_event | 'Q' == upper( dts_event ) then
                    dts_done = 1

                when 'I' == upper( dts_event ) then
                    call insert_new_tag_sub( )

                when '7f'x == dts_event | 'D' == upper( dts_event ) then
                    call delete_current_tag_sub( )

                otherwise
                    nop
            end
        end
        call list_tags( )
        call sync_disp_tags( )
    end
return dts_ret

list_tag_subs:
    tag_subs. = ''
    'getattr tag' current_app_name':'current_tag_name"'S"
    parse var result 'TEXT:' tag_subs.count
    tag_subs.max_len = 0
    do i = 1 for tag_subs.count
        'getattr tag' current_app_name':'current_tag_name'.'i
        tag_subs.i = result
        tag_subs.max_len = max( length( tag_subs.i ), tag_subs.max_len )
    end
    tag_subs.i = '::Quit::'
    tag_subs.count = i
    tag_subs.max_len = max( length( '::Quit::' ), tag_subs.max_len )
return

sync_disp_tag_subs:
    call show_tag_subs( )
    call highlight_current_tag_sub( )
return

show_tag_subs:
    call cls( )
    say '::Tag subs for' current_app_name':'current_tag_name'::'
    say
    call push_mode( 'inverse' )
    sts_max_len = tag_subs.max_len + 2
    do i = 1 for tag_subs.count
        say '' left( tag_subs.i, sts_max_len )
    end
    call pop_mode( )
return

show_current_tag_sub:
    call pos_cursor( current_tag_sub + 2, 2 )
    call writech( 'STDOUT', tag_subs.current_tag_sub )
    call pos_cursor( current_tag_sub + 2, 2 )
return

highlight_current_tag_sub:
    call push_mode( 'inverse underline' )
    call show_current_tag_sub( )
    call pop_mode( )
return

adjust_current_tag_sub:
parse arg acts_adj
    acts_new = current_tag_sub + acts_adj
    acts_new = max( min( tag_subs.count, acts_new ), 1 )
    if acts_new = current_tag_sub then
        call beep( )
    else
    do
        call push_mode( 'inverse' )
        call show_current_tag_sub( )
        current_tag_sub = acts_new
        call highlight_current_tag_sub( )
        call pop_mode( )
    end
return

delete_current_tag_sub:
    dcts_tag = current_tag_name'.'current_tag_sub
    dcts_app_tag = current_app_name':'dcts_tag
    'remattr tag' dcts_app_tag
    call list_tag_subs( )
    call sync_disp_tag_subs( )
return

insert_new_tag_sub:
    ints_quit = ('::Quit::' == tag_subs.current_tag_sub)
    if ints_quit & (current_tag_sub > 1) then
        call beep( )
    else
    do
        ints_def_app = current_app_name
        ints_def_tag = current_tag_name
        if current_tag_sub == tag_subs.count then
        do
            /* ints_def_num = '' */
            ints_def_enc = 'TEXT'
            ints_def_val = ''
        end
        else
        do
            /* ints_def_num = current_tag_sub */
            'getattr tag' ints_def_app':'ints_def_tag'.'current_tag_sub
            parse var result ints_def_enc':'ints_def_val
        end
        call cls( )
        /* say '::New application:encoding:tag.num:value::' */
        say '::New application:encoding:tag:value::'
        say
        say 'Data:'
        say '  app:' ints_def_app
        say '  enc:' ints_def_enc
        say '  tag:' ints_def_tag
        say '  num:  ---' /*** ints_def_num ***/
        say '  val:' ints_def_val

        call set_con( )

        call pos_cursor( 10, 1 )
        call writech( 'STDOUT', 'App: ' )
        call push_mode( 'inverse' )
        ints_app = readln( 'STDIN' )
        if '' == ints_app then
            ints_app = ints_def_app
        ints_app = compress( ints_app, ':' )
        call pos_cursor( 4, 8 )
        call writech( 'STDOUT', left( ints_app, 64 ) )
        call pop_mode( )

        call pos_cursor( 10, 1 )
        call writech( 'STDOUT', 'Enc: ' )
        call push_mode( 'inverse' )
        ints_enc = readln( 'STDIN' )
        if '' == ints_enc then
            ints_enc = ints_def_enc
        ints_enc = compress( ints_enc, ':' )
        call pos_cursor( 5, 8 )
        call writech( 'STDOUT', left( ints_enc, 64 ) )
        call pop_mode( )

        call pos_cursor( 10, 1 )
        call writech( 'STDOUT', 'Tag: ' )
        call push_mode( 'inverse' )
        ints_tag = readln( 'STDIN' )
        if '' == ints_tag then
            ints_tag = ints_def_tag
        ints_tag = compress( ints_tag, "'.:" )
        call pos_cursor( 6, 8 )
        call writech( 'STDOUT', left( ints_tag, 64 ) )
        call pop_mode( )

        /*
        **  call pos_cursor( 10, 1 )
        **  call writech( 'STDOUT', 'Num: ' )
        **  call push_mode( 'inverse' )
        **  ints_num = readln( 'STDIN' )
        **  if ~datatype( ints_num, 'n' ) then
        **      ints_num = ints_def_val
        **  call pos_cursor( 7, 8 )
        **  call writech( 'STDOUT', left( ints_num, 64 ) )
        **  call pop_mode( )
        **
        */

        call pos_cursor( 10, 1 )
        call writech( 'STDOUT', 'Val: ' )
        call push_mode( 'inverse' )
        ints_val = readln( 'STDIN' )
        if '' == ints_val then
            ints_val = ints_def_val
        call pos_cursor( 8, 8 )
        call writech( 'STDOUT', left( ints_val, 64 ) )
        call pop_mode( )

        call set_raw( )

        'addattr tag' ints_app':'ints_enc':'ints_tag':'ints_val

        call list_tag_subs( )
        call sync_disp_tag_subs( )
    end
return ''


do_specific_tag:
    dst_ret = 0
    if '::Quit::' = tag_subs.current_tag_sub then
        dst_ret = 1
    else
        call beep( )
return dst_ret




/*
**  Screen editing functions
**
*/
init_display:
    call cls( )
    mode. = ''
    mode.count = 0
return

cls:
    call writech( 'STDOUT', '0c'x )
return

push_mode:
parse arg pm_add
    pm_c = mode.count
    pm_old = mode.pm_c
    pm_new = '' pm_old ''
    do i = 1 for words( pm_add )
        if 0 = pos( '' word( pm_add, i ) '', pm_new ) then
            pm_new = pm_new || word( pm_add, i ) ''
    end
    pm_c = pm_c + 1
    mode.pm_c = strip( pm_new )
    mode.count = pm_c
    call display_mode( )
return

pop_mode:
    mode.count = mode.count - 1
    if 0 > mode.count then
        mode.count = 0
    call display_mode( )
return

display_mode:
    dm_out = '9b'x || '0'
    dm_c = mode.count
    dm_modes = mode.dm_c
    do i = 1 for words( dm_modes )
        dm_umode = upper( word( dm_modes, i ) )
        select
            when 'BOLD' == dm_umode then
                dm_out = dm_out';1'

            when 'STANDOUT' = dm_umode then
                dm_out = dm_out';2'

            when 'ITALICS' = dm_umode then
                dm_out = dm_out';3'

            when 'UNDERLINE' = dm_umode then
                dm_out = dm_out';4'

            when 'INVERSE' == dm_umode then
                dm_out = dm_out';7'

            otherwise
                nop
        end
    end
    call writech( 'STDOUT', dm_out'm' )
return

pos_cursor:
parse arg pc_row, pc_col
    call writech( 'STDOUT', '9b'x || pc_row';'pc_col'H' )
return

get_key:
    gk_ret = readch( 'STDIN', 1 )
    if '1b'x == gk_ret then
    do
        gk_ret = gk_ret || readch( 'STDIN', 1 )
        if '1b5b'x == gk_ret then
            gk_ret = '9b'x
    end
    if '9b'x = gk_ret then
    do
        gk_ret = gk_ret || readch( 'STDIN', 1 )
        select
            when '9b41'x == gk_ret then
                gk_ret = 'UP'

            when '9b42'x == gk_ret then
                gk_ret = 'DOWN'

            when '9b43'x == gk_ret then
                gk_ret = 'RIGHT'

            when '9b44'x == gk_ret then
                gk_ret = 'LEFT'

            otherwise
                gk_ret = ''
        end
    end
return gk_ret


beep:
return writech( 'STDOUT', '07'x )

set_con:
    address command 'set_con'
return 1
set_raw:
    address command 'set_raw'
return 1
