function parse_query($search_type, $text, $sort_order = '', $wg_ids = NULL, $publicOnly = false)
{
    // wg_ids is a list of the workgroups we can access; records records marked with a rec_OwnerUGrpID not in this list are omitted
    // remove any  lone dashes outside matched quotes.
    $text = preg_replace('/- (?=[^"]*(?:"[^"]*"[^"]*)*$)|-\\s*$/', ' ', $text);
    // divide the query into dbl-quoted and other (note a dash(-) in front of a string is preserved and means negate)
    preg_match_all('/(-?"[^"]+")|([^" ]+)/', $text, $matches);
    $preProcessedQuery = "";
    $connectors = array(":", ">", "<", "=", ",");
    foreach ($matches[0] as $queryPart) {
        //if the query part is not a dbl-quoted string (ignoring a preceeding dash and spaces)
        //necessary since we want double quotes to allow all characters
        if (!preg_match('/^\\s*-?".*"$/', $queryPart)) {
            // clean up the query.
            // liposuction out all the non-kocher characters
            // (this means all punctuation except -, _, :, ', ", = and ,  ...?)
            $queryPart = preg_replace('/[\\000-\\041\\043-\\046\\050-\\053\\073\\077\\100\\133\\135\\136\\140\\173-\\177]+/s', ' ', $queryPart);
        }
        //reconstruct the string
        $addSpace = $preProcessedQuery != "" && !in_array($preProcessedQuery[strlen($preProcessedQuery) - 1], $connectors) && !in_array($queryPart[0], $connectors);
        $preProcessedQuery .= ($addSpace ? " " : "") . $queryPart;
    }
    $query = new Query($search_type, $preProcessedQuery, $publicOnly);
    $query->addWorkgroupRestriction($wg_ids);
    $q = $query->makeSQL();
    if ($query->sort_phrases) {
        // handled in Query logic
    } else {
        if (preg_match('/^f:(\\d+)/', $sort_order, $matches)) {
            $q .= ' order by ifnull((select if(link.rec_ID is null, dtl_Value, link.rec_Title) from recDetails left join Records link on dtl_Value=link.rec_ID where dtl_RecID=TOPBIBLIO.rec_ID and dtl_DetailTypeID=' . $matches[1] . ' order by link.rec_Title limit 1), "~~"), rec_Title';
        } else {
            if ($search_type == BOOKMARK) {
                switch ($sort_order) {
                    case SORT_POPULARITY:
                        $q .= ' order by rec_Popularity desc, rec_Added desc';
                        break;
                    case SORT_RATING:
                        $q .= ' order by bkm_Rating desc';
                        break;
                    case SORT_URL:
                        $q .= ' order by rec_URL is null, rec_URL';
                        break;
                    case SORT_MODIFIED:
                        $q .= ' order by bkm_Modified desc';
                        break;
                    case SORT_ADDED:
                        $q .= ' order by bkm_Added desc';
                        break;
                    case SORT_TITLE:
                    default:
                        $q .= ' order by rec_Title = "", rec_Title';
                }
            } else {
                switch ($sort_order) {
                    case SORT_POPULARITY:
                        $q .= ' order by rec_Popularity desc, rec_Added desc';
                        break;
                    case SORT_URL:
                        $q .= ' order by rec_URL is null, rec_URL';
                        break;
                    case SORT_MODIFIED:
                        $q .= ' order by rec_Modified desc';
                        break;
                    case SORT_ADDED:
                        $q .= ' order by rec_Added desc';
                        break;
                    case SORT_TITLE:
                    default:
                        $q .= ' order by rec_Title = "", rec_Title';
                }
            }
        }
    }
    return $q;
}