Cleanup conditional construction logic for --resolved and --user

Signed-off-by: Joey Armstrong <jarmstrong@linuxfoundation.org>
Change-Id: I2080713f8c340aa234923e0a226030ec1b666133
diff --git a/jira/jira-search/include.sh b/jira/jira-search/include.sh
index 8f81512..773afba 100644
--- a/jira/jira-search/include.sh
+++ b/jira/jira-search/include.sh
@@ -48,4 +48,7 @@
 source "${pgm_lib}/resolved.sh"
 source "${pgm_lib}/help/utils.sh"
 
+source "${pgm_lib}/is_empty/include.sh"
+source "${pgm_lib}/is_not/include.sh"
+
 # [EOF]
diff --git a/jira/jira-search/is_empty.sh b/jira/jira-search/is_empty.sh
index fe6e9d1..5abe08a 100644
--- a/jira/jira-search/is_empty.sh
+++ b/jira/jira-search/is_empty.sh
@@ -21,7 +21,7 @@
     if [[ " ${valid[@]} " =~ " ${val} " ]]; then
         is_empty+=("$val")
     else
-        error "Detected invalid --is-empty switch [$arg]"
+        error "Detected invalid --empty switch [$arg]"
     fi
     
     return
diff --git a/jira/jira-search/is_empty/include.sh b/jira/jira-search/is_empty/include.sh
new file mode 100644
index 0000000..0acb0c2
--- /dev/null
+++ b/jira/jira-search/is_empty/include.sh
@@ -0,0 +1,67 @@
+#!/bin/bash
+## -----------------------------------------------------------------------
+## Intent: getopts parsing and set flag status for --is-empty swtiches
+## -----------------------------------------------------------------------
+
+## -----------------------------------------------------------------------
+## Intent: Parse command line switch, when *-empty detected take action
+##   - remove is-empty OR is-not-empty from swtich string
+##   - set values in map %attrs=() to capture detection bits
+## Return:
+##   %attrs
+##    --is-empty        empty=true
+##    --is-not-empty    empty=true, not=true
+## -----------------------------------------------------------------------
+function getopts_switch__empty()
+{ 
+    local -n gse_arg=$1; shift
+    declare -g -A attrs
+
+    case "$gse_arg" in
+        *'-is-empty')
+            is_switch_valid__is_empty "$gse_arg"
+            attrs['empty']=1
+            # declare -g -i argv_is_empty=1
+            gse_arg="${gse_arg/-is-empty/}"
+            local -i rc=0
+            ;;
+        *) local -i rc=1 ;;
+    esac
+
+    [[ $rc -eq 0 ]] && { true; } || { false; }
+    return
+}
+
+## -----------------------------------------------------------------------
+## Intent: Define flags based on detected switch modifiers
+## -----------------------------------------------------------------------
+function gen_attrs__empty()
+{
+    local switch="$1"; shift
+    declare -g attrs
+
+    local is="${switch}_is_empty"
+    local not="${switch}_not_empty"
+    declare -g -i "$is"
+    declare -g -i "$not"
+    
+    ## Clear prior state
+    [[ -v "$is" ]]  && { echo "IS"; unset "$is"; }
+    [[ -v "$not" ]] && { echo "NOT"; unset "$not"; }
+
+    ## Apply current attributes
+    ## [TODO] parameterize flag creation
+    if [[ ! -v attrs['empty'] ]]; then
+        : # fall through
+    elif [[ -v attrs['not'] ]]; then
+        declare -g -i $not=1
+    else
+        declare -g -i $is=1
+    fi
+
+    : # assign ($?==0)
+    return
+}
+
+
+# [EOF]
diff --git a/jira/jira-search/is_not/include.sh b/jira/jira-search/is_not/include.sh
new file mode 100644
index 0000000..0858b36
--- /dev/null
+++ b/jira/jira-search/is_not/include.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+## -----------------------------------------------------------------------
+## -----------------------------------------------------------------------
+
+## -----------------------------------------------------------------------
+## Intent: Parse command line switch, when *-not detected take action
+##   - remove substring '-not' modifier from switch name
+##   - set values in map %attrs=() to capture detection of NOT
+##   - switch value returned modified
+## Return:
+##   %attrs   ['not']=true
+## -----------------------------------------------------------------------
+function getopts_switch__not()
+{
+    local -n gsn_arg=$1 ; shift
+    declare -g -A attrs
+
+    case "$gsn_arg" in
+
+        # -[-not]
+        '--not')
+            attrs['not']=1
+            gsn_argv=''
+            local -i rc=0
+            ;;
+
+        # --reserved-is[-not]-empty
+        *'-not'*)
+            declare -a args=()
+            attrs['not']=1
+            gsn_arg="${gsn_arg/-not/}"
+            local -i rc=0
+            ;;
+
+        *) local -i rc=1 ;;
+    esac
+
+    [[ $rc -eq 0 ]] && { true; } || { false; }
+    return
+}
+
+# [EOF]
diff --git a/jira/jira-search/resolved.sh b/jira/jira-search/resolved.sh
index 88b6835..cf6bf31 100644
--- a/jira/jira-search/resolved.sh
+++ b/jira/jira-search/resolved.sh
@@ -10,13 +10,26 @@
 function get_jcl_resolved()
 {
     local -n ref=$1; shift
+    local -i count=${#ref[@]}
 
     local -a tmp=()
     do_resolved tmp
-    ref+=("$tmp")
-    
-    local query="$(join_by 'OR' "${tmp[0]}")"
-    ref+=("($query)")
+
+    ## --------------------------
+    ## Construct resolved queries
+    ## -------------------------- 
+    local query="$(join_by ' OR ' "${tmp[@]}")"
+
+    ## ----------------------------------------
+    ## Normalize parens for the composite query
+    ## ----------------------------------------
+    if [[ ${#ref[@]} -eq 0 ]]; then
+        ref+=("$query")
+    else
+        local buffer
+        buffer="$(join_by ' AND ' "(${ref[@]})" "($query)")"
+        ref=("$buffer")
+    fi
     
     return
 }
@@ -44,12 +57,23 @@
 {
     declare -n ans=$1; shift
 
-    [[ -v resolved_start ]] && { ans+=("(Resolved >= $resolved_start)"); }
-    [[ -v resolved_end ]]   && { ans+=("(Resolved <= $resolved_end)"); }
+    # --resolved-in {start} {end} can resolve join({and,or}) ambiguity
+    # [[ -v resolved_start ]] && { ans+=("(Resolved >= $resolved_start)"); }
+    # [[ -v resolved_end ]]   && { ans+=("(Resolved <= $resolved_end)"); }
+    declare -a joinby=()
+    [[ -v resolved_start ]] && { joinby+=("(Resolved >= $resolved_start)"); }
+    [[ -v resolved_end ]]   && { joinby+=("(Resolved <= $resolved_end)"); }
+    
+    if [[ ${#joinby[@]} -lt 2 ]]; then
+        ans+=("${joinby[@]}")
+    else
+        filter="$(join_by ' AND ' "${joinby[@]}")"
+        ans+=("(${filter})")
+    fi
 
+    
     if [[ -v resolved_excl ]]; then
         filter="$(join_by ',' "${resolved_excl[@]}")"
-        declare -p filter
         ans+=( "(resolution NOT IN ($filter))" )
     fi
 
@@ -58,14 +82,12 @@
         ans+=( "(resolution IN ($filter))" )
     fi
 
-    [[ -v resolved_not_empty ]] \
-        && { ans+=('(resolved IS NOT EMPTY)'); } \
-        || { true; }
-               
-    [[ -v resolved_is_empty ]] \
-        && { ans+=('(resolved IS EMPTY)'); } \
-        || { true; }
-
+    if [[ -v resolved_not_empty ]]; then
+        ans+=('(resolved IS NOT EMPTY)')
+    elif [[ -v resolved_is_empty ]]; then
+        ans+=('(resolved IS EMPTY)')
+    fi
+    
     return
 }