//
//  SubKeysView.swift
//  KMEI
//
//  Created by Gabriel Wong on 2017-09-28.
//  Copyright © 2017 SIL International. All rights reserved.
//

import  UIKit

class SubKeysView: UIView {
  private let borderRadius: CGFloat = 5.0
  private let strokeWidth: CGFloat = 1.0
  private var baseKeyYDelta: CGFloat = 0.0

  private var keyFrame = CGRect.zero
  private var adjX: CGFloat = 0.0
  private var adjY: CGFloat = 0.0
  private var rows: Int = 0

  private let scale = UIScreen.main.scale
  private let bgColor = Colors.keyboardBackground
  private let bgColor2 = Colors.keyboardBackground
  private let borderColor = Colors.popupBorder

  let containerView: UIView

  init(keyFrame frame: CGRect, subKeys: [UIButton]) {
    let isSystemKeyboard = Manager.shared.isSystemKeyboard
    var isPortrait = true
    if isSystemKeyboard {
      isPortrait = InputViewController.isPortrait
    } else {
      isPortrait = UIDevice.current.orientation.isPortrait
    }

    let screenRect = UIScreen.main.bounds
    let screenWidth = screenRect.width
    let screenHeight = screenRect.height

    keyFrame = frame.insetBy(dx: 0, dy: 0)
    var buttonWidth: CGFloat
    var buttonHeight: CGFloat
    let marginX: CGFloat = 4.0
    let marginY: CGFloat = 3.0

    let maxButtonSize = CGSize(width: keyFrame.width * 0.9, height: keyFrame.height * 0.9)
    let minButtonSize: CGSize
    if UIDevice.current.userInterfaceIdiom == .pad {
      if isPortrait {
        minButtonSize = CGSize(width: keyFrame.width * 0.65, height: keyFrame.height * 0.65)
      } else {
        minButtonSize = CGSize(width: keyFrame.width * 0.55, height: keyFrame.height * 0.55)
      }
    } else {
      if isPortrait {
        minButtonSize = CGSize(width: keyFrame.width * 0.75, height: keyFrame.height * 0.75)
      } else {
        minButtonSize = CGSize(width: keyFrame.width * 0.675, height: keyFrame.height * 0.675)
      }
    }

    let kbHeight = Manager.shared.inputViewController.kmwHeight
    let maxContainerHeight = (screenHeight - kbHeight) + keyFrame.origin.y - strokeWidth

    var columns = Int((screenWidth - marginX) / (maxButtonSize.width + marginX))
    rows = subKeys.count / columns
    if subKeys.count % columns != 0 {
      rows += 1
    }

    if subKeys.count % rows == 0 {
      columns = subKeys.count / rows
    } else {
      let s = (columns * rows - subKeys.count) / 2
      columns -= s / (rows - 1)
    }

    buttonWidth = maxButtonSize.width
    buttonHeight = (maxContainerHeight - CGFloat(rows + 1) * marginY) / CGFloat(rows)
    buttonHeight = CGFloat.minimum(buttonHeight, maxButtonSize.height)
    buttonHeight = CGFloat.maximum(buttonHeight, minButtonSize.height)

    let cx: CGFloat = 1.5
    let containerWidth = (columns < 2 ? cx : CGFloat(columns)) * (buttonWidth + marginX) + marginX
    let containerHeight = (CGFloat(rows) * (buttonHeight + marginY)) + marginY
    let containerFrame = CGRect(x: strokeWidth, y: strokeWidth, width: containerWidth, height: containerHeight)
    let viewWidth = containerWidth + 2 * strokeWidth
    let baseHeight = keyFrame.size.height + marginY
    let viewHeight = baseHeight + containerHeight - marginY + strokeWidth
    var viewPosX = keyFrame.origin.x - (viewWidth - keyFrame.size.width) / 2.0
    var viewPosY = keyFrame.origin.y - (viewHeight - keyFrame.size.height + strokeWidth)

    // Ensure that the system keyboard doesn't try to display off the top of the keyboard's view area.
    if viewPosY < 0 && isSystemKeyboard {
      baseKeyYDelta = viewPosY // We'll need this to adjust the visualization.
      viewPosY = 0
    }

    adjX = 0
    adjY = 0

    if viewPosX < 0 {
      if (keyFrame.origin.x - borderRadius * 1.25) < 0 {
        adjX = keyFrame.origin.x - viewPosX
        viewPosX = keyFrame.origin.x
      } else {
        adjX = -viewPosX
        viewPosX = 0
      }
    } else if (viewPosX + viewWidth) > screenWidth {
      if ((keyFrame.origin.x + keyFrame.size.width) + borderRadius * 1.25) > screenWidth {
        adjX = viewPosX - keyFrame.origin.x
        viewPosX = keyFrame.origin.x + 2 * adjX
      } else {
        adjX = (screenWidth - viewWidth) - viewPosX
        viewPosX = adjX + viewPosX
      }
    }
    containerView = UIView(frame: containerFrame)
    containerView.backgroundColor = UIColor.clear

    super.init(frame: CGRect(x: viewPosX, y: viewPosY, width: viewWidth, height: viewHeight))

    super.backgroundColor = UIColor.clear
    //isUserInteractionEnabled = false

    addSubview(containerView)
    let fontSize = buttonHeight * (UIDevice.current.userInterfaceIdiom == .pad ? 0.4 : 0.5)

    for button in subKeys {
      let i = button.tag
      let buttonRow = CGFloat(i / columns)
      let buttonFrame = CGRect(x: marginX + CGFloat(i % columns) * (buttonWidth + marginX),
                               y: (buttonRow * buttonHeight) + (buttonRow + 1) * marginY,
                               width: buttonWidth, height: buttonHeight)
      button.frame = buttonFrame
      if subKeys.count == 1 {
        button.center = containerView.center
      }

      button.titleLabel?.minimumScaleFactor = 0.25
      button.titleLabel?.adjustsFontSizeToFitWidth = true
      button.titleLabel?.font = button.titleLabel?.font.withSize(fontSize)
      containerView.addSubview(button)
    }

  }

  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  override func draw(_ rect: CGRect) {
    drawKeyPreviewUp(rect)
  }

  private func drawKeyPreviewUp(_ rect: CGRect) {
    let keyWidth = keyFrame.size.width
    let keyHeight = keyFrame.size.height + adjY
    let viewWidth = rect.size.width
    let viewHeight = rect.size.height

    guard let context = UIGraphicsGetCurrentContext() else {
      return
    }
    UIGraphicsPushContext(context)
    context.setLineJoin(.round)
    context.setLineWidth(strokeWidth * 2)
    context.setStrokeColor(borderColor.cgColor)
    context.setFillColor(bgColor.cgColor)

    let keyLeftUnrounded = (viewWidth - keyWidth) / 2.0 + strokeWidth - adjX
    let keyRightUnrounded = (viewWidth - keyWidth) / 2.0 + keyWidth - strokeWidth - adjX
    var keyLeft = (keyLeftUnrounded * 10).rounded(.up) / 10
    var keyRight = (keyRightUnrounded * 10).rounded(.down) / 10

    let midY = viewHeight - keyHeight
    var viewLeft = strokeWidth
    var viewRight = viewWidth - strokeWidth
    let viewTop = strokeWidth

    var viewBottom = viewHeight - strokeWidth * 0.75 - (CGFloat(rows - 1) * 0.25)
    viewBottom += baseKeyYDelta

    let showBaseKeyPopup = (viewBottom > midY)

    if scale == 3.0 {
      viewBottom -= CGFloat(3 - rows) * 0.4
    } else if scale == 2.0 {
      viewBottom -= CGFloat(3 - rows) * 0.1
    }

    let viewMid = viewWidth / 2.0
    let r0 = borderRadius - strokeWidth
    let r1 = borderRadius - strokeWidth
    let r2 = borderRadius * 1.25 - strokeWidth

    if viewLeft.rounded() == keyLeft.rounded() || viewLeft.rounded(.down) == keyLeft.rounded(.down) {
      keyLeft = CGFloat.minimum(viewLeft, keyLeft)
      viewLeft = keyLeft
    }

    if viewRight.rounded() == keyRight.rounded() || viewRight.rounded(.down) == keyRight.rounded(.down) {
      keyRight = CGFloat.maximum(viewRight, keyRight)
      viewRight = keyRight
    }

    context.beginPath()
    context.move(to: CGPoint(x: viewMid, y: viewTop))
    context.addArc(tangent1End: CGPoint(x: viewLeft, y: viewTop),
                   tangent2End: CGPoint(x: viewLeft, y: midY), radius: r1)
    if showBaseKeyPopup {
      context.addArc(tangent1End: CGPoint(x: viewLeft, y: midY),
                     tangent2End: CGPoint(x: keyLeft, y: midY), radius: r1)
      context.addArc(tangent1End: CGPoint(x: keyLeft, y: midY),
                     tangent2End: CGPoint(x: keyLeft, y: viewBottom), radius: r2)
      context.addArc(tangent1End: CGPoint(x: keyLeft, y: viewBottom),
                     tangent2End: CGPoint(x: keyRight, y: viewBottom), radius: r0)
      context.addArc(tangent1End: CGPoint(x: keyRight, y: viewBottom),
                     tangent2End: CGPoint(x: keyRight, y: midY), radius: r0)
      context.addArc(tangent1End: CGPoint(x: keyRight, y: midY),
                     tangent2End: CGPoint(x: viewRight, y: midY), radius: r2)
    } else {
      context.addArc(tangent1End: CGPoint(x: viewLeft, y: midY),
                     tangent2End: CGPoint(x: viewRight, y: midY), radius: r0)
    }
    context.addArc(tangent1End: CGPoint(x: viewRight, y: midY),
                   tangent2End: CGPoint(x: viewRight, y: viewTop), radius: r1)
    context.addArc(tangent1End: CGPoint(x: viewRight, y: viewTop),
                   tangent2End: CGPoint(x: viewMid, y: viewTop), radius: r1)
    context.closePath()
    context.drawPath(using: .stroke)

    context.beginPath()
    context.move(to: CGPoint(x: viewMid, y: viewTop))
    context.addArc(tangent1End: CGPoint(x: viewLeft, y: viewTop),
                   tangent2End: CGPoint(x: viewLeft, y: midY), radius: r1)
    if showBaseKeyPopup {
      context.addArc(tangent1End: CGPoint(x: viewLeft, y: midY),
                     tangent2End: CGPoint(x: keyLeft, y: midY), radius: r1)
      context.addArc(tangent1End: CGPoint(x: keyLeft, y: midY),
                     tangent2End: CGPoint(x: keyLeft, y: viewBottom), radius: r2)
      context.addArc(tangent1End: CGPoint(x: keyLeft, y: viewBottom),
                     tangent2End: CGPoint(x: keyRight, y: viewBottom), radius: r0)
      context.addArc(tangent1End: CGPoint(x: keyRight, y: viewBottom),
                     tangent2End: CGPoint(x: keyRight, y: midY), radius: r0)
      context.addArc(tangent1End: CGPoint(x: keyRight, y: midY),
                     tangent2End: CGPoint(x: viewRight, y: midY), radius: r2)
    } else {
      context.addArc(tangent1End: CGPoint(x: viewLeft, y: midY),
                     tangent2End: CGPoint(x: viewRight, y: midY), radius: r0)
    }
    context.addArc(tangent1End: CGPoint(x: viewRight, y: midY),
                   tangent2End: CGPoint(x: viewRight, y: viewTop), radius: r1)
    context.addArc(tangent1End: CGPoint(x: viewRight, y: viewTop),
                   tangent2End: CGPoint(x: viewMid, y: viewTop), radius: r1)
    context.closePath()
    context.clip()

    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let gradientColors = [bgColor.cgColor, bgColor2.cgColor] as CFArray
    let gradientLocations: [CGFloat] = [0, 1]
    let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: gradientLocations)!

    let startPoint = CGPoint(x: rect.midX, y: rect.minY)
    let endPoint = CGPoint(x: rect.midX, y: rect.maxY)

    context.drawLinearGradient(gradient, start: startPoint, end: endPoint, options: [])
    UIGraphicsPopContext()
  }
}
