                   (split description #"\.\s+"))
           :else description)))
 
-(defn clear-label
-  [label]
-  (-> label
-      delete-parenthesized-parts 
-      trim))
+(def clear-label
+  (comp trim delete-parenthesized-parts))
 
 (defn clear-tokens
+  "Filter out roman numerals"
   [tokens]
-  ; Filter out roman numerals
   (filter (fn [token]
             (not (re-matches #"^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})\.?$" token)))
           tokens))

    (go
      (swap! app-state #(assoc % :loading? true))
      (let [query (render-template (<! query-channel) :data data)]
        ;(.log js/console query)
        (>! sparql-results (<! (sparql-query-channel query))))
      (swap! app-state #(assoc % :loading? false)))
    sparql-results))

(defn sparql-autocomplete
  "Autocomplete from SPARQL endpoint.
  request: jQuery UI autocomplete's request object
  response: channel to put the response to"
  [request response]
  (let [fragment (lower-case (.-term request))
        sparql-results (sparql-results-channel)
        query (render-template autocomplete-template
                               :data {:classes (get-in config [:data :sparql :classes :default])
                                      :fragment fragment})
        sparql-query (sparql-query-channel query)]
    (go (let [results (map :label (<! (wrap-load sparql-query sparql-results)))]
          (response (clj->js results))))))

(defn wikipedia-autocomplete
  "Autocomplete from Wikipedia API.
  request: jQuery UI autocomplete's request object
  response: channel to put the response to"
  [request response]
  (let [fragment (lower-case (.-term request))
        query (http/jsonp "http://cs.wikipedia.org/w/api.php"
                          {:query-params {:action "opensearch"
                                          :format "json"
                                          :search fragment}})]
    (go (-> query <! :body second clj->js response))))

(defn load-gdocs-items
  "Load items from Google Spreadsheet's worksheet."
  [spreadsheet-id worksheet-id]
  (let [url (str "https://spreadsheets.google.com/feeds/list/"
                 spreadsheet-id "/" worksheet-id "/public/full")
        results (chan 1 (map (comp :entry :feed :body)))]
    (wrap-load (http/jsonp url {:query-params {:alt "json-in-script"}})
               results)))

  (:require-macros [cljs.core.async.macros :refer [go go-loop]])
  (:require [db-quiz.config :refer [config]]
            [db-quiz.state :refer [app-state]]
            [db-quiz.modals :as modals]
            [db-quiz.util :refer [number-of-fields]]
            [cljs-http.client :as http]
            [cljs.core.async :refer [<! >! chan pipe]]
            [clojure.string :refer [join lower-case replace split trim]]
            [cljsjs.mustache :as mustache]
            [reagent-modals.modals :as reagent-modals]))

; ----- Private vars -----

(def load-labels-template
  "PREFIX dbo:     <http://dbpedia.org/ontology/>
  PREFIX rdfs:     <http://www.w3.org/2000/01/rdf-schema#>

  SELECT ?label
  WHERE {
    {
      SELECT (STR(?_label) AS ?label)
      WHERE {
        GRAPH <http://cs.dbpedia.org> {
          VALUES ?class {
            {{#classes}}
            <{{{.}}}>
            {{/classes}}
          }
          [] a ?class ;
            rdfs:label ?_label ;
            dbo:abstract ?_description .
          FILTER (!REGEX(?_label, '^(\\\\p{Lu}\\\\.?)+$')
                  &&
                  !REGEX(?_label, '^.*\\\\d+.*$') 
                  &&
                  (STRLEN(?_description) > 140)
                  &&
                  langMatches(lang(?_label), 'cs')
                  &&
                  langMatches(lang(?_description), 'cs'))
        }
      }
      ORDER BY ?label
    }
  }
  LIMIT {{limit}}
  OFFSET {{offset}}")

(def load-labels-group-template
  "PREFIX dbo:     <http://dbpedia.org/ontology/>
  PREFIX rdfs:     <http://www.w3.org/2000/01/rdf-schema#>

  SELECT (GROUP_CONCAT(STR(?_label); separator = '|') AS ?labels)
  WHERE {
    GRAPH <http://cs.dbpedia.org> {
      VALUES ?class {
        {{#classes}}
        <{{{.}}}>
        {{/classes}}
      }
      [] a ?class ;
        rdfs:label ?_label ;
        dbo:abstract ?_description .
      FILTER (!REGEX(?_label, '^(\\\\p{Lu}\\\\.?)+$')
              &&
              !REGEX(?_label, '^.*\\\\d+.*$') 
              &&
              (STRLEN(?_description) > 140)
              &&
              langMatches(lang(?_label), 'cs')
              &&
              langMatches(lang(?_description), 'cs'))
    }
  }")

; ----- Public functions -----

(def sparql-results-channel
  "Channel that extracts values from application/sparql-results+json format."
  (letfn [(extract-values [result] (into {} (map (fn [[k v]] [k (:value v)]) result)))]
    (fn []
      (chan 1 (map (comp (partial map extract-values) :bindings :results :body))))))

(defn sparql-query-channel
  "Virtuoso-specific JSON-P request"
  [endpoint query]
  (http/jsonp endpoint
              {:query-params {; Since JSON-P does not allow setting Accept header,
                              ; we need to use Virtuoso-specific query parameter `format`.
                              :format "application/sparql-results+json"
                              :query query
                              :timeout 60000}}))

(defn render-template
  "Render Mustache template with data."
