<commit_before>//
//  GenericControllerOfSettings.swift
//  ASToolkit
//
//  Created by <NAME> on 3/25/16.
//  Copyright © 2017 <NAME>. All rights reserved.
//

import Foundation
import UIKit

open class GenericControllerOfSettings : UITableViewController
{
    
    
    public typealias FunctionOnCell                         = (_ cell:UITableViewCell, _ indexPath:IndexPath) -> ()
    public typealias Update                                 = Action
    public typealias Action                                 = () -> ()
    public typealias FunctionUpdateOnUISwitch               = (UISwitch) -> ()
    public typealias FunctionUpdateOnUISlider               = (UISlider) -> ()
    public typealias FunctionUpdateOnUITextField            = (UITextField) -> ()
    
    
    
    
    
    var actions                             : [IndexPath : Action]                  = [:]
    var updates                             : [Update]                              = []
    
    var registeredUISwitches                : [UISwitch : FunctionUpdateOnUISwitch] = [:]
    var registeredUISliders                 : [UISlider : FunctionUpdateOnUISlider] = [:]
    var registeredUITextFields:[UITextField : FunctionUpdateOnUITextField]          = [:]

    
    

    open weak var manager                   : GenericManagerOfSettings?
    
    
    public struct Section {
        public var header                   : String?
        public var footer                   : String?
        public var cells                    : [FunctionOnCell]
        
        public init(header:String? = nil,
                    footer:String? = nil,
                    cells :[FunctionOnCell]? = nil) {
            self.header = header
            self.footer = footer
            self.cells  = cells ?? []
        }
    }
    
    open var sections                       : [Section]                             = []

    open func row(at:IndexPath) -> FunctionOnCell? {
        return sections[safe:at.section]?.cells[safe:at.item]
    }
    
    open var elementCornerRadius            : CGFloat                               = 4
    open var elementBackgroundColor         : UIColor                               = UIColor(white:1,alpha:0.3)
    open var colorForHeaderText             : UIColor?
    open var colorForFooterText             : UIColor?
    

    static open var lastOffsetY             : [String:CGPoint]                      = [:]
    
    
    
    
    
    // MARK: - PRIVATE METHODS
    
    // MARK: - OPEN METHODS
    
    open func createSections() -> [Section]
    {
        return [Section]()
    }
    

    
    // MARK: - UIViewController
    
    
    open func reload()
    {
        tableView.reloadData()
    }
    
    override open func viewDidLoad()
    {
        tableView = UITableView(frame:tableView.frame, style:.grouped)

        self.edgesForExtendedLayout = UIRectEdge.init(rawValue: 0)
        
        super.viewDidLoad()
    }
    
    override open func viewWillAppear(_ animated: Bool)
    {
        registeredUISliders.removeAll()
        registeredUISwitches.removeAll()
        
        updates.removeAll()
        
        actions.removeAll()
        
        sections = createSections()
        
        reload()
        
        if let title = super.title {
            if let point = GenericControllerOfSettings.lastOffsetY[title] {
                tableView.setContentOffset(point,animated:true)
            }
        }
        
        super.viewWillAppear(animated)
        
    }
    
    
    override open func viewWillDisappear(_ animated: Bool)
    {
        if let title = super.title {
            GenericControllerOfSettings.lastOffsetY[title] = tableView.contentOffset
        }
        
        registeredUISliders.removeAll()
        registeredUISwitches.removeAll()
        
        for update in updates {
            update()
        }
        
        updates.removeAll()
        
        sections.removeAll()
        
        actions.removeAll()
        
        manager?.synchronize()
        
        super.viewWillDisappear(animated)
    }
    
    

    
    
    // MARK: - UITableView
    
    override open func numberOfSections              (in: UITableView) -> Int
    {
        return sections.count
    }
    
    override open func tableView                     (_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return sections[section].cells.count
    }
    
    override open func tableView                     (_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
    {
        return sections[section].header
    }
    
    override open func tableView                     (_ tableView: UITableView, titleForFooterInSection section: Int) -> String?
    {
        return sections[section].footer
    }
    
    override open func tableView                     (_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        let cell = UITableViewCell(style:.value1, reuseIdentifier:nil)
        
        cell.selectionStyle = .none
        
        if let HSBA = cell.backgroundColor?.HSBA {
            if 1 <= HSBA.alpha {
                cell.backgroundColor = cell.backgroundColor!.withAlphaComponent(0.50)
            }
        }
        else {
            cell.backgroundColor = UIColor(white:1,alpha:0.7)
        }
        
        sections[indexPath.section].cells[indexPath.row](cell,indexPath)
        
        return cell
    }
    
    
    
    
    
    
    override open func tableView                     (_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
        
        if let view = view as? UITableViewHeaderFooterView {
            if let color = colorForHeaderText {
                view.textLabel?.textColor = color
            }
        }
        
    }
    

    override open func tableView                     (_ tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int) {
        
        if let view = view as? UITableViewHeaderFooterView {
            if let color = colorForFooterText {
                view.textLabel?.textColor = color
            }
        }
        
    }
    

    
    
    
    
    // MARK: - Actions
    
    open func addAction(indexPath:IndexPath, action:@escaping Action) {
        actions[indexPath] = action
    }
    
    open func registerCellSelection(indexPath:IndexPath, action:@escaping Action) {
        addAction(indexPath: indexPath,action:action)
    }
    
    override open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
    {
        if let action = actions[indexPath] {
            action()
        }
    }
    
    
    
    
    
    // MARK: - Updates 
    
    open func addUpdate(update:@escaping Update) {
        updates.append(update)
    }
    
    
    
    
    
    
    // MARK: - Alerts
    
    open func createAlertForInput               (title:String, message:String, value:String = "", ok:String = "Ok", cancel:String = "Cancel", setter:@escaping (String)->()) {
        let alert = UIAlertController.init(title: title, message: message, preferredStyle: .alert)
        alert.addTextField { textfield in
            textfield.text = value
        }
        let ok = UIAlertAction.init(title: ok, style: UIAlertActionStyle.default) { action in
            setter(alert.textFields?[safe:0]?.text ?? "")
            alert.dismiss(animated: true) {
            }
        }
        alert.addAction(ok)
        let cancel = UIAlertAction.init(title: cancel, style: UIAlertActionStyle.cancel) { action in
            alert.dismiss(animated: true) {
            }
        }
        alert.addAction(cancel)
        self.present(alert, animated: true)
    }
    
    open func createAlertForQuestion            (title:String, message:String, ok:String = "Ok", cancel:String = "Cancel", handler:@escaping Action) {
        let alert = UIAlertController.init(title: title, message: message, preferredStyle: .alert)
        let ok = UIAlertAction.init(title: ok, style: UIAlertActionStyle.default) { action in
            handler()
            alert.dismiss(animated: true) {
            }
        }
        alert.addAction(ok)
        let cancel = UIAlertAction.init(title: cancel, style: UIAlertActionStyle.cancel) { action in
            alert.dismiss(animated: true) {
            }
        }
        alert.addAction(cancel)
        self.present(alert, animated: true)
    }
    
    open func createAlertForUITextField         (_ field:UITextField, title:String, message:String, ok:String = "Ok", cancel:String = "Cancel", setter:@escaping (String)->()) {
        let alert = UIAlertController.init(title: title, message: message, preferredStyle: .alert)
        alert.addTextField { textfield in
            textfield.text = field.text
        }
        let ok = UIAlertAction.init(title: ok, style: UIAlertActionStyle.default) { action in
            setter(alert.textFields?[safe:0]?.text ?? "")
            alert.dismiss(animated: true) {
            }
        }
        alert.addAction(ok)
        let cancel = UIAlertAction.init(title: cancel, style: UIAlertActionStyle.cancel) { action in
            alert.dismiss(animated: true) {
            }
        }
        alert.addAction(cancel)
        self.present(alert, animated: true)
    }
    
    open func createAlertForChoice              (title:String, message:String, choices:[String], cancel:String = "Cancel", handler:@escaping (String)->()) {
        let alert = UIAlertController.init(title: title, message: message, preferredStyle: .actionSheet)
        for choice in choices {
            let ok = UIAlertAction.init(title: choice, style: .destructive) { action in
                handler(choice)
//                alert.dismiss(animated: true) {
//                }
            }
            alert.addAction(ok)
        }
        let cancel = UIAlertAction.init(title: cancel, style: .cancel) { action in
            alert.dismiss(animated: true) {
            }
        }
        alert.addAction(cancel)
        self.present(alert, animated: true)
    }
    

    
    
    
    
    // MARK: - CREATE CELL - TAP
    
    open func createCellForTap                      (title:String, setup:((UITableViewCell,IndexPath)->())? = nil, action:Action? = nil ) -> FunctionOnCell {
        
        return { (cell:UITableViewCell, indexPath:IndexPath) in
            if let label = cell.textLabel {
                cell.selectionStyle = .default
                label.text          = title
                setup?(cell,indexPath)
                if let action = action {
                    self.addAction(indexPath: indexPath, action: action)
                }
            }
        }
        
    }
    

    open func createCellForTapOnQuestion            (title:String, message:String, ok:String = "Ok", cancel:String = "Cancel", setup:((UITableViewCell,IndexPath)->())? = nil, action:Action? = nil) -> FunctionOnCell {
        
        return { (cell:UITableViewCell, indexPath:IndexPath) in
            if let label = cell.textLabel {
                cell.selectionStyle = .default
                label.text          = title
                setup?(cell,indexPath)
                self.addAction(indexPath: indexPath) { [weak self] in
                    self?.createAlertForQuestion(title: title, message: message, ok:ok, cancel:cancel) {
                        action?()
                    }
                }
            }
        }
        
    }
    
    open func createCellForTapOnInput               (title:String, message:String, ok:String = "Ok", cancel:String = "Cancel", setup:((UITableViewCell,IndexPath)->())? = nil, value:@escaping ()->String, action:@escaping (String)->()) -> FunctionOnCell {
        
        return { (cell:UITableViewCell, indexPath:IndexPath) in
            if let label = cell.textLabel {
                cell.selectionStyle = .default
                label.text          = title
                setup?(cell,indexPath)
                self.addAction(indexPath: indexPath) { [weak self] in
                    self?.createAlertForInput(title: title, message: message, value:value(), ok:ok, cancel:cancel) { result in
                        action(result)
                    }
                }
            }
        }
        
    }
    
    open func createCellForTapOnChoice              (title:String, message:String, choices:@escaping ()->([String]), cancel:String = "Cancel", setup:((UITableViewCell,IndexPath)->())? = nil, action:@escaping (String)->()) -> FunctionOnCell {
        
        return { (cell:UITableViewCell, indexPath:IndexPath) in
            if let label = cell.textLabel {
                cell.selectionStyle = .default
                label.text          = title
                setup?(cell,indexPath)
                self.addAction(indexPath: indexPath) { [weak self] in
                    self?.createAlertForChoice(title: title, message: message, choices:choices(), cancel:cancel) { result in
                        action(result)
                    }
                }
            }
        }
        
    }
    

    
    
<commit_msg>fix for untrimmed titles in alerts<commit_after>//
//  GenericControllerOfSettings.swift
//  ASToolkit
//
//  Created by <NAME> on 3/25/16.
//  Copyright © 2017 <NAME>. All rights reserved.
//

import Foundation
import UIKit

open class GenericControllerOfSettings : UITableViewController
{
    
    
    public typealias FunctionOnCell                         = (_ cell:UITableViewCell, _ indexPath:IndexPath) -> ()
    public typealias Update                                 = Action
    public typealias Action                                 = () -> ()
    public typealias FunctionUpdateOnUISwitch               = (UISwitch) -> ()
    public typealias FunctionUpdateOnUISlider               = (UISlider) -> ()
    public typealias FunctionUpdateOnUITextField            = (UITextField) -> ()
    
    
    
    
    
    var actions                             : [IndexPath : Action]                  = [:]
    var updates                             : [Update]                              = []
    
    var registeredUISwitches                : [UISwitch : FunctionUpdateOnUISwitch] = [:]
    var registeredUISliders                 : [UISlider : FunctionUpdateOnUISlider] = [:]
    var registeredUITextFields:[UITextField : FunctionUpdateOnUITextField]          = [:]

    
    

    open weak var manager                   : GenericManagerOfSettings?
    
    
    public struct Section {
        public var header                   : String?
        public var footer                   : String?
        public var cells                    : [FunctionOnCell]
        
        public init(header:String? = nil,
                    footer:String? = nil,
                    cells :[FunctionOnCell]? = nil) {
            self.header = header
            self.footer = footer
            self.cells  = cells ?? []
        }
    }
    
    open var sections                       : [Section]                             = []

    open func row(at:IndexPath) -> FunctionOnCell? {
        return sections[safe:at.section]?.cells[safe:at.item]
    }
    
    open var elementCornerRadius            : CGFloat                               = 4
    open var elementBackgroundColor         : UIColor                               = UIColor(white:1,alpha:0.3)
    open var colorForHeaderText             : UIColor?
    open var colorForFooterText             : UIColor?
    

    static open var lastOffsetY             : [String:CGPoint]                      = [:]
    
    
    
    
    
    // MARK: - PRIVATE METHODS
    
    // MARK: - OPEN METHODS
    
    open func createSections() -> [Section]
    {
        return [Section]()
    }
    

    
    // MARK: - UIViewController
    
    
    open func reload()
    {
        tableView.reloadData()
    }
    
    override open func viewDidLoad()
    {
        tableView = UITableView(frame:tableView.frame, style:.grouped)

        self.edgesForExtendedLayout = UIRectEdge.init(rawValue: 0)
        
        super.viewDidLoad()
    }
    
    override open func viewWillAppear(_ animated: Bool)
    {
        registeredUISliders.removeAll()
        registeredUISwitches.removeAll()
        
        updates.removeAll()
        
        actions.removeAll()
        
        sections = createSections()
        
        reload()
        
        if let title = super.title {
            if let point = GenericControllerOfSettings.lastOffsetY[title] {
                tableView.setContentOffset(point,animated:true)
            }
        }
        
        super.viewWillAppear(animated)
        
    }
    
    
    override open func viewWillDisappear(_ animated: Bool)
    {
        if let title = super.title {
            GenericControllerOfSettings.lastOffsetY[title] = tableView.contentOffset
        }
        
        registeredUISliders.removeAll()
        registeredUISwitches.removeAll()
        
        for update in updates {
            update()
        }
        
        updates.removeAll()
        
        sections.removeAll()
        
        actions.removeAll()
        
        manager?.synchronize()
        
        super.viewWillDisappear(animated)
    }
    
    

    
    
    // MARK: - UITableView
    
    override open func numberOfSections              (in: UITableView) -> Int
    {
        return sections.count
    }
    
    override open func tableView                     (_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return sections[section].cells.count
    }
    
    override open func tableView                     (_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
    {
        return sections[section].header
    }
    
    override open func tableView                     (_ tableView: UITableView, titleForFooterInSection section: Int) -> String?
    {
        return sections[section].footer
    }
    
    override open func tableView                     (_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        let cell = UITableViewCell(style:.value1, reuseIdentifier:nil)
        
        cell.selectionStyle = .none
        
        if let HSBA = cell.backgroundColor?.HSBA {
            if 1 <= HSBA.alpha {
                cell.backgroundColor = cell.backgroundColor!.withAlphaComponent(0.50)
            }
        }
        else {
            cell.backgroundColor = UIColor(white:1,alpha:0.7)
        }
        
        sections[indexPath.section].cells[indexPath.row](cell,indexPath)
        
        return cell
    }
    
    
    
    
    
    
    override open func tableView                     (_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
        
        if let view = view as? UITableViewHeaderFooterView {
            if let color = colorForHeaderText {
                view.textLabel?.textColor = color
            }
        }
        
    }
    

    override open func tableView                     (_ tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int) {
        
        if let view = view as? UITableViewHeaderFooterView {
            if let color = colorForFooterText {
                view.textLabel?.textColor = color
            }
        }
        
    }
    

    
    
    
    
    // MARK: - Actions
    
    open func addAction(indexPath:IndexPath, action:@escaping Action) {
        actions[indexPath] = action
    }
    
    open func registerCellSelection(indexPath:IndexPath, action:@escaping Action) {
        addAction(indexPath: indexPath,action:action)
    }
    
    override open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
    {
        if let action = actions[indexPath] {
            action()
        }
    }
    
    
    
    
    
    // MARK: - Updates 
    
    open func addUpdate(update:@escaping Update) {
        updates.append(update)
    }
    
    
    
    
    
    
    // MARK: - Alerts
    
    open func createAlertForInput               (title:String, message:String, value:String = "", ok:String = "Ok", cancel:String = "Cancel", setter:@escaping (String)->()) {
        let alert = UIAlertController.init(title: title, message: message, preferredStyle: .alert)
        alert.addTextField { textfield in
            textfield.text = value
        }
        let ok = UIAlertAction.init(title: ok, style: UIAlertActionStyle.default) { action in
            setter(alert.textFields?[safe:0]?.text ?? "")
            alert.dismiss(animated: true) {
            }
        }
        alert.addAction(ok)
        let cancel = UIAlertAction.init(title: cancel, style: UIAlertActionStyle.cancel) { action in
            alert.dismiss(animated: true) {
            }
        }
        alert.addAction(cancel)
        self.present(alert, animated: true)
    }
    
    open func createAlertForQuestion            (title:String, message:String, ok:String = "Ok", cancel:String = "Cancel", handler:@escaping Action) {
        let alert = UIAlertController.init(title: title, message: message, preferredStyle: .alert)
        let ok = UIAlertAction.init(title: ok, style: UIAlertActionStyle.default) { action in
            handler()
            alert.dismiss(animated: true) {
            }
        }
        alert.addAction(ok)
        let cancel = UIAlertAction.init(title: cancel, style: UIAlertActionStyle.cancel) { action in
            alert.dismiss(animated: true) {
            }
        }
        alert.addAction(cancel)
        self.present(alert, animated: true)
    }
    
    open func createAlertForUITextField         (_ field:UITextField, title:String, message:String, ok:String = "Ok", cancel:String = "Cancel", setter:@escaping (String)->()) {
        let alert = UIAlertController.init(title: title, message: message, preferredStyle: .alert)
        alert.addTextField { textfield in
            textfield.text = field.text
        }
        let ok = UIAlertAction.init(title: ok, style: UIAlertActionStyle.default) { action in
            setter(alert.textFields?[safe:0]?.text ?? "")
            alert.dismiss(animated: true) {
            }
        }
        alert.addAction(ok)
        let cancel = UIAlertAction.init(title: cancel, style: UIAlertActionStyle.cancel) { action in
            alert.dismiss(animated: true) {
            }
        }
        alert.addAction(cancel)
        self.present(alert, animated: true)
    }
    
    open func createAlertForChoice              (title:String, message:String, choices:[String], cancel:String = "Cancel", handler:@escaping (String)->()) {
        let alert = UIAlertController.init(title: title, message: message, preferredStyle: .actionSheet)
        for choice in choices {
            let ok = UIAlertAction.init(title: choice, style: .destructive) { action in
                handler(choice)
//                alert.dismiss(animated: true) {
//                }
            }
            alert.addAction(ok)
        }
        let cancel = UIAlertAction.init(title: cancel, style: .cancel) { action in
            alert.dismiss(animated: true) {
            }
        }
        alert.addAction(cancel)
        self.present(alert, animated: true)
    }
    

    
    
    
    
    // MARK: - CREATE CELL - TAP
    
    open func createCellForTap                      (title:String, setup:((UITableViewCell,IndexPath)->())? = nil, action:Action? = nil ) -> FunctionOnCell {
        
        return { (cell:UITableViewCell, indexPath:IndexPath) in
            if let label = cell.textLabel {
                cell.selectionStyle = .default
                label.text          = title
                setup?(cell,indexPath)
                if let action = action {
                    self.addAction(indexPath: indexPath, action: action)
                }
            }
        }
        
    }
    

    open func createCellForTapOnQuestion            (title:String, message:String, ok:String = "Ok", cancel:String = "Cancel", setup:((UITableViewCell,IndexPath)->())? = nil, action:Action? = nil) -> FunctionOnCell {
        
        return { (cell:UITableViewCell, indexPath:IndexPath) in
            if let label = cell.textLabel {
                cell.selectionStyle = .default
                label.text          = title
                setup?(cell,indexPath)
                self.addAction(indexPath: indexPath) { [weak self] in
                    self?.createAlertForQuestion(title: title.trimmed(), message: message.trimmed(), ok:ok, cancel:cancel) {
                        action?()
                    }
                }
            }
        }
        
    }
    
    open func createCellForTapOnInput               (title:String, message:String, ok:String = "Ok", cancel:String = "Cancel", setup:((UITableViewCell,IndexPath)->())? = nil, value:@escaping ()->String, action:@escaping (String)->()) -> FunctionOnCell {
        
        return { (cell:UITableViewCell, indexPath:IndexPath) in
            if let label = cell.textLabel {
                cell.selectionStyle = .default
                label.text          = title
                setup?(cell,indexPath)
                self.addAction(indexPath: indexPath) { [weak self] in
                    self?.createAlertForInput(title: title.trimmed(), message: message.trimmed(), value:value(), ok:ok, cancel:cancel) { result in
                        action(result)
                    }
                }
            }
        }
        
    }
    
    open func createCellForTapOnChoice              (title:String, message:String, choices:@escaping ()->([String]), cancel:String = "Cancel", setup:((UITableViewCell,IndexPath)->())? = nil, action:@escaping (String)->()) -> FunctionOnCell {
        
        return { (cell:UITableViewCell, indexPath:IndexPath) in
            if let label = cell.textLabel {
                cell.selectionStyle = .default
                label.text          = title
                setup?(cell,indexPath)
                self.addAction(indexPath: indexPath) { [weak self] in
                    self?.createAlertForChoice(title: title.trimmed(), message: message.trimmed(), choices:choices(), cancel:cancel) { result in
                        action(result)
                    }
                }
            }
        }
        
    }
    

    
    

{'fraction_non_alphanumeric': 0.09259189443920829, 'fraction_numerical': 0.0018096135721017907, 'mean_word_length': 1.5889127464376342, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5820245', 'n_tokens_mistral': 7281, 'n_tokens_neox': 6903, 'n_words': 1457}