         return true
     }
 
-    private func isVisiblePagingViewController(pagingViewController: UIViewController) -> Bool {
-        return childViewControllers.contains(pagingViewController)
-    }
-    
     // MARK: - Page calculator
-    
-    private func currentPagingViewPosition() -> PagingViewPosition {
+
+    private var currentPagingViewPosition: PagingViewPosition {
+        guard let contentScrollView = contentScrollView else { return .Left }
         let pageWidth = contentScrollView.frame.width
         let order = Int(ceil((contentScrollView.contentOffset.x - pageWidth / 2) / pageWidth))
-        
+
         if case .Infinite = options.menuDisplayMode {
-            return PagingViewPosition(order: order)
-        }
-        
+            return PagingViewPosition(order: order) ?? .Left
+        }
+
         // consider left edge menu as center position
-        guard currentPage == 0 && contentScrollView.contentSize.width < (pageWidth * CGFloat(visiblePagingViewNumber)) else { return PagingViewPosition(order: order) }
-        return PagingViewPosition(order: order + 1)
-    }
-    
+        guard currentPage == 0 && contentScrollView.contentSize.width < (pageWidth * CGFloat(visiblePagingViewNumber)) else {
+            return PagingViewPosition(order: order) ?? .Left
+        }
+
+        return PagingViewPosition(order: order + 1) ?? .Left
+    }
+
     private func targetPage(tappedPage tappedPage: Int) -> Int {
         guard case let .Standard(_, _, scrollingMode) = options.menuDisplayMode else { return tappedPage }
         guard case .PagingEnabled = scrollingMode else { return tappedPage }
         return tappedPage < currentPage ? currentPage - 1 : currentPage + 1
     }
-    
+
     // MARK: - Validator
-    
+
     private func validateDefaultPage() {
         guard options.defaultPage >= options.menuItemCount || options.defaultPage < 0 else { return }
-        
+
         NSException(name: ExceptionName, reason: "default page is invalid", userInfo: nil).raise()
     }
-    
+
     private func validatePageNumbers() {
         guard case .Infinite = options.menuDisplayMode else { return }
         guard options.menuItemCount < visiblePagingViewNumber else { return }
+
+        NSException(name: ExceptionName, reason: "the number of view controllers should be more than three with Infinite display mode", userInfo: nil).raise()
+    }
+
+    // MARK: - Private
+
+    private func nextPage(right right: Bool) -> Int {
+        guard let count = pagingViewControllers?.count else { return 0 }
+
+        let nextPage = currentPage + (right ? 1 : -1)
+
+        switch nextPage {
+        case _ where nextPage >= count:
+            return 0
+        case _ where nextPage < 0:
+            return count - 1
+        default:
+            return nextPage
+        }
+    }
+
+    private var lastVisiblePage: Int = 0
+
+    /// The viewController that will be visible when scrolling ends
+    private var toViewController: UIViewController?
+
+    private func viewCopyImageView(isFront isFront: Bool) -> UIImageView {
+        let imageView = UIImageView()
+        imageView.backgroundColor = .greenColor()
+        contentScrollView.addSubview(imageView)
+        imageView.translatesAutoresizingMaskIntoConstraints = false
+
+        let toItem = isFront ? contentScrollView : pagingViewControllers!.last!.view
+
+        for attribute in [NSLayoutAttribute.Top, .Leading, .Height, .Width] {
+            let toAttribute: NSLayoutAttribute
+
+            if !isFront && attribute == .Leading {
+                toAttribute = .Trailing
+            } else {
+                toAttribute = attribute
+            }
+
+            NSLayoutConstraint(item: imageView, attribute: attribute, relatedBy: .Equal, toItem: toItem, attribute: toAttribute, multiplier: 1, constant: 0).active = true
+        }
+
+        return imageView
+    }
+    private lazy var frontImageView: UIImageView = self.viewCopyImageView(isFront: true)
+    private lazy var backImageView: UIImageView = self.viewCopyImageView(isFront: false)
+
+    private var offsetXFirstPage: CGFloat {
+        if case .Infinite = options.menuDisplayMode {
+            return view.bounds.width
+        } else {
+            return 0
+        }
+    }
+
+    private var offsetXLastPage: CGFloat {
+        if let count = pagingViewControllers?.count,
+            case .Infinite = options.menuDisplayMode {
+                return view.bounds.width * CGFloat(count + 1)
+        } else {
+            return 0
+        }
+    }
+
+    private enum InfiniteCopyType {
+        case Front, Back
+    }
+
+    private func setupImageViewCopy(copyType copyType: InfiniteCopyType) {
+        switch copyType {
+        case .Front:
+            guard let lastView = pagingViewControllers?.last?.view else { return }
+            frontImageView.image = UIImage.imageFromView(lastView)
+        case .Back:
+            guard let firstView = pagingViewControllers?.first?.view else { return }
+            backImageView.image = UIImage.imageFromView(firstView)
+        }
+    }
+
+    private func jumpToPage(page: InfiniteCopyType) {
+        let viewController: UIViewController?
         
-        NSException(name: ExceptionName, reason: "the number of view controllers should be more than three with Infinite display mode", userInfo: nil).raise()
+        switch page {
+        case .Front:
+            viewController = pagingViewControllers?.first
+        case .Back:
+            viewController = pagingViewControllers?.last
+        }
+        
+        if let offsetX = viewController?.view.frame.origin.x {
+            contentScrollView.contentOffset.x = offsetX
+        }
+    }
+}
+
+extension UIImage {
+    class func imageFromView(view: UIView) -> UIImage? {
+        UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0)
+        guard let context = UIGraphicsGetCurrentContext() else { return nil }
+        
+        view.layer.renderInContext(context)
+        let image = UIGraphicsGetImageFromCurrentImageContext()
+        UIGraphicsEndImageContext()
+        
+        return image
     }
 }
            contentScrollView.contentOffset.x = currentViewController.view!.frame.minX
        }
    }
    
    override public func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
        
        menuView.updateMenuViewConstraints(size: size)
        
        coordinator.animateAlongsideTransition({ [unowned self] (_) -> Void in
            self.view.setNeedsLayout()
            self.view.layoutIfNeeded()
            
            // reset selected menu item view position
            switch self.options.menuDisplayMode {
            case .Standard, .Infinite:
                self.menuView.moveToMenu(page: self.currentPage, animated: true)
            default: break
            }
        }, completion: nil)
    }
    
    public func setup(viewControllers viewControllers: [UIViewController], options: PagingMenuOptions) {
        self.options = options
        pagingViewControllers = viewControllers
        visiblePagingViewControllers.reserveCapacity(visiblePagingViewNumber)
        
        // validate
        validateDefaultPage()
        validatePageNumbers()
        
        // cleanup
        cleanup()
        
        currentPage = options.defaultPage
        
        constructMenuView()
        constructContentScrollView()
        layoutMenuView()
        layoutContentScrollView()
        constructContentView()
        layoutContentView()
        constructPagingViewControllers()
        layoutPagingViewControllers()

        currentPosition = currentPagingViewPosition()
        currentViewController = pagingViewControllers[currentPage]
        moveToMenuPage(currentPage, animated: false)
    }
    
    public func rebuild(viewControllers: [UIViewController], options: PagingMenuOptions) {
        // cleanup properties to avoid memory leaks. This could also be placed inside the cleanup method, or in within didSet{} of the pagingViewController
        visiblePagingViewControllers.removeAll()
        currentViewController = nil
        
        for childViewController in childViewControllers {
            childViewController.view.removeFromSuperview()
            childViewController.removeFromParentViewController()
        }

        // perform setup
        
        setup(viewControllers: viewControllers, options: options)
        
        view.setNeedsLayout()
        view.layoutIfNeeded()
    }
    
    // MARK: - UISCrollViewDelegate
    
    public func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
        guard scrollView.isEqual(contentScrollView) else { return }

        let position = currentPagingViewPosition()
        
        // set new page number according to current moving direction
        switch position {
        case .Left: currentPage = previousIndex
        case .Right: currentPage = nextIndex
        default: return
        }

        delegate?.willMoveToMenuPage?(currentPage)
        menuView.moveToMenu(page: currentPage, animated: true)
        currentViewController = pagingViewControllers[currentPage]
        contentScrollView.contentOffset.x = currentViewController.view!.frame.minX

        constructPagingViewControllers()
        layoutPagingViewControllers()
        view.setNeedsLayout()
        view.layoutIfNeeded()

        currentPosition = currentPagingViewPosition()
        delegate?.didMoveToMenuPage?(currentPage)
    }
    
    // MARK: - UIGestureRecognizer
    
    internal func handleTapGesture(recognizer: UITapGestureRecognizer) {
        let tappedMenuView = recognizer.view as! MenuItemView
        guard let tappedPage = menuView.menuItemViews.indexOf(tappedMenuView) where tappedPage != currentPage else { return }
        
        let page = targetPage(tappedPage: tappedPage)
        moveToMenuPage(page, animated: true)
    }
    
    internal func handleSwipeGesture(recognizer: UISwipeGestureRecognizer) {
        var newPage = currentPage
        if recognizer.direction == .Left {

        case .SegmentedControl: return
        case .Infinite: break
        }

        let leftSwipeGesture = UISwipeGestureRecognizer(target: self, action: "handleSwipeGesture:")
        leftSwipeGesture.direction = .Left
        menuView.panGestureRecognizer.requireGestureRecognizerToFail(leftSwipeGesture)
