



// Datei ViewController.swift

import UIKit

class ViewController: UIViewController {

  // Outlets zum Zugriff auf die Steuerelemente
  @IBOutlet weak var puzzleView: UIView!
  @IBOutlet weak var sizeSegment: UISegmentedControl!
  
  // das Datenmodell der App
  var puzzle: Puzzle!
  var randomMoves = 0
  
  // bereits vorgesehener Code
  override func viewDidLoad() {
    super.viewDidLoad()
    puzzle = Puzzle(size: 4,
                    img: UIImage(named: "tower-bridge.jpg")!,
                    vc: self)

  }
  
  // in viewDidLoad() ist Layout noch nicht fertig; daher
  // hier Anpassung der Puzzlesteine an endgültige Größe
  override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    puzzle.setTilesFrame(in: puzzleView)
  }

  // Actions: diese Methoden werden aufgerufen, 
  // wenn ein Button angeklickt wird.
  // Segmented Control zur Größeneinstellung
  @IBAction func changeSize(_ sender: Any) {
    randomMoves = 0
    puzzle = Puzzle(size: sizeSegment.selectedSegmentIndex + 3,
                    img: UIImage(named: "tower-bridge.jpg")!,
                    vc: self)
    puzzle.setTilesFrame(in: puzzleView)
  }
  

  // Shuffle-Button
  @IBAction func shuffle(_ sender: Any) {
    randomMoves = min(puzzle.size * puzzle.size * 10, 300)
    randomMove()
  }
  
  // Puzzle zufällig an einer Stelle ändern, Funktion
  // solange weiter aufrufen, bis randomMoves <= 0
  func randomMove()  {
    randomMoves -= 1
    print("moves = \(randomMoves)")
    if(randomMoves <= 0) { return }
    
    var ok = false
    repeat {
      let col = Int(arc4random_uniform(UInt32(puzzle.size)))
      let row = Int(arc4random_uniform(UInt32(puzzle.size)))
      let dir = Direction(rawValue: Int(arc4random_uniform(4)) )!
      ok =  puzzle.moveTile(col: col, row: row, dir: dir,
                            container: puzzleView,
                            duration: 0,
                            completion: { (_) in self.randomMove() })
    } while(ok==false)
  }

  
  // Reset-Button
  @IBAction func reset(_ sender: Any) {
    randomMoves = 0
    
    // neu geordnetes Array
    var orderedTiles = [[Tile?]](
      repeating: [Tile?](repeating: nil, count: puzzle.size),
      count: puzzle.size)
    
    for col in 0..<puzzle.size {
      for row in 0..<puzzle.size {
        if let t = puzzle.tiles[col][row] {
          // an richtiger Position speichern
          orderedTiles[t.col][t.row] = t
          // und animiert dorthin schieben (Closure)
          UIView.animate(withDuration: 0.5) {
            t.frame = self.puzzle.getRect(
              col: t.col, row: t.row,
              container: self.puzzleView)
            t.layer.borderWidth = 0
          }
        }
      }
    }
    puzzle.tiles = orderedTiles
  }
  
  // Schiebebewegung für Puzzlestück festgestellt
  func panTile(recognizer: UIPanGestureRecognizer) {
    if recognizer.state == .changed,
      let t = recognizer.view as? Tile
    {
      // ist die Bewegung ausreichend weit und eindeutig?
      let transl = recognizer.translation(in: t)
      if let dir = panDir(transl: transl,
                          tilesize: t.frame.width)
      {
        // Ereignis erkannt; vorerst weitere Aufrufe stoppen
        recognizer.isEnabled = false
        
        // versuchen, Puzzlestück entsprechend zu bewegen
        if let (col, row) = puzzle.getPosition(of: t) {
          _ = puzzle.moveTile(col: col, row: row, dir: dir,
                              container: puzzleView, duration: 0.25)
        }
      }
    }
    
    // Gesture Recognizer für das nächste Mal wieder aktivieren
    if recognizer.state == .ended  ||
      recognizer.state == .cancelled
    {
      recognizer.isEnabled = true
    }
  }
  
  // wertet Bewegung des Pan-Recognizer aus; Rückgabe nur, wenn die
  // Richtung eindeutig ist und  mehr als 40% des Puzzlestücks beträgt
  func panDir(transl: CGPoint, tilesize: CGFloat) -> Direction? {
    let min = tilesize * 0.40
    if abs(transl.x) < min && abs(transl.y) < min {
      return nil  // Bewegung zu klein
    }
    if abs(transl.x) > 2 * abs(transl.y) {
      // horiz. Bewegung
      return transl.x > 0 ? .right : .left
    } else if abs(transl.y) > 2 * abs(transl.x) {
      // vert. Bewegung
      return transl.y > 0 ? .down : .up
    } else {
      return nil
    }
  }


}

