#+fw.dump
(eval-when (:compile-toplevel :load-toplevel :execute)
  (load "~/quicklisp/setup.lisp"))

#+fw.dump
(ql:quickload '(:net.didierverna.clon :alexandria :serapeum :com.inuoe.jzon))

(defpackage :fwoar.json-formatter
  (:use :cl )
  (:export ))
(in-package :fwoar.json-formatter)

(defgeneric pprint-json (client obj context stream))

(defmethod pprint-json ((client (eql :flat)) (obj string) context stream)
  (format stream "\"~a\"" (serapeum:string-replace-all "\"" obj "\\\"")))
(defmethod pprint-json ((client (eql :flat)) (obj float) context stream)
  (format stream "~a" obj))
(defmethod pprint-json ((client (eql :flat)) (obj integer) context stream)
  (format stream "~a" obj))

(defmethod pprint-json ((client (eql :flat)) (obj hash-table) context stream)
  (let* ((keys (sort (alexandria:hash-table-keys obj)
                     'string-lessp))
         (id (find "id" keys :test 'equal))
         (keys (remove "id" keys :test 'equal)))
    (princ "{" stream)
    (if id
        (pprint-json client id context stream)
        (pprint-json client (car keys) context stream))
    (princ ": " stream)
    (if id
        (pprint-json client (gethash id obj) obj stream)
        (pprint-json client (gethash (car keys) obj) obj stream))
    (mapc (lambda (key)
            (princ ", " stream)
            (pprint-json client key context stream)
            (princ ": " stream)
            (pprint-json client (gethash key obj) obj stream))
          (if id
              keys
              (cdr keys)))
    (princ "}" stream)))

(defmethod pprint-json ((client (eql :flat)) (obj array) context stream)
  (pprint-logical-block (stream nil :prefix "[" :suffix "]")
    (loop for sub across obj
          for first = t then nil
          unless first
            do (princ "," stream) (pprint-newline :mandatory stream)
          do (pprint-json client sub obj stream))))

#+fw.dump
(defvar *synopsis*
  (net.didierverna.clon:defsynopsis (:postfix "PATHS" :make-default nil)
      (flag :short-name "h" :long-name "help")))

#+fw.dump
(defun main ()
  (let* ((context (net.didierverna.clon:make-context :synopsis *synopsis*))
         (net.didierverna.clon:*context* context))
    (cond ((net.didierverna.clon:getopt :context context
                                        :long-name "help")
           (net.didierverna.clon:help))


          (t
           (let ((input (first (net.didierverna.clon:remainder :context context))))
             (with-open-file (s input)
               (let ((decoded (com.inuoe.jzon:parse s)))
                 (fresh-line)
                 (pprint-json :flat decoded nil *standard-output*))))
           (fresh-line)))))

#+fw.dump
(defun dump ()
  (setf net.didierverna.clon:*context* nil
        *features* (remove :fw.dump *features*))
  (net.didierverna.clon:dump "json-formatter" main))