<commit_before>//
//  DispatchQueueController.swift
//  Incidents
//
//  © 2015 <NAME> and its contributors. All rights reserved.
//  See the file COPYRIGHT.md for terms.
//

import Cocoa



struct FilteredIncidentsCache {
    let searchText: String
    let incidents: [Incident]
    let openIncidents: [Incident]
}



class DispatchQueueController: NSWindowController {

    var appDelegate: AppDelegate!

    let ims: IncidentManagementSystem

    var incidentControllers: [Int: IncidentController] = [:]

    var reloadInterval: NSTimeInterval = 10
    var reloadTimer: NSTimer? = nil

    @IBOutlet weak var searchField     : NSSearchField?
    @IBOutlet weak var dispatchTable   : NSTableView?
    @IBOutlet weak var loadingIndicator: NSProgressIndicator?
    @IBOutlet weak var reloadButton    : NSButton?
    @IBOutlet weak var showClosedButton: NSButton?
    @IBOutlet weak var updatedLabel    : NSTextField?


    var searchText: String {
        guard let searchFieldCell = searchField?.cell as? NSSearchFieldCell else {
            return ""
        }
        return searchFieldCell.stringValue
    }


    var showClosed: Bool {
        guard let showClosedState = showClosedButton?.state else {
            return false
        }
        return showClosedState == NSOnState
    }


    var sortedIncidents: [Incident] {
        if _sortedIncidents == nil {
            if let sortDescriptors = dispatchTable?.sortDescriptors as [NSSortDescriptor]? {
                func isOrderedBefore(lhs: Incident, rhs: Incident) -> Bool {
                    return incident(lhs, isOrderedBeforeIncident: rhs, usingDescriptors: sortDescriptors)
                }
                _sortedIncidents = ims.incidentsByNumber.values.sort(isOrderedBefore)
            }
            else {
                func isOrderedBefore(i1: Incident, i2: Incident) -> Bool {
                    return i1.number < i2.number
                }
                _sortedIncidents = ims.incidentsByNumber.values.sort(isOrderedBefore)
            }
        }
        return _sortedIncidents!
    }
    private var _sortedIncidents: [Incident]? = nil


    var filteredIncidentsCache: FilteredIncidentsCache {
        if let cache = _filteredIncidentsCache {
            if cache.searchText == searchText {
                return cache
            }
        }

        var filteredIncidents    : [Incident] = []
        var filteredOpenIncidents: [Incident] = []

        for incident in sortedIncidents {
            // FIXME *************************  SEARCH  *************************************
            filteredIncidents.append(incident)

            if !showClosed && incident.state != IncidentState.Closed {
                filteredOpenIncidents.append(incident)
            }

        }

        _filteredIncidentsCache = FilteredIncidentsCache(
            searchText: searchText,
            incidents: filteredIncidents,
            openIncidents: filteredOpenIncidents
        )
        
        return _filteredIncidentsCache!
    }
    private var _filteredIncidentsCache: FilteredIncidentsCache? = nil


    convenience init(appDelegate: AppDelegate) {
        self.init(windowNibName: "DispatchQueue")

        self.appDelegate = appDelegate
    }


    override init(window: NSWindow?) {
//        ims = InMemoryIncidentManagementSystem()
//
//        // For debugging... ************************************************************************************
//        _populateWithFakeData(ims as! InMemoryIncidentManagementSystem)

        let defaults = NSUserDefaults.standardUserDefaults()

        let scheme: String
        if defaults.boolForKey("IMSServerDisableTLS") {
            scheme = "http"
        } else {
            scheme = "https"
        }

        let host: String
        if let _host = defaults.stringForKey("IMSServerHostName") {
            host = _host
        } else {
            host = "localhost"
        }

        let port: String
        if let _port = defaults.stringForKey("IMSServerPort") {
            port = ":\(_port)"
        } else {
            port = ""
        }

        let path = "/"

        let url = "\(scheme)://\(host)\(port)\(path)"

        logInfo("IMS Server: \(url)")
        ims = HTTPIncidentManagementSystem(url: url)

        super.init(window: window)

        ims.delegate = self
    }


    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


    func reload(force: Bool) {
        if force && reloadTimer != nil {
            reloadTimer!.invalidate()
            reloadTimer = nil
        }

        if (reloadTimer == nil || !reloadTimer!.valid) {
            ims.reload()

            logDebug("Restarting reload timer")
            reloadTimer = NSTimer.scheduledTimerWithTimeInterval(
                reloadInterval,
                target: self,
                selector: Selector("reloadTimerFired:"),
                userInfo: self,
                repeats: false
            )
        }
    }


    func reloadTimerFired(timer: NSTimer) {
        logDebug("Reloading after timer")
        reload(true)
    }


    func openIncident(incident: Incident) {
        guard let number = incident.number else {
            logError("Can't open an incident without a number")
            return
        }

        let incidentController: IncidentController

        if let _incidentController = incidentControllers[number] {
            // Already have a controller for the incident in question
            incidentController = _incidentController
        } else {
            // Create a controller for the incident in question
            incidentController = IncidentController(
                dispatchQueueController: self,
                incident: incident
            )
            incidentControllers[number] = incidentController
        }

        incidentController.showWindow(self)
        incidentController.window?.makeKeyAndOrderFront(self)

        // FIXME: Register for window closing notifcation?  (See old code.)
    }


    func openClickedIncident() {
        guard let dispatchTable = self.dispatchTable else { return }

        let rowIndex = dispatchTable.clickedRow

        let f = incidentForTableRow(rowIndex)
        if f.failed {
            logError("No incident for clicked row index \(rowIndex)")
            return
        }
        let incident = f.value!

        openIncident(incident)
    }

}



extension DispatchQueueController: IncidentManagementSystemDelegate {
    func incidentDidUpdate(ims: IncidentManagementSystem, incident: Incident) {
        resort(self)
    }
}



extension DispatchQueueController: NSWindowDelegate {

     override func windowDidLoad() {
        super.windowDidLoad()

        func arghEvilDeath(uiElementName: String) {
            fatalError("Dispatch queue controller: no \(uiElementName)?")
        }

        if window           == nil { arghEvilDeath("window"            ) }
        if searchField      == nil { arghEvilDeath("search field"      ) }
        if dispatchTable    == nil { arghEvilDeath("dispatch table"    ) }<commit_msg>Placeholder for notifying incident controller of a changed incident.<commit_after>//
//  DispatchQueueController.swift
//  Incidents
//
//  © 2015 <NAME> and its contributors. All rights reserved.
//  See the file COPYRIGHT.md for terms.
//

import Cocoa



struct FilteredIncidentsCache {
    let searchText: String
    let incidents: [Incident]
    let openIncidents: [Incident]
}



class DispatchQueueController: NSWindowController {

    var appDelegate: AppDelegate!

    let ims: IncidentManagementSystem

    var incidentControllers: [Int: IncidentController] = [:]

    var reloadInterval: NSTimeInterval = 10
    var reloadTimer: NSTimer? = nil

    @IBOutlet weak var searchField     : NSSearchField?
    @IBOutlet weak var dispatchTable   : NSTableView?
    @IBOutlet weak var loadingIndicator: NSProgressIndicator?
    @IBOutlet weak var reloadButton    : NSButton?
    @IBOutlet weak var showClosedButton: NSButton?
    @IBOutlet weak var updatedLabel    : NSTextField?


    var searchText: String {
        guard let searchFieldCell = searchField?.cell as? NSSearchFieldCell else {
            return ""
        }
        return searchFieldCell.stringValue
    }


    var showClosed: Bool {
        guard let showClosedState = showClosedButton?.state else {
            return false
        }
        return showClosedState == NSOnState
    }


    var sortedIncidents: [Incident] {
        if _sortedIncidents == nil {
            if let sortDescriptors = dispatchTable?.sortDescriptors as [NSSortDescriptor]? {
                func isOrderedBefore(lhs: Incident, rhs: Incident) -> Bool {
                    return incident(lhs, isOrderedBeforeIncident: rhs, usingDescriptors: sortDescriptors)
                }
                _sortedIncidents = ims.incidentsByNumber.values.sort(isOrderedBefore)
            }
            else {
                func isOrderedBefore(i1: Incident, i2: Incident) -> Bool {
                    return i1.number < i2.number
                }
                _sortedIncidents = ims.incidentsByNumber.values.sort(isOrderedBefore)
            }
        }
        return _sortedIncidents!
    }
    private var _sortedIncidents: [Incident]? = nil


    var filteredIncidentsCache: FilteredIncidentsCache {
        if let cache = _filteredIncidentsCache {
            if cache.searchText == searchText {
                return cache
            }
        }

        var filteredIncidents    : [Incident] = []
        var filteredOpenIncidents: [Incident] = []

        for incident in sortedIncidents {
            // FIXME *************************  SEARCH  *************************************
            filteredIncidents.append(incident)

            if !showClosed && incident.state != IncidentState.Closed {
                filteredOpenIncidents.append(incident)
            }

        }

        _filteredIncidentsCache = FilteredIncidentsCache(
            searchText: searchText,
            incidents: filteredIncidents,
            openIncidents: filteredOpenIncidents
        )
        
        return _filteredIncidentsCache!
    }
    private var _filteredIncidentsCache: FilteredIncidentsCache? = nil


    convenience init(appDelegate: AppDelegate) {
        self.init(windowNibName: "DispatchQueue")

        self.appDelegate = appDelegate
    }


    override init(window: NSWindow?) {
//        ims = InMemoryIncidentManagementSystem()
//
//        // For debugging... ************************************************************************************
//        _populateWithFakeData(ims as! InMemoryIncidentManagementSystem)

        let defaults = NSUserDefaults.standardUserDefaults()

        let scheme: String
        if defaults.boolForKey("IMSServerDisableTLS") {
            scheme = "http"
        } else {
            scheme = "https"
        }

        let host: String
        if let _host = defaults.stringForKey("IMSServerHostName") {
            host = _host
        } else {
            host = "localhost"
        }

        let port: String
        if let _port = defaults.stringForKey("IMSServerPort") {
            port = ":\(_port)"
        } else {
            port = ""
        }

        let path = "/"

        let url = "\(scheme)://\(host)\(port)\(path)"

        logInfo("IMS Server: \(url)")
        ims = HTTPIncidentManagementSystem(url: url)

        super.init(window: window)

        ims.delegate = self
    }


    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


    func reload(force: Bool) {
        if force && reloadTimer != nil {
            reloadTimer!.invalidate()
            reloadTimer = nil
        }

        if (reloadTimer == nil || !reloadTimer!.valid) {
            ims.reload()

            logDebug("Restarting reload timer")
            reloadTimer = NSTimer.scheduledTimerWithTimeInterval(
                reloadInterval,
                target: self,
                selector: Selector("reloadTimerFired:"),
                userInfo: self,
                repeats: false
            )
        }
    }


    func reloadTimerFired(timer: NSTimer) {
        logDebug("Reloading after timer")
        reload(true)
    }


    func openIncident(incident: Incident) {
        guard let number = incident.number else {
            logError("Can't open an incident without a number")
            return
        }

        let incidentController: IncidentController

        if let _incidentController = incidentControllers[number] {
            // Already have a controller for the incident in question
            incidentController = _incidentController
        } else {
            // Create a controller for the incident in question
            incidentController = IncidentController(
                dispatchQueueController: self,
                incident: incident
            )
            incidentControllers[number] = incidentController
        }

        incidentController.showWindow(self)
        incidentController.window?.makeKeyAndOrderFront(self)

        // FIXME: Register for window closing notifcation?  (See old code.)
    }


    func openClickedIncident() {
        guard let dispatchTable = self.dispatchTable else { return }

        let rowIndex = dispatchTable.clickedRow

        let f = incidentForTableRow(rowIndex)
        if f.failed {
            logError("No incident for clicked row index \(rowIndex)")
            return
        }
        let incident = f.value!

        openIncident(incident)
    }

}



extension DispatchQueueController: IncidentManagementSystemDelegate {

    func incidentDidUpdate(ims: IncidentManagementSystem, incident: Incident) {
        guard let number = incident.number else {
            logError("Updated incident has no number: \(incident)")
            return
        }
        
        logDebug("Incident updated: \(incident)")
        
        if let incidentController = incidentControllers[number] {
            alert(title: "Implement Me", message: "incidentDidUpdate() with controller \(incidentController)")
        }

        resort(self)
    }

}



extension DispatchQueueController: NSWindowDelegate {

     override func windowDidLoad() {
        super.windowDidLoad()

        func arghEvilDeath(uiElementName: String) {
            fatalError("Dispatch queue controller: no \(uiElementName)?")
        }

        if window           == nil { arghEvilDeath("window"            ) }
        if searchField      == nil { arghEvilDeath("search field"      ) }
        if dispatchTable    == nil { arghEvilDeath("dispatch table"    ) }
{'fraction_non_alphanumeric': 0.09828711256117455, 'fraction_numerical': 0.0013594344752582926, 'mean_word_length': 2.079321892005023, 'pattern_counts': {'":': 2, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4027286', 'n_tokens_mistral': 4037, 'n_tokens_neox': 3719, 'n_words': 911}