;;; this is just a snippet to show how to use Qt for POST requests to
;;; a cgi script (using e.g. python for cgi)
;;;
;;; this is here to have an alternative to Lisp solutions, which don't
;;; work well in ECL on some platforms (namely Windows)
;;;
;;; example usage:
;;;
;;; (server-request "booking.py"
;;;                 (list (cons "from" "2020-08-01")
;;;                       (cons "to"   "2020-08-08")))
;;;
;;; please note the use of QLET to have all locally created Qt objects deleted
;;; when leaving the function body;
;;;
;;; note also how this is done with function HTTP-PART, where we can't use QLET
;;; inside the function for 'QHttpPart', because we need to return the newly
;;; created Qt object; in this case, QLET is placed in the caller, see:
;;;
;;;   (dolist...
;;;     (qlet ((part (http-part param)))
;;;       (|append|...
;;;
;;; ...and since we are at it, just a reminder:
;;;
;;; as you already should know, QLET is crucial for all only locally used Qt
;;; objects, because it guarantees two things:
;;; - the C++ destructors being called when leaving the QLET body
;;; - not leaving around some garbage (GC through finalizing is only implemen-
;;;   ted for return values from Qt function calls)

(qrequire :network)

;; for testing, using e.g. python3 -m http.server 8080 --cgi
(defparameter *server* "http://localhost:8080/cgi-bin/")

(defun http-part (parameter)
  (let ((part (qnew "QHttpPart")))
    (qlet ((name "QVariant(QString)"
                 (format nil "form-data; name=~S" (car parameter))))
      (|setHeader| part |QNetworkRequest.ContentDispositionHeader| name)
      (|setBody| part (x:string-to-bytes (cdr parameter))))
    part))

(defun server-request (script &optional parameters)
  "Make a http POST request to a cgi script, forcing synchronous behaviour,
  which simplifies things and is preferable in many cases."
  (start-busy-animation) ; pseudo code
  (let (response)
    (qlet ((ev-loop "QEventLoop")
           (manager "QNetworkAccessManager"))
      (qconnect manager "finished(QNetworkReply*)"
                (lambda (reply)
                  (|deleteLater| reply)
                  (let ((err (|error| reply)))
                    (when (= |QNetworkReply.NoError| err)
                      (setf response (qfrom-utf8 (|readAll| reply)))))
                  (|exit| ev-loop)))
      (qlet ((multi   "QHttpMultiPart")
             (qurl    "QUrl(QString)" (x:cc *server* script))
             (request "QNetworkRequest(QUrl)" qurl))
        (dolist (param parameters)
          (qlet ((part (http-part param)))
            (|append| multi part)))
        (|post| manager request multi)
        (|exec| ev-loop |QEventLoop.ExcludeUserInputEvents|)
        (stop-busy-animation) ; pseudo code
        response))))

