            upload-id)
 
     (swap! app-state/app-state
-           assoc
-           :uploads
-           (merge (:uploads @app-state/app-state)
-                  (if (< (:num-of-uploads @app-state/app-state)
+           merge
+           @app-state/app-state
+           (if (< (count (:active-uploads @app-state/app-state))
                          (:upload-slots   @app-state/app-state))
-                    {upload-id (start-upload new-upload)}
-                    {upload-id new-upload})))))
+             {:uploads (merge (:uploads @app-state/app-state)
+                              {upload-id (start-upload new-upload)})
+              :active-uploads (prepend-upload (:active-uploads @app-state/app-state)
+                                              upload-id)}
+             {:uploads (merge (:uploads @app-state/app-state)
+                              {upload-id new-upload})
+              :inactive-uploads (prepend-upload (:inactive-uploads @app-state/app-state)
+                                                upload-id)}))))
 
 

        upload-id (.v4 js/uuid)
        stream (.createStream js/ss)
        blob-stream (.createBlobReadStream js/ss file)
        upload-watch-fn (fn [_ _ old-state new-state]
                          (let [action (get-action old-state new-state upload-id)]
                            (cond
                              (= action :paused)
                                (.unpipe blob-stream)
                              (= action :unpaused)
                                (.pipe blob-stream stream)
                              (= action :stopped)
                                (do
                                  (swap! app-state/app-state
                                         assoc
                                         :active-uploads
                                         (remove #{upload-id}
                                                 (:active-uploads @app-state/app-state)))
                                  (swap! app-state/app-state
                                         assoc
                                         :inactive-uploads
                                         (prepend-upload (:inactive-uploads @app-state/app-state)
                                                         upload-id))
                                  (.unpipe blob-stream))
                              (= action :started)
                                (do
                                  (swap! app-state/app-state
                                         assoc
                                         :inactive-uploads
                                         (remove #{upload-id}
                                                 (:inactive-uploads @app-state/app-state)))
                                  (swap! app-state/app-state
                                         assoc
                                         :active-uploads
                                         (append-upload (:active-uploads @app-state/app-state)
                                                        upload-id))
                                  (.pipe blob-stream stream)))))]
    (.on blob-stream "end"
      (fn []
        (swap! app-state/app-state
               assoc
               :num-of-uploads
               (dec (:num-of-uploads @app-state/app-state)))
        (swap! app-state/app-state
               assoc
               :uploads
               (dissoc (:uploads @app-state/app-state)
                       upload-id))
        (remove-watch app-state/app-state upload-id)))
    (add-watch app-state/app-state
               upload-id
               upload-watch-fn)

    (swap! app-state/app-state
           assoc
           :inactive-uploads
           (append-upload (:inactive-uploads @app-state/app-state)
                          upload-id))

    (.emit (js/ss app-state/socket)
           "file-upload"

(defn drop-last-upload [uploads]
  (subvec uploads 0 (dec (count uploads))))

(defn handle-upload-slots-change [old-state new-state]
  (let [old-upload-slots (:upload-slots old-state)
        new-upload-slots (:upload-slots new-state)
        active-uploads   (:active-uploads new-state)
        inactive-uploads (:inactive-uploads new-state)
        uploads (:uploads new-state)]
    (cond
      (< old-upload-slots new-upload-slots)
        (if-not (empty? inactive-uploads)
          {:active-uploads (append-upload active-uploads
                                          (first inactive-uploads))
           :inactive-uploads (drop-first-upload inactive-uploads)
           :uploads (merge uploads {(first inactive-uploads)
                                    (start-upload (first inactive-uploads))})})
      (> old-upload-slots new-upload-slots)
        (if-not (empty? active-uploads)
          {:active-uploads (drop-last-upload active-uploads)
           :inactive-uploads (prepend-upload inactive-uploads
                                             (last active-uploads))
           :uploads (merge uploads {(last active-uploads)
                                    (stop-upload (last active-uploads))})}))))

(defn upload-slots-watch-fn! [_ _ old-state new-state]
  (let [new-uploads-info (handle-upload-slots-change old-state new-state)]
    (if-not (nil? new-uploads-info)
      (do

        (println "NEW UPLOADS INFO:" new-uploads-info)
        (swap! app-state/app-state (merge @app-state/app-state
                                          new-uploads-info))))))

(add-watch app-state/app-state :upload-slots  upload-slots-watch-fn!)

(defn get-action [old-state new-state upload-id]
  "returns the action applied to the given upload-id.
