<commit_before>
import Foundation
import BlocksKit
import Tweaks

extension WMFArticleViewController : WMFTableOfContentsViewControllerDelegate {

    public func tableOfContentsControllerWillDisplay(controller: WMFTableOfContentsViewController){
        if let item: TableOfContentsItem = webViewController.currentVisibleSection() {
            tableOfContentsViewController!.selectAndScrollToItem(item, animated: false)
        } else if let footerIndex: WMFArticleFooterViewIndex = WMFArticleFooterViewIndex(rawValue: webViewController.visibleFooterIndex()) {
            switch footerIndex {
            case .ReadMore:
                tableOfContentsViewController!.selectAndScrollToItem(TableOfContentsReadMoreItem(site: self.articleTitle.site), animated: false)
            }
        } else {
            assertionFailure("Couldn't find current position of user at current offset!")
        }
    }

    public func tableOfContentsController(controller: WMFTableOfContentsViewController,
                                          didSelectItem item: TableOfContentsItem) {
        var dismissVCCompletionHandler: (() -> Void)?
        if let section = item as? MWKSection {
            // HAX: webview has issues scrolling when browser view is out of bounds, disable animation if needed
            self.webViewController.scrollToSection(section, animated: self.webViewController.isWebContentVisible)
            dismissVCCompletionHandler = {
                // HAX: This is terrible, but iOS events not under our control would steal our focus if we didn't wait long enough here and due to problems in UIWebView, we cannot work around it either.
                dispatchOnMainQueueAfterDelayInSeconds(1) {
                    self.webViewController.accessibilityCursorToSection(section)
                }
            }
        } else if let footerItem = item as? TableOfContentsFooterItem {
            let footerIndex = UInt(footerItem.footerViewIndex.rawValue)
            self.webViewController.scrollToFooterAtIndex(footerIndex)
            dismissVCCompletionHandler = {
                self.webViewController.accessibilityCursorToFooterAtIndex(footerIndex)
            }
        } else {
            assertionFailure("Unsupported selection of TOC item \(item)")
        }

        // Don't dismiss immediately - it looks jarring - let the user see the ToC selection before dismissing
        dispatchOnMainQueueAfterDelayInSeconds(0.25) {
            self.dismissViewControllerAnimated(true, completion: dismissVCCompletionHandler)
        }
    }

    public func tableOfContentsControllerDidCancel(controller: WMFTableOfContentsViewController) {
        dismissViewControllerAnimated(true, completion: nil)
    }

    public func tableOfContentsArticleSite() -> MWKSite {
        return self.articleTitle.site
    }
}

extension WMFArticleViewController {

    /**
     Create ToC items.

     - note: This must be done in Swift because `WMFTableOfContentsViewControllerDelegate` is not an ObjC protocol,
     and therefore cannot be referenced in Objective-C.

     - returns: sections of the ToC.
     */
    func createTableOfContentsSections() -> [TableOfContentsItem]? {
        // HAX: need to forcibly downcast each section object to our protocol type. yay objc/swift interop!
        return hasTableOfContents() ? article?.sections?.entries.map() { $0 as! TableOfContentsItem } : nil
    }

    /**
    Create a new instance of `WMFTableOfContentsViewController` which is configured to be used with the receiver.
    */
    public func createTableOfContentsViewControllerIfNeeded() {
        if let items = createTableOfContentsSections() {
            self.tableOfContentsViewController = WMFTableOfContentsViewController(presentingViewController: self, items: items, delegate: self)
        }
    }

    /**
     Append a read more section to the table of contents.
     */
    public func appendReadMoreTableOfContentsItemIfNeeded() {
        assert(self.tableOfContentsViewController != nil, "Attempting to add read more when toc is nil")
        guard let tvc = self.tableOfContentsViewController
              where !tvc.items.contains({ (item: TableOfContentsItem) in item.dynamicType == TableOfContentsReadMoreItem.self })
              else { return }
        if var items = createTableOfContentsSections() {
            items.append(TableOfContentsReadMoreItem(site: self.articleTitle.site))
            tvc.items = items
        }
    }

    public func showTableOfContents() {
        presentViewController(self.tableOfContentsViewController!, animated: true, completion: nil)

    }
    
    func backgroundView() -> UIVisualEffectView {
        let view = UIVisualEffectView(frame: CGRectZero)
        view.autoresizingMask = .FlexibleWidth
        view.effect = UIBlurEffect(style: .Light)
        view.alpha = 0.0
        return view
    }
    
    class func registerTweak(){
        let tweak = FBTweak(identifier: "Always Peek ToC")
        tweak.name = "Always Peek ToC"
        tweak.defaultValue = false
        
        let collection = FBTweakCollection(name: "Table of Contents");
        collection.addTweak(tweak)

        let store = FBTweakStore.sharedInstance()
        let category = store.tweakCategoryWithName("Article")

        category.addTweakCollection(collection);
    }
    
    func shouldPeek() -> Bool {
        let store = FBTweakStore.sharedInstance()
        let category = store.tweakCategoryWithName("Article")
        let collection = category.tweakCollectionWithName("Table of Contents")
        let tweak = collection.tweakWithIdentifier("Always Peek ToC")
        if tweak.currentValue as? Bool == true {
            return true
        }
        
        return !NSUserDefaults.standardUserDefaults().wmf_didPeekTableOfContents()
    }

    public func peekTableOfContentsIfNeccesary() {
        guard self.navigationController != nil else{
            return
        }
        guard let toc = self.tableOfContentsViewController else{
            return
        }
        guard shouldPeek() == true else{
            return
        }

        let bg = backgroundView()
        
        let containerBounds = self.navigationController!.view.bounds
        bg.frame = containerBounds
        self.navigationController!.view!.addSubview(bg)

        let maxToCWidth: CGFloat = 300.0
        let peekWidth = (containerBounds.width * 0.3) < maxToCWidth ? containerBounds.width * 0.3 : maxToCWidth
        let tocWidth = (containerBounds.width * 0.4) < maxToCWidth ? containerBounds.width * 0.4 : maxToCWidth
        
        var onscreen = containerBounds
        onscreen.size.width = tocWidth
        var offscreen = onscreen
        
        if UIApplication.sharedApplication().wmf_tocShouldBeOnLeft {
            offscreen.origin.x -= offscreen.width
            onscreen.origin.x = offscreen.origin.x + peekWidth
        }else{
            onscreen.origin.x = containerBounds.width - peekWidth
            offscreen.origin.x = containerBounds.width
        }
        
        toc.view.frame = offscreen
        toc.view.layer.shadowOpacity = 0.25
        toc.view.layer.shadowRadius = 4.0
        toc.view.layer.shadowOffset = CGSizeZero
        
        self.navigationController!.view!.addSubview(toc.view)
        <commit_msg>Fix toc peek being wrapped<commit_after>
import Foundation
import BlocksKit
import Tweaks

extension WMFArticleViewController : WMFTableOfContentsViewControllerDelegate {

    public func tableOfContentsControllerWillDisplay(controller: WMFTableOfContentsViewController){
        if let item: TableOfContentsItem = webViewController.currentVisibleSection() {
            tableOfContentsViewController!.selectAndScrollToItem(item, animated: false)
        } else if let footerIndex: WMFArticleFooterViewIndex = WMFArticleFooterViewIndex(rawValue: webViewController.visibleFooterIndex()) {
            switch footerIndex {
            case .ReadMore:
                tableOfContentsViewController!.selectAndScrollToItem(TableOfContentsReadMoreItem(site: self.articleTitle.site), animated: false)
            }
        } else {
            assertionFailure("Couldn't find current position of user at current offset!")
        }
    }

    public func tableOfContentsController(controller: WMFTableOfContentsViewController,
                                          didSelectItem item: TableOfContentsItem) {
        var dismissVCCompletionHandler: (() -> Void)?
        if let section = item as? MWKSection {
            // HAX: webview has issues scrolling when browser view is out of bounds, disable animation if needed
            self.webViewController.scrollToSection(section, animated: self.webViewController.isWebContentVisible)
            dismissVCCompletionHandler = {
                // HAX: This is terrible, but iOS events not under our control would steal our focus if we didn't wait long enough here and due to problems in UIWebView, we cannot work around it either.
                dispatchOnMainQueueAfterDelayInSeconds(1) {
                    self.webViewController.accessibilityCursorToSection(section)
                }
            }
        } else if let footerItem = item as? TableOfContentsFooterItem {
            let footerIndex = UInt(footerItem.footerViewIndex.rawValue)
            self.webViewController.scrollToFooterAtIndex(footerIndex)
            dismissVCCompletionHandler = {
                self.webViewController.accessibilityCursorToFooterAtIndex(footerIndex)
            }
        } else {
            assertionFailure("Unsupported selection of TOC item \(item)")
        }

        // Don't dismiss immediately - it looks jarring - let the user see the ToC selection before dismissing
        dispatchOnMainQueueAfterDelayInSeconds(0.25) {
            self.dismissViewControllerAnimated(true, completion: dismissVCCompletionHandler)
        }
    }

    public func tableOfContentsControllerDidCancel(controller: WMFTableOfContentsViewController) {
        dismissViewControllerAnimated(true, completion: nil)
    }

    public func tableOfContentsArticleSite() -> MWKSite {
        return self.articleTitle.site
    }
}

extension WMFArticleViewController {

    /**
     Create ToC items.

     - note: This must be done in Swift because `WMFTableOfContentsViewControllerDelegate` is not an ObjC protocol,
     and therefore cannot be referenced in Objective-C.

     - returns: sections of the ToC.
     */
    func createTableOfContentsSections() -> [TableOfContentsItem]? {
        // HAX: need to forcibly downcast each section object to our protocol type. yay objc/swift interop!
        return hasTableOfContents() ? article?.sections?.entries.map() { $0 as! TableOfContentsItem } : nil
    }

    /**
    Create a new instance of `WMFTableOfContentsViewController` which is configured to be used with the receiver.
    */
    public func createTableOfContentsViewControllerIfNeeded() {
        if let items = createTableOfContentsSections() {
            self.tableOfContentsViewController = WMFTableOfContentsViewController(presentingViewController: self, items: items, delegate: self)
        }
    }

    /**
     Append a read more section to the table of contents.
     */
    public func appendReadMoreTableOfContentsItemIfNeeded() {
        assert(self.tableOfContentsViewController != nil, "Attempting to add read more when toc is nil")
        guard let tvc = self.tableOfContentsViewController
              where !tvc.items.contains({ (item: TableOfContentsItem) in item.dynamicType == TableOfContentsReadMoreItem.self })
              else { return }
        if var items = createTableOfContentsSections() {
            items.append(TableOfContentsReadMoreItem(site: self.articleTitle.site))
            tvc.items = items
        }
    }

    public func showTableOfContents() {
        presentViewController(self.tableOfContentsViewController!, animated: true, completion: nil)

    }
    
    func backgroundView() -> UIVisualEffectView {
        let view = UIVisualEffectView(frame: CGRectZero)
        view.autoresizingMask = .FlexibleWidth
        view.effect = UIBlurEffect(style: .Light)
        view.alpha = 0.0
        return view
    }
    
    class func registerTweak(){
        let tweak = FBTweak(identifier: "Always Peek ToC")
        tweak.name = "Always Peek ToC"
        tweak.defaultValue = false
        
        let collection = FBTweakCollection(name: "Table of Contents");
        collection.addTweak(tweak)

        let store = FBTweakStore.sharedInstance()
        let category = store.tweakCategoryWithName("Article")

        category.addTweakCollection(collection);
    }
    
    func shouldPeek() -> Bool {
        let store = FBTweakStore.sharedInstance()
        let category = store.tweakCategoryWithName("Article")
        let collection = category.tweakCollectionWithName("Table of Contents")
        let tweak = collection.tweakWithIdentifier("Always Peek ToC")
        if tweak.currentValue as? Bool == true {
            return true
        }
        
        return !NSUserDefaults.standardUserDefaults().wmf_didPeekTableOfContents()
    }

    public func peekTableOfContentsIfNeccesary() {
        guard self.navigationController != nil else{
            return
        }
        guard let toc = self.tableOfContentsViewController else{
            return
        }
        guard shouldPeek() == true else{
            return
        }

        let bg = backgroundView()
        
        let containerBounds = self.navigationController!.view.bounds
        bg.frame = containerBounds
        self.navigationController!.view!.addSubview(bg)

        let tocWidth: CGFloat = 300.0
        let peekWidth = (containerBounds.width * 0.3) < tocWidth ? containerBounds.width * 0.3 : tocWidth
        
        var onscreen = containerBounds
        onscreen.size.width = tocWidth
        var offscreen = onscreen
        
        if UIApplication.sharedApplication().wmf_tocShouldBeOnLeft {
            offscreen.origin.x -= offscreen.width
            onscreen.origin.x = offscreen.origin.x + peekWidth
        }else{
            onscreen.origin.x = containerBounds.width - peekWidth
            offscreen.origin.x = containerBounds.width
        }
        
        toc.view.frame = offscreen
        toc.view.layer.shadowOpacity = 0.25
        toc.view.layer.shadowRadius = 4.0
        toc.view.layer.shadowOffset = CGSizeZero
        
        self.navigationController!.view!.addSubview(toc.view)
        
{'fraction_non_alphanumeric': 0.07168952919280347, 'fraction_numerical': 0.0030330185427724548, 'mean_word_length': 2.6098531973127646, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2889199', 'n_tokens_mistral': 3818, 'n_tokens_neox': 3588, 'n_words': 920}