 
 // MARK: - ImageTaggerViewController: UIViewController, Alertable
 
-class ImageTaggerViewController: UIViewController, Alertable {
-    
-    // MARK: - Properties
-    
+final class ImageTaggerViewController: UIViewController, Alertable {
+    
+    // MARK: - Instance Variables
+
+    /// Image for analysis and discovery.
+    /// Hashtags will be generated using this image.
     var taggingImage: UIImage!
+
     var persistenceCentral: PersistenceCentral!
     
     private let imaggaApiClient = ImaggaApiClient.shared
-    
-    fileprivate var generatedTags: [ImaggaTag]?
-    fileprivate var createdCategory: Category?
-    fileprivate lazy var temporaryContext: NSManagedObjectContext = {
+
+    /// Generated hashtags from the `taggingImage`.
+    private var generatedTags: [ImaggaTag]?
+
+    /// Category associated with the `generatedTags`.
+    private var createdCategory: Category?
+
+    private lazy var temporaryContext: NSManagedObjectContext = {
         let context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
         context.persistentStoreCoordinator = self.persistenceCentral.coreDataStackManager.persistentStoreCoordinator
+
         return context
     }()
     
-    // MARK: Outlets
-    
-    @IBOutlet var cancelBarButtonItem: UIBarButtonItem!
+    // MARK: IBOutlets
+
     @IBOutlet var imageView: UIImageView!
     @IBOutlet var activityIndicator: UIActivityIndicatorView!
+    @IBOutlet var cancelBarButtonItem: UIBarButtonItem!
     @IBOutlet var generateBarButtonItem: UIBarButtonItem!
     @IBOutlet var resultsBarButtonItem: UIBarButtonItem!
     @IBOutlet var saveResultsBarButtonItem: UIBarButtonItem!
     
-    // MARK: - View Life Cycle
+    // MARK: - UIViewController lifecycle
     
     override func viewDidLoad() {
         super.viewDidLoad()

        configureUI()
    }
    
    // MARK: - Actions
    
    @IBAction func cancelDidPressed(_ sender: AnyObject) {
        dismiss(animated: true, completion: nil)
    }
    
    @IBAction func generateTags(_ sender: AnyObject) {
        setUIState(.networking)
        imaggaApiClient.taggingImage(taggingImage, success: { [weak self] tags in
            self?.processOnGeneratedTags(tags)
        }) { [weak self] error in
            self?.generatedTags = nil
            self?.setUIState(.doneWithNetworking)
            let alert = self?.alert("Error", message: error.localizedDescription, handler: nil)
            self?.present(alert!, animated: true, completion: nil)
        }
    }
    
    @IBAction func showResults(_ sender: AnyObject) {
        let tagListViewController = TagListViewController(persistenceCentral: persistenceCentral)
        
        if let createdCategory = createdCategory {
            tagListViewController.category = createdCategory
        } else {

            tagListViewController.tags = ImaggaTag.map(on: generatedTags!,
                                                       in: temporaryContext)
        }

        navigationController?.pushViewController(tagListViewController, animated: true)
    }

    @IBAction func saveResults(_ sender: AnyObject) {
        func showAlert() {
            let alert = self.alert(
                "Invalid category name",
                message: "Try again",
                handler: { [weak self] in
                    self?.saveResults($0)
                }
            )

            present(alert, animated: true, completion: nil)
        }

        var categoryNameTextField: UITextField?

        let alert = UIAlertController(title: "Create Category",
                                      message: "To save the tags, please enter the category name.",
                                      preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
        alert.addAction(UIAlertAction(title: "Save", style: .default, handler: { [unowned self] _ in
            guard let name = categoryNameTextField?.text, !name.isEmpty else {
                showAlert()
                return
            }

            self.createCategory(with: name)
        }))
        alert.addTextField { textField in
            categoryNameTextField = textField
            categoryNameTextField?.placeholder = "Enter category name"
        }

        present(alert, animated: true, completion: nil)
    }

}

// MARK: - ImageTaggerViewController (UI) -

extension ImageTaggerViewController {
    
    private func configureUI() {
        setUIState(.default)
        navigationController?.view.backgroundColor = .white
        navigationItem.backBarButtonItem = UIBarButtonItem(title: "Back",
                                                           style: .plain,
                                                           target: nil,
                                                           action: nil)
    }
    
    private func setUIState(_ state: UIState) {
        switch state {
        case .default:
            imageView.image = taggingImage
