<commit_before>//
//  MultiSlider+Internal.swift
//  MultiSlider
//
//  Created by <NAME> on 21/06/2019.
//

import UIKit

extension MultiSlider {
    func setup() {
        trackView.backgroundColor = actualTintColor
        updateTrackViewCornerRounding()
        slideView.layoutMargins = .zero
        setupOrientation()
        setupPanGesture()

        isAccessibilityElement = true
        accessibilityIdentifier = "multi_slider"
        accessibilityLabel = "slider"
        accessibilityTraits = [.adjustable]

        minimumView.isHidden = true
        maximumView.isHidden = true

        if #available(iOS 11.0, *) {
            valueLabelFormatter.addObserverForAllProperties(observer: self)
        }
    }

    private func setupPanGesture() {
        addConstrainedSubview(panGestureView)
        for edge: NSLayoutConstraint.Attribute in [.top, .bottom, .left, .right] {
            constrain(panGestureView, at: edge, diff: -edge.inwardSign * margin)
        }
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(didDrag(_:)))
        panGesture.delegate = self
        panGestureView.addGestureRecognizer(panGesture)
    }

    func setupOrientation() {
        trackView.removeFromSuperview()
        trackView.removeConstraints(trackView.constraints)
        slideView.removeFromSuperview()
        minimumView.removeFromSuperview()
        maximumView.removeFromSuperview()
        switch orientation {
        case .vertical:
            let centerAttribute: NSLayoutConstraint.Attribute
            if #available(iOS 12, *) {
                centerAttribute = .centerX // iOS 12 doesn't like .topMargin, .rightMargin
            } else {
                centerAttribute = .centerXWithinMargins
            }
            addConstrainedSubview(trackView, constrain: .top, .bottom, centerAttribute)
            trackView.constrain(.width, to: trackWidth)
            trackView.addConstrainedSubview(slideView, constrain: .left, .right)
            constrainVerticalTrackViewToLayoutMargins()
            addConstrainedSubview(minimumView, constrain: .bottomMargin, centerAttribute)
            addConstrainedSubview(maximumView, constrain: .topMargin, centerAttribute)
        default:
            let centerAttribute: NSLayoutConstraint.Attribute
            if #available(iOS 12, *) {
                centerAttribute = .centerY // iOS 12 doesn't like .leftMargin, .rightMargin
            } else {
                centerAttribute = .centerYWithinMargins
            }
            addConstrainedSubview(trackView, constrain: .left, .right, centerAttribute)
            trackView.constrain(.height, to: trackWidth)
            trackView.addConstrainedSubview(slideView, constrain: .top, .bottom)
            constrainHorizontalTrackViewToLayoutMargins()
            addConstrainedSubview(minimumView, constrain: .leftMargin, centerAttribute)
            addConstrainedSubview(maximumView, constrain: .rightMargin, centerAttribute)
        }
        setupTrackLayoutMargins()
    }

    func setupTrackLayoutMargins() {
        let thumbSize = (thumbImage ?? defaultThumbImage)?.size ?? CGSize(width: 2, height: 2)
        let thumbDiameter = orientation == .vertical ? thumbSize.height : thumbSize.width
        let halfThumb = thumbDiameter / 2 - 1 // 1 pixel for semi-transparent boundary
        if orientation == .vertical {
            trackView.layoutMargins = UIEdgeInsets(top: halfThumb, left: 0, bottom: halfThumb, right: 0)
            constrain(.width, to: max(thumbSize.width, trackWidth), relation: .greaterThanOrEqual)
        } else {
            trackView.layoutMargins = UIEdgeInsets(top: 0, left: halfThumb, bottom: 0, right: halfThumb)
            constrainHorizontalTrackViewToLayoutMargins()
            constrain(.height, to: max(thumbSize.height, trackWidth), relation: .greaterThanOrEqual)
        }
    }

    /// workaround to a problem in iOS 12-13, of constraining to `leftMargin` and `rightMargin`.
    func constrainHorizontalTrackViewToLayoutMargins() {
        trackView.constrain(slideView, at: .left, diff: trackView.layoutMargins.left)
        trackView.constrain(slideView, at: .right, diff: -trackView.layoutMargins.right)
    }

    /// workaround to a problem in iOS 12-13, of constraining to `topMargin` and `bottomMargin`.
    func constrainVerticalTrackViewToLayoutMargins() {
        trackView.constrain(slideView, at: .top, diff: trackView.layoutMargins.top)
        trackView.constrain(slideView, at: .bottom, diff: -trackView.layoutMargins.bottom)
    }

    func repositionThumbViews() {
        thumbViews.forEach { $0.removeFromSuperview() }
        thumbViews = []
        valueLabels.forEach { $0.removeFromSuperview() }
        valueLabels = []
        adjustThumbCountToValueCount()
    }

    func adjustThumbCountToValueCount() {
        if value.count == thumbViews.count {
            return
        } else if value.count < thumbViews.count {
            thumbViews.removeViewsStartingAt(value.count)
            valueLabels.removeViewsStartingAt(value.count)
        } else { // add thumbViews
            for _ in thumbViews.count ..< value.count {
                addThumbView()
            }
        }
        updateOuterTrackViews()
    }

    func updateOuterTrackViews() {
        outerTrackViews.removeViewsStartingAt(0)
        outerTrackViews.removeAll()
        guard nil != outerTrackColor else { return }
        if thumbViews.count > 1 {
            guard let firstThumb = thumbViews.first, let lastThumb = thumbViews.last, firstThumb != lastThumb else { return }

            outerTrackViews = [
                outerTrackView(constraining: .top(in: orientation), to: firstThumb),
                outerTrackView(constraining: .bottom(in: orientation), to: lastThumb),
            ]
        } else {
            guard let firstThumb = thumbViews.first else { return }
            outerTrackViews = [
                outerTrackView(constraining: .bottom(in: orientation), to: firstThumb)
            ]
        }
    }

    private func outerTrackView(constraining: NSLayoutConstraint.Attribute, to thumbView: UIView) -> UIView {
        let view = UIView()
        view.backgroundColor = outerTrackColor
        trackView.addConstrainedSubview(view, constrain: .top, .bottom, .left, .right)
        trackView.removeFirstConstraint { $0.firstItem === view && $0.firstAttribute == constraining }
        trackView.constrain(view, at: constraining, to: thumbView, at: .center(in: orientation))
        trackView.sendSubviewToBack(view)

        view.layer.cornerRadius = trackView.layer.cornerRadius
        if #available(iOS 11.0, *) {
            view.layer.maskedCorners = .direction(constraining.opposite)
        }

        return view
    }

    private func addThumbView() {
        let i = thumbViews.count
        let thumbView = UIImageView(image: thumbImage ?? defaultThumbImage)
        thumbView.addShadow()
        thumbViews.append(thumbView)<commit_msg>simplify code for `outerTrackColor` for single thumb<commit_after>//
//  MultiSlider+Internal.swift
//  MultiSlider
//
//  Created by <NAME> on 21/06/2019.
//

import UIKit

extension MultiSlider {
    func setup() {
        trackView.backgroundColor = actualTintColor
        updateTrackViewCornerRounding()
        slideView.layoutMargins = .zero
        setupOrientation()
        setupPanGesture()

        isAccessibilityElement = true
        accessibilityIdentifier = "multi_slider"
        accessibilityLabel = "slider"
        accessibilityTraits = [.adjustable]

        minimumView.isHidden = true
        maximumView.isHidden = true

        if #available(iOS 11.0, *) {
            valueLabelFormatter.addObserverForAllProperties(observer: self)
        }
    }

    private func setupPanGesture() {
        addConstrainedSubview(panGestureView)
        for edge: NSLayoutConstraint.Attribute in [.top, .bottom, .left, .right] {
            constrain(panGestureView, at: edge, diff: -edge.inwardSign * margin)
        }
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(didDrag(_:)))
        panGesture.delegate = self
        panGestureView.addGestureRecognizer(panGesture)
    }

    func setupOrientation() {
        trackView.removeFromSuperview()
        trackView.removeConstraints(trackView.constraints)
        slideView.removeFromSuperview()
        minimumView.removeFromSuperview()
        maximumView.removeFromSuperview()
        switch orientation {
        case .vertical:
            let centerAttribute: NSLayoutConstraint.Attribute
            if #available(iOS 12, *) {
                centerAttribute = .centerX // iOS 12 doesn't like .topMargin, .rightMargin
            } else {
                centerAttribute = .centerXWithinMargins
            }
            addConstrainedSubview(trackView, constrain: .top, .bottom, centerAttribute)
            trackView.constrain(.width, to: trackWidth)
            trackView.addConstrainedSubview(slideView, constrain: .left, .right)
            constrainVerticalTrackViewToLayoutMargins()
            addConstrainedSubview(minimumView, constrain: .bottomMargin, centerAttribute)
            addConstrainedSubview(maximumView, constrain: .topMargin, centerAttribute)
        default:
            let centerAttribute: NSLayoutConstraint.Attribute
            if #available(iOS 12, *) {
                centerAttribute = .centerY // iOS 12 doesn't like .leftMargin, .rightMargin
            } else {
                centerAttribute = .centerYWithinMargins
            }
            addConstrainedSubview(trackView, constrain: .left, .right, centerAttribute)
            trackView.constrain(.height, to: trackWidth)
            trackView.addConstrainedSubview(slideView, constrain: .top, .bottom)
            constrainHorizontalTrackViewToLayoutMargins()
            addConstrainedSubview(minimumView, constrain: .leftMargin, centerAttribute)
            addConstrainedSubview(maximumView, constrain: .rightMargin, centerAttribute)
        }
        setupTrackLayoutMargins()
    }

    func setupTrackLayoutMargins() {
        let thumbSize = (thumbImage ?? defaultThumbImage)?.size ?? CGSize(width: 2, height: 2)
        let thumbDiameter = orientation == .vertical ? thumbSize.height : thumbSize.width
        let halfThumb = thumbDiameter / 2 - 1 // 1 pixel for semi-transparent boundary
        if orientation == .vertical {
            trackView.layoutMargins = UIEdgeInsets(top: halfThumb, left: 0, bottom: halfThumb, right: 0)
            constrain(.width, to: max(thumbSize.width, trackWidth), relation: .greaterThanOrEqual)
        } else {
            trackView.layoutMargins = UIEdgeInsets(top: 0, left: halfThumb, bottom: 0, right: halfThumb)
            constrainHorizontalTrackViewToLayoutMargins()
            constrain(.height, to: max(thumbSize.height, trackWidth), relation: .greaterThanOrEqual)
        }
    }

    /// workaround to a problem in iOS 12-13, of constraining to `leftMargin` and `rightMargin`.
    func constrainHorizontalTrackViewToLayoutMargins() {
        trackView.constrain(slideView, at: .left, diff: trackView.layoutMargins.left)
        trackView.constrain(slideView, at: .right, diff: -trackView.layoutMargins.right)
    }

    /// workaround to a problem in iOS 12-13, of constraining to `topMargin` and `bottomMargin`.
    func constrainVerticalTrackViewToLayoutMargins() {
        trackView.constrain(slideView, at: .top, diff: trackView.layoutMargins.top)
        trackView.constrain(slideView, at: .bottom, diff: -trackView.layoutMargins.bottom)
    }

    func repositionThumbViews() {
        thumbViews.forEach { $0.removeFromSuperview() }
        thumbViews = []
        valueLabels.forEach { $0.removeFromSuperview() }
        valueLabels = []
        adjustThumbCountToValueCount()
    }

    func adjustThumbCountToValueCount() {
        if value.count == thumbViews.count {
            return
        } else if value.count < thumbViews.count {
            thumbViews.removeViewsStartingAt(value.count)
            valueLabels.removeViewsStartingAt(value.count)
        } else { // add thumbViews
            for _ in thumbViews.count ..< value.count {
                addThumbView()
            }
        }
        updateOuterTrackViews()
    }

    func updateOuterTrackViews() {
        outerTrackViews.removeViewsStartingAt(0)
        outerTrackViews.removeAll()
        guard nil != outerTrackColor else { return }
        guard let lastThumb = thumbViews.last else { return }
        outerTrackViews = [outerTrackView(constraining: .bottom(in: orientation), to: lastThumb)]
        guard let firstThumb = thumbViews.first, firstThumb != lastThumb else { return }
        outerTrackViews += [outerTrackView(constraining: .top(in: orientation), to: firstThumb)]
    }

    private func outerTrackView(constraining: NSLayoutConstraint.Attribute, to thumbView: UIView) -> UIView {
        let view = UIView()
        view.backgroundColor = outerTrackColor
        trackView.addConstrainedSubview(view, constrain: .top, .bottom, .left, .right)
        trackView.removeFirstConstraint { $0.firstItem === view && $0.firstAttribute == constraining }
        trackView.constrain(view, at: constraining, to: thumbView, at: .center(in: orientation))
        trackView.sendSubviewToBack(view)

        view.layer.cornerRadius = trackView.layer.cornerRadius
        if #available(iOS 11.0, *) {
            view.layer.maskedCorners = .direction(constraining.opposite)
        }

        return view
    }

    private func addThumbView() {
        let i = thumbViews.count
        let thumbView = UIImageView(image: thumbImage ?? defaultThumbImage)
        thumbView.addShadow()
        thumbViews.append(thumbView)
{'fraction_non_alphanumeric': 0.09110077068489167, 'fraction_numerical': 0.00647084484513596, 'mean_word_length': 2.6149802890932983, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 8, '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': '503146', 'n_tokens_mistral': 3929, 'n_tokens_neox': 3678, 'n_words': 787}