 (in-ns 'game.core)
 
-(declare host in-play? make-rid rez run-flag? server-list server->zone set-prop system-msg turn-flag?
-         update-breaker-strength update-ice-strength update-run-ice)
-
-; Functions for the installation and deactivation of cards.
+(declare host in-play? make-rid rez run-flag? server-list server->zone set-prop system-msg
+         turn-flag? update-breaker-strength update-ice-strength update-run-ice)
+
+;;;; Functions for the installation and deactivation of cards.
+
+;;; Deactivate a card
+(defn- dissoc-card
+  "Dissoc relevant keys in card"
+  [card keep-counter]
+  (let [c (dissoc card :current-strength :abilities :rezzed :special :added-virus-counter)
+        c (if keep-counter c (dissoc c :counter :rec-counter :advance-counter))]
+    (if (and (= (:side c) "Runner") (not= (last (:zone c)) :facedown))
+      (dissoc c :installed :facedown :counter :rec-counter :pump :named-target) c)))
+
+(defn- trigger-leave-effect
+  "Triggers leave effects for specified card if relevant"
+  [state side card]
+  (when-let [leave-effect (:leave-play (card-def card))]
+    (when (or (and (= (:side card) "Runner") (:installed card) (not (:facedown card)))
+              (:rezzed card)
+              (= (first (:zone card)) :current)
+              (= (first (:zone card)) :scored))
+      (leave-effect state side card nil))))
+
+(defn- handle-prevent-effect
+  "Handles prevent effects on the card"
+  [state card]
+  (when-let [prevent (:prevent (card-def card))]
+     (doseq [[ptype pvec] prevent]
+       (doseq [psub pvec]
+         (swap! state update-in [:prevent ptype psub]
+                (fn [pv] (remove #(= (:cid %) (:cid card)) pv)))))))
 
 (defn deactivate
   "Deactivates a card, unregistering its events, removing certain attribute keys, and triggering
   some events."
   ([state side card] (deactivate state side card nil))
   ([state side card keep-counter]
-   (let [c (dissoc card :current-strength :abilities :rezzed :special :added-virus-counter)
-         c (if (and (= (:side c) "Runner") (not= (last (:zone c)) :facedown))
-             (dissoc c :installed :facedown :counter :rec-counter :pump :named-target) c)
-         c (if keep-counter c (dissoc c :counter :rec-counter :advance-counter))]
-     (when-let [leave-effect (:leave-play (card-def card))]
-       (when (or (and (= (:side card) "Runner") (:installed card) (not (:facedown card)))
-                 (:rezzed card)
-                 (= (first (:zone card)) :current)
-                 (= (first (:zone card)) :scored))
-         (leave-effect state side card nil)))
-     (when-let [prevent (:prevent (card-def card))]
-       (doseq [[ptype pvec] prevent]
-         (doseq [psub pvec]
-           (swap! state update-in [:prevent ptype psub] (fn [pv] (remove #(= (:cid %) (:cid card)) pv))))))
-     (unregister-events state side card)
-     (when (and (:memoryunits card) (:installed card) (not (:facedown card)))
-       (gain state :runner :memory (:memoryunits card)))
-     c)))
+   (trigger-leave-effect state side card)
+   (handle-prevent-effect state card)
+   (unregister-events state side card)
+   (when (and (:memoryunits card) (:installed card) (not (:facedown card)))
+     (gain state :runner :memory (:memoryunits card)))
+   (when-let [in-play (:in-play (card-def card))]
+     (apply lose state side in-play))
+   (dissoc-card card keep-counter)))
+
+
+;;; Initialising a card
+(defn- ability-init
+  "Gets abilities associated with the card"
+  [cdef]
+  (let [make-label #(or (:label %) (and (string? (:msg %)) (capitalize (:msg %))) "")
+        abilities (if (:recurring cdef)
+                    (conj (:abilities cdef) {:msg "Take 1 [Recurring Credits]"})
+                    (:abilities cdef))]
+    (for [ab abilities]
+      (assoc (select-keys ab [:cost :pump :breaks]) :label (make-label ab)))))
 
 (defn card-init
   "Initializes the abilities and events of the given card."
   ([state side card] (card-init state side card true))
   ([state side card resolve]
    (let [cdef (card-def card)
-         abilities (if (:recurring cdef)
-                     (conj (:abilities cdef) {:msg "Take 1 [Recurring Credits]"})
-                     (:abilities cdef))
-         abilities (for [ab abilities]
-                     (assoc (select-keys ab [:cost :pump :breaks])
-                       :label (or (:label ab) (and (string? (:msg ab)) (capitalize (:msg ab))) "")))
+         recurring (:recurring cdef)
+         abilities (ability-init cdef)
          c (merge card (:data cdef) {:abilities abilities})
-         c (if-let [r (:recurring cdef)]
-             (if (number? r) (assoc c :rec-counter r) c) c)]
-     (when-let [recurring (:recurring cdef)]
+         c (if (number? recurring) (assoc c :rec-counter recurring) c)]
+     (when recurring
        (let [r (if (number? recurring)
                  (effect (set-prop card :rec-counter recurring))
                  recurring)]

                 (when-let [dre (:derezzed-events cdef)]
                   (register-events state side dre moved-card))))))))))

(defn runner-install
  ([state side card] (runner-install state side card nil))
  ([state side {:keys [title type cost memoryunits uniqueness ] :as card}
    {:keys [extra-cost no-cost host-card facedown custom-message] :as params}]
   (when (not (seq (get-in @state [side :locked (-> card :zone first)])))
     (if-let [hosting (and (not host-card) (not facedown) (:hosting (card-def card)))]
       (resolve-ability state side
                        {:choices hosting
                         :effect (effect (runner-install card (assoc params :host-card target)))} card nil)
       (do
         (trigger-event state side :pre-install card)
         (let [cost (install-cost state side card
                                  (concat extra-cost (when (and (not no-cost) (not facedown)) [:credit cost])
                                          (when (and memoryunits (not facedown)) [:memory memoryunits])))]
           (when (and (or (not uniqueness) (not (in-play? state card)) facedown)
                      (if-let [req (:req (card-def card))]
                        (or facedown (req state side card nil)) true))
             (when-let [cost-str (pay state side card cost)]
               (let [c (if host-card
                         (host state side host-card card)
                         (move state side card [:rig (if facedown :facedown (to-keyword type))]))
                     installed-card (if facedown
                                      (update! state side (assoc c :installed true))
                                      (card-init state side (assoc c :installed true) true))]
                 (if facedown
                   (system-msg state side "installs a card facedown")
                   (if custom-message
                     (system-msg state side custom-message)
                     (system-msg state side (str (build-spend-msg cost-str "install") title
                                                 (when host-card (str " on " (:title host-card)))
                                                 (when no-cost " at no cost")))))
                 ;Apply added-virus-counter flag for this turn if the card enters play with a counter
                 (if (and (contains? installed-card :counter)
                          (contains? installed-card :subtype)
                          (has-subtype? card "Virus")
                          (pos? (:counter installed-card)))
                   (update! state side (assoc installed-card :added-virus-counter true)))
                 (trigger-event state side :runner-install installed-card)
                 (when (has-subtype? c "Icebreaker") (update-breaker-strength state side c))))))
         (when (is-type? card "Resource")
           (swap! state assoc-in [:runner :register :installed-resource] true))
         (swap! state update-in [:bonus] dissoc :install-cost))))))

               install-cost (if (and (ice? c) (not no-install-cost))
                              (count dest-zone) 0)
               install-state (or install-state (:install-state cdef))]
           (when (corp-can-install? card dest-zone)
             (when-let [cost-str (pay state side card extra-cost :credit install-cost)]
               (corp-install-asset-agenda state side c dest-zone)
               (corp-install-message state side c server install-state cost-str)
               (let [moved-card (move state side c slot)]
                 (trigger-event state side :corp-install moved-card)
                 (when (is-type? c "Agenda")
