//
//  ViewController.swift
//  StandardSDK6003Swift
//
//  Created by Abdul on 17/04/18.
//  Copyright © 2018 Abdul. All rights reserved.
//

import UIKit
import AVKit
import CoreLocation
import AdSupport
import AVFoundation
import NielsenAppApi

class ViewController: UIViewController, NielsenAppApiDelegate, AVPlayerViewControllerDelegate {
    
    var nielsenApi : NielsenAppApi!
    var videoType : Int!
    var player : AVPlayer!
    var controller : AVPlayerViewController!
    var sdkMethods : SDKMethods!
    
    @IBOutlet weak var MetaInfo: UILabel!
    @IBOutlet weak var MetaInfo2: UILabel!
    @IBOutlet weak var VideoName: UILabel!
    
    var data : [String : Any]!
    var timeObserver: Any!
    var totalVideosPlayed = 0
    var ContentPlayed = 0
    var totalVideos : Int!
    var getVideoName = ""
    
    var isOptIn : Bool!
    
    var TimedMetadataObserverContext = 3
    var array : Any!
    let timedMetadataKey = "currentItem.timedMetadata"
    
    var NIELSEN_URL_OPT_OUT : String = "nielsenappsdk://1"
    var NIELSEN_URL_OPT_IN : String = "nielsenappsdk://0"
  

    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //Setting background image
        self.view.backgroundColor = UIColor(patternImage: UIImage(named: "new_background.jpg")!)
        
        MetaInfo.text =  "\u{22}appid\u{22}: \u{22}P5F65CC4D-9B26-445B-BA62-E6518DA4CFE2\u{22}"
    
        
       //SDKMethods class we wrote methods which creates content,Ad,DTVR objects
        sdkMethods = SDKMethods()
        
        if(videoType == Constants.onlyContent){
            //loading video content url
             getVideoName = sdkMethods.setContentUrl()
            
        }else if(videoType == Constants.dtvrVideo){
            //loading video DTVR url
            getVideoName = sdkMethods.setDtvrUrl()
            
        }else{
            //loading video Ad url
           getVideoName = sdkMethods.setAdUrl()
           
    
        }
        
        setPlayer()
        
        if(videoType != Constants.dtvrVideo){
            
            //For DTVR video playHeadPosition is not required
            //For DCR Content,Ad videos only this method will execute.
            setPlayHeadPosition()
        }
        
        //Setting observer to know the completion of video
        setVideoFinishObserver()
    }
    
    func setPlayer() {
        
        //creating player
        player  = AVPlayer.init(url: sdkMethods.url! as URL)
        controller = AVPlayerViewController()
        controller.view.frame = CGRect(x:0 , y:100, width: self.view.frame.width, height: 300)
        controller.player = player;
        controller.showsPlaybackControls = true;
        controller.delegate = self;
        
        player.play()
        
        if(totalVideosPlayed == 0){
            //For first time sending Channel info to SDK using "play" method.
            nielsenApi.play(sdkMethods.loadChannelInfo())
        }
        
        if(videoType == Constants.contentWithOneAd && totalVideosPlayed == 0){
            //load Content data
            self.data = sdkMethods.loadContent2()
            nielsenApi.loadMetadata(self.data)
            //loading Ad data
            self.data = sdkMethods.loadPreRollAd()
 //           getVideoName = sdkMethods.setAdUrl()
            nielsenApi.loadMetadata(self.data)
        }else if(videoType == Constants.contentWithOneAd && totalVideosPlayed == 1){
            //loading Ad data
            self.data = sdkMethods.loadContent2()
            nielsenApi.loadMetadata(self.data)
        }else if(videoType == Constants.dtvrVideo){
              self.data = sdkMethods.loadDtvr()
            nielsenApi.loadMetadata(self.data)
        }else if (videoType == Constants.onlyContent){
            self.data = sdkMethods.loadContent()
            nielsenApi.loadMetadata(self.data)
        }
        
 
        MetaInfo2.text = "\(self.data!)"  //Displays on screen metadata being passed to NielsenSDK
        VideoName.text = sdkMethods.url?.absoluteString
         updateOptValue()
        
        //Adding observer to player to track play,pause.
        player.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions.new, context: nil)
        
        //Only for DTVR videos we are tracking iD3 Tags and sends to SDK after extracting.
        if(videoType == Constants.dtvrVideo){
            
            //Setting observer to track timedMetadata
            player.addObserver(self, forKeyPath: timedMetadataKey, options: NSKeyValueObservingOptions.new, context: &TimedMetadataObserverContext)
            
        }
        
        self.addChild(controller)
        self.view.addSubview(controller.view)
    }
    
    func setPlayHeadPosition() {
        //Setting play head position
        let timeInterval : CMTime = CMTimeMakeWithSeconds(1.0, preferredTimescale: 10)
        controller.player?.addPeriodicTimeObserver(forInterval: timeInterval, queue: DispatchQueue.main) {(elapsedTime: CMTime) -> Void in
            
            let time : Float64 = self.controller.player!.currentTime().seconds;
            let pos = Int64(time);
            //Sending playHeadPosition to SDK.
            self.nielsenApi?.playheadPosition(pos);
        }
    }
    
    func setVideoFinishObserver() {
        //observer fires on completion video.
        NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: controller.player?.currentItem)
    }
    
    //rate 0.0 = Video Pause or stopped
    //rate 1.0 = Video played or resumed
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        
        //For DTVR video
        if keyPath == timedMetadataKey {
            if(context == &TimedMetadataObserverContext){
                if change != nil {
                    let timedMetadataArray = change![.newKey]
                    if timedMetadataArray != nil && (timedMetadataArray! as AnyObject) is Array<Any> {
                        for item in timedMetadataArray as! [AVMetadataItem]  {
                            //Handling TimedMetadata
                            self.handleTimedMetadata(metadataItem: item)
                        }
                    }
                }
            }
        }
        
        if keyPath == "rate" {
            if let rate = change?[NSKeyValueChangeKey.newKey] as? Float {
                
                if rate == 0.0 {
                    print("Playback stopped")
                    //On Video pause calling the "stop" method of SDK.
                    nielsenApi.stop()
                }
                if rate == 1.0 {
                    print("normal playback")
                    //On video Resume calling "loadMetada" method of SDK
                    nielsenApi.loadMetadata(self.data)
                }
            }
        }
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        
        //On moving to other screen calling "stop" method of SDK.
        nielsenApi.end()
        player.rate = 0
        player.pause()
    }
    
    @objc func playerDidFinishPlaying(note: NSNotification) {
        
        self.player?.removeObserver(self, forKeyPath: "rate")
        
        //As video completed playing, incrementing the variable value.
        totalVideosPlayed += 1
        
        if(videoType == Constants.onlyContent || totalVideosPlayed == totalVideos){
            //When content video completes or total videos finishes, call "end" method.
            nielsenApi.end()
            
        }else if(videoType == Constants.contentWithOneAd){
            
            //On completion of "AD" call "end" method.
            nielsenApi.end()
 
            //After preRoll ad completes, load content video.
            self.data = sdkMethods.loadContent2()
            
        }
        
        //Checking if total videos played or not.
        if(totalVideosPlayed != totalVideos){
            
            updateOptValue()
            setPlayer()
            setPlayHeadPosition()
            
            //Setting observer to know the completion of video
            setVideoFinishObserver()
            
        }
    }
    
    func updateOptValue(){
        if(isOptIn){
            self.data.updateValue(self.NIELSEN_URL_OPT_IN, forKey: "optout")
        }else{
            self.data.updateValue(self.NIELSEN_URL_OPT_OUT, forKey: "optout")
        }
    }
    
    deinit {
        
        print("Remove NotificationCenter Deinit")
        NotificationCenter.default.removeObserver(self)
    }
    
    func handleTimedMetadata(metadataItem: AVMetadataItem) {
        //Checking if there is any extraAttributeType is present in metadataItem, if not, then it will return
        guard let extraAttributeType = metadataItem.extraAttributes else {
            return
        }
        //Getting info attribute key from AVMetadataExtraAttributeKey
        let info : AVMetadataExtraAttributeKey = AVMetadataExtraAttributeKey(rawValue: "info")
        
        //Getting info from the extraAttribute of metadataItem using "info" key.
        let extraString = extraAttributeType[info] as AnyObject
        let key = metadataItem.key as! String
        
        //Checking if info of medadataItem contains tag that starts with "www.nielsen.com", then only sending to SDK
        if key == "PRIV" && extraString.range(of: "www.nielsen.com").length > 0 {
            
            DispatchQueue.global(qos: .default).async { () -> Void in
                
                //Sending ID3 to SDK
                self.nielsenApi?.sendID3(extraString as? String)
            }
        }
    }
}

