<commit_before>//
//  LXPageViewWithButtonsViewController.swift
//
//  Created by XianLi on 23/3/2016.
//  Copyright © 2016 LXIAN. All rights reserved.
//

import Foundation
import UIKit

let LXPageViewWithButtonsViewControllerCurrentViewControllerDidChangeNotification = "LXPageViewWithButtonsViewControllerCurrentViewControllerDidChangeNotification"

public class LXPageViewWithButtonsViewController: UIViewController, UIPageViewControllerDelegate {
    /// page view controller
    public let pageViewController = UIPageViewController(transitionStyle: .Scroll, navigationOrientation: .Horizontal, options: nil)
    /// the scrollView inside the pageViewController
    private var _pageViewScrollView: UIView?
    var pageViewScrollView : UIView? {
        if _pageViewScrollView == nil {
            var views : [UIView] = [pageViewController.view]
            while views.count > 0 {
                let view = views[0]
                if view.isKindOfClass(UIScrollView) {
                    _pageViewScrollView = view
                    break
                }
                views.appendContentsOf(view.subviews)
                views.removeAtIndex(0)
            }
        }
        return _pageViewScrollView
    }
    /// buttons
    public let buttonsScrollView: LXButtonsScrollView = LXButtonsScrollView()
    /// data source required by UIpageViewController
    let pageViewControllerDataSource = LXPageViewWithButtonsViewControllerDataSource()
    
    /// page index
    var targetIndex: Int?
    var currentIdx = 0 {
        didSet {
            currentIdxUpdated()
        }
    }
    func currentIdxUpdated() {
        buttonsScrollView.buttons.forEach { $0.selected = false }
        buttonsScrollView.buttons[currentIdx].selected = true
        
        NSNotificationCenter.defaultCenter().postNotificationName(LXPageViewWithButtonsViewControllerCurrentViewControllerDidChangeNotification , object: self)
        
        /// scroll the scroll view if needed
        /// if the target button is already visible, then no need to scorll the view
        if !(targetIndex != nil && buttonsScrollView.isButtonVisible(targetIndex!)) {
            dispatch_async(dispatch_get_main_queue(), { [weak self] in
                self?.scrollButtonsViewToCurrentIndex()
                })
        }
        
        if currentIdx == targetIndex {
            targetIndex = nil
        }
    }
    
    public var viewControllers : [UIViewController]? {
        didSet {
            pageViewControllerDataSource.viewControllers = self.viewControllers
        }
    }
    public var currentViewController: UIViewController? {
        return viewControllers?[currentIdx]
    }
    
    public override func viewDidLoad() {
        super.viewDidLoad()
        setupPageViewController()
        setupButtons()
    }
    
    private var viewAppearedOnce = false
    public override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        if !viewAppearedOnce {
            pageViewController.setViewControllers([viewControllers![0]], direction: .Forward, animated: false, completion: nil)
            viewAppearedOnce = true
        }
    }
    
    deinit {
        pageViewScrollView?.removeObserver(self, forKeyPath: "contentOffset")
    }
    
    public override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    public override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        buttonsScrollView.translatesAutoresizingMaskIntoConstraints = false
        let pageViewControllerView = pageViewController.view
        pageViewControllerView.translatesAutoresizingMaskIntoConstraints = false
        
        
        NSLayoutConstraint.activateConstraints([
            NSLayoutConstraint(item: buttonsScrollView, attribute: .CenterX, relatedBy: .Equal, toItem: self.view, attribute: .CenterX, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: buttonsScrollView, attribute: .Top, relatedBy: .Equal, toItem: self.topLayoutGuide, attribute: .Bottom, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: buttonsScrollView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 30),
            NSLayoutConstraint(item: buttonsScrollView, attribute: .Width, relatedBy: .Equal, toItem: self.view, attribute: .Width, multiplier: 1, constant: 0)
            ])
        
        // layout pageViewController
        NSLayoutConstraint.activateConstraints([
            NSLayoutConstraint(item: pageViewControllerView, attribute: .CenterX, relatedBy: .Equal, toItem: self.view, attribute: .CenterX, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: pageViewControllerView, attribute: .Top, relatedBy: .Equal, toItem: buttonsScrollView, attribute: .Bottom, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: pageViewControllerView, attribute: .Bottom, relatedBy: .Equal, toItem: self.bottomLayoutGuide, attribute: .Top, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: pageViewControllerView, attribute: .Width, relatedBy: .Equal, toItem: self.view, attribute: .Width, multiplier: 1, constant: 0)
            ])
    }
    
    // MARK: - Setups
    public func setupButtons() {
        guard let viewControllers = viewControllers else { return }
        buttonsScrollView.setButtonTitles( viewControllers.map{ return $0.title ?? "" })
        view.addSubview(buttonsScrollView)<commit_msg>extract the function for layout to allow possibly override and layout customisation<commit_after>//
//  LXPageViewWithButtonsViewController.swift
//
//  Created by XianLi on 23/3/2016.
//  Copyright © 2016 LXIAN. All rights reserved.
//

import Foundation
import UIKit

let LXPageViewWithButtonsViewControllerCurrentViewControllerDidChangeNotification = "LXPageViewWithButtonsViewControllerCurrentViewControllerDidChangeNotification"

public class LXPageViewWithButtonsViewController: UIViewController, UIPageViewControllerDelegate {
    /// page view controller
    public let pageViewController = UIPageViewController(transitionStyle: .Scroll, navigationOrientation: .Horizontal, options: nil)
    /// the scrollView inside the pageViewController
    private var _pageViewScrollView: UIView?
    var pageViewScrollView : UIView? {
        if _pageViewScrollView == nil {
            var views : [UIView] = [pageViewController.view]
            while views.count > 0 {
                let view = views[0]
                if view.isKindOfClass(UIScrollView) {
                    _pageViewScrollView = view
                    break
                }
                views.appendContentsOf(view.subviews)
                views.removeAtIndex(0)
            }
        }
        return _pageViewScrollView
    }
    /// buttons
    public let buttonsScrollView: LXButtonsScrollView = LXButtonsScrollView()
    /// data source required by UIpageViewController
    let pageViewControllerDataSource = LXPageViewWithButtonsViewControllerDataSource()
    
    /// page index
    var targetIndex: Int?
    var currentIdx = 0 {
        didSet {
            currentIdxUpdated()
        }
    }
    func currentIdxUpdated() {
        buttonsScrollView.buttons.forEach { $0.selected = false }
        buttonsScrollView.buttons[currentIdx].selected = true
        
        NSNotificationCenter.defaultCenter().postNotificationName(LXPageViewWithButtonsViewControllerCurrentViewControllerDidChangeNotification , object: self)
        
        /// scroll the scroll view if needed
        /// if the target button is already visible, then no need to scorll the view
        if !(targetIndex != nil && buttonsScrollView.isButtonVisible(targetIndex!)) {
            dispatch_async(dispatch_get_main_queue(), { [weak self] in
                self?.scrollButtonsViewToCurrentIndex()
                })
        }
        
        if currentIdx == targetIndex {
            targetIndex = nil
        }
    }
    
    public var viewControllers : [UIViewController]? {
        didSet {
            pageViewControllerDataSource.viewControllers = self.viewControllers
        }
    }
    public var currentViewController: UIViewController? {
        return viewControllers?[currentIdx]
    }
    
    public override func viewDidLoad() {
        super.viewDidLoad()
        setupPageViewController()
        setupButtons()
    }
    
    private var viewAppearedOnce = false
    public override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        if !viewAppearedOnce {
            pageViewController.setViewControllers([viewControllers![0]], direction: .Forward, animated: false, completion: nil)
            viewAppearedOnce = true
        }
    }
    
    deinit {
        pageViewScrollView?.removeObserver(self, forKeyPath: "contentOffset")
    }
    
    public override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    public override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        
        lx_LayoutViews()
    }
    
    /// layout buttonsScrollView and page view controller's view 
    /// override this function if you want other layout
    func lx_LayoutViews() {
        /// layout the buttons scroll view
        buttonsScrollView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activateConstraints([
            NSLayoutConstraint(item: buttonsScrollView, attribute: .CenterX, relatedBy: .Equal, toItem: self.view, attribute: .CenterX, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: buttonsScrollView, attribute: .Top, relatedBy: .Equal, toItem: self.topLayoutGuide, attribute: .Bottom, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: buttonsScrollView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 30),
            NSLayoutConstraint(item: buttonsScrollView, attribute: .Width, relatedBy: .Equal, toItem: self.view, attribute: .Width, multiplier: 1, constant: 0)
            ])
        
        /// layout page view controllers' view
        let pageViewControllerView = pageViewController.view
        pageViewControllerView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activateConstraints([
            NSLayoutConstraint(item: pageViewControllerView, attribute: .CenterX, relatedBy: .Equal, toItem: self.view, attribute: .CenterX, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: pageViewControllerView, attribute: .Top, relatedBy: .Equal, toItem: buttonsScrollView, attribute: .Bottom, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: pageViewControllerView, attribute: .Bottom, relatedBy: .Equal, toItem: self.bottomLayoutGuide, attribute: .Top, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: pageViewControllerView, attribute: .Width, relatedBy: .Equal, toItem: self.view, attribute: .Width, multiplier: 1, constant: 0)
            ])
    }
    
    // MARK: - Setups
    public func setupButtons() {
        guard let viewControllers = viewControllers else { return }
        buttonsScrollView.setButtonTitles( viewControllers.map{ return $0.title ?? "" })
        view.addSubview(buttonsScrollView)
{'fraction_non_alphanumeric': 0.0804055235098759, 'fraction_numerical': 0.0061178115714036006, 'mean_word_length': 2.8502691790040378, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '6982430', 'n_tokens_mistral': 2969, 'n_tokens_neox': 2832, 'n_words': 720}