//
//  LocalNotificationFactory.swift
//  Engagement
//
//  Created by Microsoft on 18/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import Foundation

/**
 *  This factory create UILocalNotification to simulate out of app AzME SDK Notifications
 */
struct LocalNotificationFactory {

  static var outOfAppNotification : UILocalNotification {
    get {
      let category = UIMutableUserNotificationCategory()

      let shareAction = UIMutableUserNotificationAction()
      shareAction.identifier = Config.Notifications.shareIdentifier
      shareAction.destructive = false
      shareAction.title = Config.Notifications.shareActionTitle
      shareAction.activationMode = .Foreground
      shareAction.authenticationRequired = false

      let feedbackAction = UIMutableUserNotificationAction()
      feedbackAction.identifier = Config.Notifications.feedbackIdentifier
      feedbackAction.destructive = false
      feedbackAction.title = Config.Notifications.feedbackActionTitle
      feedbackAction.activationMode = .Foreground
      feedbackAction.authenticationRequired = false

      let categoryIdentifier = "category.outofapp.action"
      category.identifier = categoryIdentifier
      category.setActions([shareAction, feedbackAction], forContext: .Minimal)
      category.setActions([shareAction, feedbackAction], forContext: .Default)

      let categories = Set(arrayLiteral: category)
      let settings = UIUserNotificationSettings(forTypes: [.Alert, .Sound], categories: categories)
      UIApplication.sharedApplication().registerUserNotificationSettings(settings)

      let notification = UILocalNotification()
      notification.userInfo = [
        AzMELocalNotification.keyNotificationType : AzMELocalNotification.DeepLink.rawValue,
        AzMELocalNotification.keyNotificationLink : Config.AzMESDK.DeepLink.recentUpdatesLink]

      notification.applicationIconBadgeNumber = 0
      notification.category = categoryIdentifier
      notification.alertTitle = L10n.tr("out.of.app.push.notification.content.title")
      notification.alertBody = L10n.tr("out.of.app.push.notification.content.text")
      notification.fireDate = NSDate().dateByAddingTimeInterval(5)
      notification.timeZone = NSTimeZone.defaultTimeZone()
      notification.alertAction = "Action Name"

      return notification
    }
  }

  static var outOfAppAnnouncementNotification : UILocalNotification {
    get {
      let category = UIMutableUserNotificationCategory()

      let shareAction = UIMutableUserNotificationAction()
      shareAction.identifier = Config.Notifications.shareIdentifier
      shareAction.destructive = false
      shareAction.title = Config.Notifications.shareActionTitle
      shareAction.activationMode = .Foreground
      shareAction.authenticationRequired = false

      let feedbackAction = UIMutableUserNotificationAction()
      feedbackAction.identifier = Config.Notifications.feedbackIdentifier
      feedbackAction.destructive = false
      feedbackAction.title = Config.Notifications.feedbackActionTitle
      feedbackAction.activationMode = .Foreground
      feedbackAction.authenticationRequired = false

      let categoryIdentifier = "category.outofapp.action"
      category.identifier = categoryIdentifier
      category.setActions([shareAction, feedbackAction], forContext: .Minimal)
      category.setActions([shareAction, feedbackAction], forContext: .Default)

      let categories = Set(arrayLiteral: category)
      let settings = UIUserNotificationSettings(forTypes: [.Alert, .Sound], categories: categories)
      UIApplication.sharedApplication().registerUserNotificationSettings(settings)

      let notification = UILocalNotification()
      notification.userInfo = [
        AzMELocalNotification.keyNotificationType : AzMELocalNotification.WebAnnouncement.rawValue,
        AzMELocalNotification.keyNotificationContent : [
          "title": L10n.tr("out.of.app.push.notification.content.title"),
          "body": L10n.tr("local.rebound.content"),
          "actionButton": L10n.tr("home.recent.updates.view.all"),
          "exitButton": L10n.tr("close.button")
        ],
        AzMELocalNotification.keyNotificationLink : Config.AzMESDK.DeepLink.recentUpdatesLink
      ]
      notification.category = categoryIdentifier
      notification.applicationIconBadgeNumber = 0
      notification.alertTitle = L10n.tr("out.of.app.push.notification.content.title")
      notification.alertBody = L10n.tr("out.of.app.push.notification.content.text")
      notification.fireDate = NSDate().dateByAddingTimeInterval(5)
      notification.timeZone = NSTimeZone.defaultTimeZone()
      notification.alertAction = "Action Name"
      return notification
    }
  }
}


//
//  MenuItem.swift
//  Engagement
//
//  Created by Microsoft on 10/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import UIKit

let defaultMenuImageWidth = 25

/**
 *  Represent an item to be display on the left side menu controller
 */
struct MenuItem {

  var icon: UIImage?
  var title: String?
  var initViewController: (() -> UIViewController?)?
  var selectedCompletion: (() -> Void)?
  var isChild: Bool?
  var isSelectable: Bool?
  var separator: Bool?

  //MARK - Initialisations
  init(title: String?, icon: AzIcon, isSelectable: Bool = true){
    self.icon = icon.imageWithSize(CGSize(width: defaultMenuImageWidth, height: defaultMenuImageWidth)).imageWithRenderingMode(.AlwaysTemplate)
    self.title = title
    self.isSelectable = isSelectable
  }

  init(title: String?, icon: AzIcon, initViewController: (() -> UIViewController?)?) {
    self.init(title: title, icon: icon)
    self.initViewController = initViewController
  }

  init(title: String?, icon: AzIcon, selectedCompletion: (() -> Void)?, isChild: Bool = false) {
    self.init(title: title, icon: icon, isSelectable: false)
    self.selectedCompletion = selectedCompletion
    self.isChild = isChild
  }

  /**
   Default helpuflinks to collapse into the menu

   - parameter controller: The MenuViewController receiver

   - returns: Array of MenuItem
   */
  static func helpfulLinksFromMenuController(controller: MenuViewController) -> [MenuItem] {
    let documentationItem = MenuItem(title: L10n.tr("helpful.link.documentation"),
      icon: AzIcon.iconDocumentation(),
      selectedCompletion: {
        AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.SafariViewController.documentation, extras: nil)
        controller.openLink(Config.URLs.helpfulDocumentation)
      },
      isChild: true)

    let pricingItem = MenuItem(title: L10n.tr("helpful.link.pricing"),
      icon: AzIcon.iconPricing(),
      selectedCompletion: {
        AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.SafariViewController.pricing, extras: nil)
        controller.openLink(Config.URLs.helpfulPricing)
      },
      isChild: true)

    let SLAItem = MenuItem(title: L10n.tr("helpful.link.sla"),
      icon: AzIcon.iconSLA(),
      selectedCompletion: {
        AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.SafariViewController.SLA, extras: nil)
        controller.openLink(Config.URLs.helpfulSLA)
      },
      isChild: true)

    let MSDNForumItem = MenuItem(title: L10n.tr("helpful.link.msdn.support.forum"),
      icon: AzIcon.iconMSDNForum(),
      selectedCompletion: {
        AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.SafariViewController.MSDNForum, extras: nil)
        controller.openLink(Config.URLs.helpfulMSDNForum)
      },
      isChild: true)

    let userVoiceForumItem = MenuItem(title: L10n.tr("helpful.link.user.voice.forum"),
      icon: AzIcon.iconUserVoiceForum(),
      selectedCompletion: {
        AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.SafariViewController.clickSuggestFeatures, extras: nil)
        controller.openLink(Config.URLs.helpfulVoiceForum)
      },
      isChild: true)

    return [documentationItem, pricingItem, SLAItem, MSDNForumItem, userVoiceForumItem];
  }

  /**
   Default data source fot the drawer menu

   - parameter controller: The MenuViewController receiver

   - returns: An array of section|items tuple
   */
  static func defaultDataSoruceFromMenuController(controller: MenuViewController) -> [(sectionName: String, items: [MenuItem])]{

    var dataSource = [(sectionName: String, items: [MenuItem])]()
    // Home section
    let homeItem = MenuItem(title: L10n.tr("menu.home.title"),
      icon: AzIcon.iconMenuHome(defaultMenuImageWidth),
      initViewController: {return HomeViewController()})

    dataSource.append(("", [homeItem]))

    // Resources section
    let featuresItem = MenuItem(title: L10n.tr("menu.features.title"),
      icon: AzIcon.iconMenuFeatures(defaultMenuImageWidth),
      initViewController: {return WebViewController(title: L10n.tr("menu.features.title"),
        URL: NSURL(string: Config.URLs.features))})

    let videosItem = MenuItem(title: L10n.tr("menu.videos.title"),
      icon: AzIcon.iconMenuVideos(defaultMenuImageWidth),
      initViewController: {return VideosViewController()})

    let helpfulLinksItem = MenuItem(title: L10n.tr("menu.helpful.links.title"),
      icon: AzIcon.iconMenuHelpfulLinks(defaultMenuImageWidth),
      selectedCompletion: {
        controller.toogleLinks()
    })

    let recentUpdatesItem = MenuItem(title: L10n.tr("menu.recent.product.updates.title"),
      icon: AzIcon.iconMenuRecentUpdates(defaultMenuImageWidth),
      initViewController: {return RecentUpdatesController()})

    var twitterItem = MenuItem(title: L10n.tr("menu.twitter.title"),
      icon: AzIcon.iconMenuTwitter(defaultMenuImageWidth),
      initViewController: nil)
    twitterItem.selectedCompletion = {
      AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.SafariViewController.twitter, extras: nil)
      controller.openLink(Config.URLs.twitterAccount)
    }

    var demoAppBackendItem = MenuItem(title: L10n.tr("menu.application.backend.title"),
      icon: AzIcon.iconMenuDemoAppBackend(defaultMenuImageWidth),
      initViewController: nil)
    demoAppBackendItem.separator = true
    demoAppBackendItem.selectedCompletion = {
      AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.SafariViewController.applicationBackend, extras: nil)
      controller.openLink(Config.URLs.backendDemo)
    }

    let getDeviceIdItem = MenuItem(title: L10n.tr("menu.get.device.id.title"),

      icon: AzIcon.iconMenGetDeviceID(defaultMenuImageWidth),
      initViewController: {return GetDeviceIdViewController()})

    dataSource.append((L10n.tr("menu.section.resources"),
      [featuresItem, videosItem, helpfulLinksItem, recentUpdatesItem, twitterItem, demoAppBackendItem, getDeviceIdItem]))

    // Notification scenarios section
    let outOfAppItem = MenuItem(title: L10n.tr("menu.out.of.app.title"),
      icon: AzIcon.iconMenuOutApp(defaultMenuImageWidth),
      initViewController: {return NotificationsViewController(notifScreen: ScreenType.OutOfApp)})

    let inAppItem = MenuItem(title: L10n.tr("menu.in.app.title"),
      icon: AzIcon.iconMenuInApp(defaultMenuImageWidth),
      initViewController: {return NotificationsViewController(notifScreen: ScreenType.InApp)})

    let inAppPopUpItem = MenuItem(title: L10n.tr("menu.in.app.pop.up.title"),
      icon: AzIcon.iconMenuPopUp(defaultMenuImageWidth),
      initViewController: {return NotificationsViewController(notifScreen: ScreenType.InAppPopUp)})

    let webAnnouncementItem = MenuItem(title: L10n.tr("menu.web.announcement.title"),
      icon: AzIcon.iconMenuFullScreen(defaultMenuImageWidth),
      initViewController: {return NotificationsViewController(notifScreen: ScreenType.WebAnnouncement)})

    let fullscreenItem = MenuItem(title: L10n.tr("menu.full.screen.title"),
      icon: AzIcon.iconMenuFullScreen(defaultMenuImageWidth),
      initViewController: {return NotificationsViewController(notifScreen: ScreenType.FullScreen)})

    let pollItem = MenuItem(title: L10n.tr("menu.poll.title"),
      icon: AzIcon.iconMenuPoll(defaultMenuImageWidth),
      initViewController: {return NotificationsViewController(notifScreen: ScreenType.Poll)})

    var dataPushItem = MenuItem(title: L10n.tr("menu.data.push.title"),
      icon: AzIcon.iconMenuDataPush(defaultMenuImageWidth),
      initViewController: {return NotificationsViewController(notifScreen: ScreenType.DataPush)})
    dataPushItem.separator = true

    var aboutItem = MenuItem(title: L10n.tr("menu.about.title"),
      icon: AzIcon.iconMenuAbout(defaultMenuImageWidth),
      initViewController: {return AboutViewController()})
    aboutItem.separator = true

    dataSource.append((L10n.tr("menu.section.notification.scenarios"),
      [outOfAppItem, inAppItem, inAppPopUpItem, webAnnouncementItem, fullscreenItem, pollItem, dataPushItem, aboutItem]))

    return dataSource
  }

}


//
//  NotificationItem.swift
//  Engagement
//
//  Created by Microsoft on 15/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import Foundation

private let defaultImageSize = CGSize(width: 60, height: 60)

/**
 Represent a notification action item on notifications controller screens
 */
public struct NotificationScreenItem
{
  var title: String
  var description: String?
  var color: UIColor
  var action: (() -> Void)//Action when tap on the simulate button
}

/* Represent the type of a notification screen
It can have informations like localized titles or related images
*/
public enum ScreenType{
  case OutOfApp, InApp, InAppPopUp, WebAnnouncement, FullScreen, Poll, DataPush

  var howTitle: String?
    {
      switch (self){
      case .OutOfApp:
        return L10n.tr("how.to.send.these.notification.out.of.app.title")
      case .InApp:
        return L10n.tr("how.to.send.these.notification.in.app.title")
      case .InAppPopUp:
        return L10n.tr("how.to.send.these.notification.in.app.popup.title")
      case .WebAnnouncement:
        return L10n.tr("how.to.send.these.notification.web.announcement.title")
      case .FullScreen:
        return L10n.tr("how.to.send.these.notification.full.screen.interstitial.title")
      case .Poll:
        return L10n.tr("how.to.send.these.notification.poll.title")
      case .DataPush:
        return L10n.tr("how.to.send.these.notification.data.push.title")
      }
  }

  var maintTitle: String?
    {
      switch (self){
      case .OutOfApp:
        return L10n.tr("menu.out.of.app.title")
      case .InApp:
        return L10n.tr("menu.in.app.title")
      case .InAppPopUp:
        return L10n.tr("menu.in.app.pop.up.title")
      case .WebAnnouncement:
        return L10n.tr("menu.web.announcement.title")
      case .FullScreen:
        return L10n.tr("menu.full.screen.title")
      case .Poll:
        return L10n.tr("menu.poll.title")
      case .DataPush:
        return L10n.tr("menu.data.push.title")
      }
  }

  var message: String?
    {
      switch (self){
      case .OutOfApp:
        return L10n.tr("out.of.app.push.notifications.message")
      case .InApp:
        return L10n.tr("in.app.notifications.message")
      case .InAppPopUp:
        return L10n.tr("in.app.coupon.notification.message")
      case .WebAnnouncement:
        return L10n.tr("full.screen.interstitial.message")
      case .FullScreen:
        return L10n.tr("full.screen.interstitial.message")
      case .Poll:
        return L10n.tr("poll.message")
      case .DataPush:
        return L10n.tr("data.push.notification.message")
      }
  }

  var footerLabelTitle: String?{
    switch self{
    case .OutOfApp, .InApp, .InAppPopUp, .FullScreen, .Poll, .WebAnnouncement:
      return "Displays sample notification text"
    case .DataPush:
      return "Displays fictitious product on the Data push screen"
    }
  }

  var image: UIImage?
    {
      switch (self){
      case .OutOfApp:
        return AzIcon.iconMenuOutApp(Int(defaultImageSize.width)).imageWithSize(defaultImageSize)
      case .InApp:
        return AzIcon.iconMenuInApp(Int(defaultImageSize.width)).imageWithSize(defaultImageSize)
      case .InAppPopUp:
        return AzIcon.iconMenuPopUp(Int(defaultImageSize.width)).imageWithSize(defaultImageSize)
      case .WebAnnouncement:
        return AzIcon.iconMenuFullScreen(Int(defaultImageSize.width)).imageWithSize(defaultImageSize)
      case .FullScreen:
        return AzIcon.iconMenuFullScreen(Int(defaultImageSize.width)).imageWithSize(defaultImageSize)
      case .Poll:
        return AzIcon.iconMenuPoll(Int(defaultImageSize.width)).imageWithSize(defaultImageSize)
      case .DataPush:
        return AzIcon.iconMenuDataPush(Int(defaultImageSize.width)).imageWithSize(defaultImageSize)
      }
  }

  var howToRessourcePathName: String?{
    switch self
    {
    case .DataPush:
      return "data_push_notification"
    case .WebAnnouncement:
      return "web_announcement"
    case .FullScreen:
      return "full_screen_interstitial"
    case .InApp:
      return "in_app"
    case .InAppPopUp:
      return "in_app_popup"
    case .OutOfApp:
      return "out_of_app"
    case .Poll:
      return "poll"
    }
  }
}

/**
 Represent the data to display on a notification controller screen
 This simulate the AzME SDK Behavior in local / without Internet connection or withtout Azure Mobile engagement endpoints
 - note: By this way, you can easely add or remove any other NotificationScreenItem in the data source that will be display on attached screen
 */
struct NotificationScreen {

  var screenType: ScreenType
  var dataSource: [NotificationScreenItem]?
  var rootController: UIViewController

  init(rootController: UIViewController, screenType: ScreenType)
  {
    self.rootController = rootController
    self.screenType = screenType
    self.dataSource = buildDataSource()
  }

  /**
   Build the related notifications item an related actions to simulate AzME notification behaviors

   - returns: an optionnal array of NotificationItem
   */
  private func buildDataSource() -> [NotificationScreenItem]?
  {
    switch (self.screenType)
    {
    case .OutOfApp:
      let notifOnly = NotificationScreenItem(title: L10n.tr("out.of.app.push.notifications.notification.only.title"),
        description: L10n.tr("out.of.app.push.notifications.notification.only.message"),
        color: UIColor(named: UIColor.Name.SecondaryPurple),
        action: { () -> Void in
          AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.OutOfAppNotifications.displayNotification, extras: nil)
          self.rootController.presentViewController(UIAlertController.alertControllerPreventNotification
            {
              UIApplication.sharedApplication().scheduleLocalNotification(LocalNotificationFactory.outOfAppNotification)
            },
            animated: true,
            completion: nil)
      })

      let announcement = NotificationScreenItem(title: L10n.tr("out.of.app.push.notifications.announcement.title"),
        description: L10n.tr("out.of.app.push.notifications.announcement.message"),
        color: UIColor(named: UIColor.Name.SecondaryOrange),
        action: { () -> Void in
          AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.OutOfAppNotifications.displayAnnoucement, extras: nil)
          self.rootController.presentViewController(UIAlertController.alertControllerPreventNotification
            {
              UIApplication.sharedApplication().scheduleLocalNotification(LocalNotificationFactory.outOfAppAnnouncementNotification)
            },
            animated: true,
            completion: nil)
      })
      return [notifOnly, announcement]

    case .InApp:
      let notifOnly = NotificationScreenItem(title: L10n.tr("out.of.app.push.notifications.notification.only.title"),
        description: L10n.tr("in.app.notifications.notification.only.message"),
        color: UIColor(named: UIColor.Name.SecondaryPurple),
        action: { () -> Void in
          AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.InAppNotifications.displayNotification, extras: nil)
          var announcement = AnnouncementViewModel()
          announcement.title = L10n.tr("in.app.notifications.notification.title")
          announcement.body = L10n.tr("in.app.notifications.notification.message")
          announcement.action = {
            DeepLinkHelper.canManage(NSURL(string: Config.AzMESDK.DeepLink.recentUpdatesLink)!)
          }
          DeepLinkHelper.displayLocalInAppNotification(announcement, inController: self.rootController)
      })

      let announcement = NotificationScreenItem(title: L10n.tr("out.of.app.push.notifications.announcement.title"),
        description: L10n.tr("in.app.notifications.announcement.message"),
        color: UIColor(named: UIColor.Name.SecondaryOrange),
        action: { () -> Void in
          AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.InAppNotifications.displayAnnouncement,
            extras: nil)
          var announcement = AnnouncementViewModel()
          announcement.title = L10n.tr("in.app.notifications.notification.title")
          announcement.body = L10n.tr("in.app.notifications.notification.message")
          announcement.actionTitle = L10n.tr("home.recent.updates.view.all")
          announcement.exitTitle = L10n.tr("close.button")
          announcement.action = {
            let userInfo = [
              AzMELocalNotification.keyNotificationType : AzMELocalNotification.WebAnnouncement.rawValue,
              AzMELocalNotification.keyNotificationContent : [
                "title": L10n.tr("in.app.notifications.notification.title"),
                "body": L10n.tr("local.rebound.content"),
                "actionButton": L10n.tr("home.recent.updates.view.all"),
                "exitButton": L10n.tr("close.button")
              ],
              AzMELocalNotification.keyNotificationLink : Config.AzMESDK.DeepLink.recentUpdatesLink
            ]

            DeepLinkHelper.manageLocalNotification(userInfo as [NSObject : AnyObject])

          }
          DeepLinkHelper.displayLocalInAppNotification(announcement, inController: self.rootController)
      })
      return [notifOnly, announcement]
    case .InAppPopUp:
      let popUpNotif = NotificationScreenItem(title: L10n.tr("in.app.coupon.notification.display.title"),
        description: "",
        color: UIColor(named: UIColor.Name.SecondaryPurple),
        action: { () -> Void in
          AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.InAppPopUpNotifications.displayInAppPopUp,
            extras: nil)
          let t =  L10n.tr("in.app.coupon.notification.dialog.title")
          let alertController = UIAlertController(title: t,
            message: L10n.tr("in.app.coupon.notification.dialog.description"),
            preferredStyle: UIAlertControllerStyle.Alert)
          let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: {
            action in

            DeepLinkHelper.canManage(NSURL(string: Config.AzMESDK.DeepLink.productLink)!)

          })
          let cancel = UIAlertAction(title: L10n.tr("close.button"), style: UIAlertActionStyle.Cancel, handler: nil)
          alertController.addAction(okAction)
          alertController.addAction(cancel)
          alertController.view.tintColor = UIColor(named: UIColor.Name.PrimaryTheme)
          self.rootController.presentViewController(alertController,
            animated: true,
            completion: nil)
      })
      return [popUpNotif]
    case .WebAnnouncement:
      let fullScreenNotif = NotificationScreenItem(title: L10n.tr("web.announcement.title"),
        description: "",
        color: UIColor(named: UIColor.Name.SecondaryPurple),
        action: { () -> Void in
          AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.FullScreenIntersticial.displayFulLScreenIntersticial,
            extras: nil)

          var announcement = AnnouncementViewModel()
          announcement.title = L10n.tr("full.screen.interstitial.dialog.announcement.title")
          announcement.body = L10n.tr("full.screen.interstitial.dialog.announcement.message")
          announcement.actionTitle = L10n.tr("home.recent.updates.view.all")
          announcement.exitTitle = L10n.tr("close.button")
          announcement.action = {
            let userInfo = [
              AzMELocalNotification.keyNotificationType : AzMELocalNotification.Fullscreen.rawValue,
              AzMELocalNotification.keyNotificationContent : [
                "title" : L10n.tr("full.screen.interstitial.dialog.announcement.title"),
                "body" : L10n.tr("full.screen.interstitial.dialog.announcement.body"),
                "actionButton" : L10n.tr("home.recent.updates.view.all"),
                "exitButton" : L10n.tr("close.button")
              ],
              AzMELocalNotification.keyNotificationLink : Config.URLs.features
            ]

            DeepLinkHelper.manageLocalNotification(userInfo as [NSObject : AnyObject])

          }
          DeepLinkHelper.displayLocalInAppNotification(announcement, inController: self.rootController)
      })
      return [fullScreenNotif]
    case .FullScreen:
      let fullScreenNotif = NotificationScreenItem(title: L10n.tr("full.screen.interstitial.display.title"),
        description: "",
        color: UIColor(named: UIColor.Name.SecondaryPurple),
        action: { () -> Void in
          AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.WebAnnouncement.displayFulLScreenIntersticial,
            extras: nil)
          let userInfo = [
            AzMELocalNotification.keyNotificationType : AzMELocalNotification.Fullscreen.rawValue,
            AzMELocalNotification.keyNotificationContent : [
              "title" : L10n.tr("full.screen.interstitial.dialog.announcement.title"),
              "body" : L10n.tr("full.screen.interstitial.dialog.announcement.body"),
              "actionButton" : L10n.tr("home.recent.updates.view.all"),
              "exitButton" : L10n.tr("close.button")
            ],
            AzMELocalNotification.keyNotificationLink : Config.URLs.features
          ]
          DeepLinkHelper.manageLocalNotification(userInfo as [NSObject : AnyObject])
      })
      return [fullScreenNotif]
    case .Poll:
      let poll = NotificationScreenItem(title: L10n.tr("poll.display.title"),
        description: "",
        color: UIColor(named: UIColor.Name.SecondaryPurple),
        action: { () -> Void in
          AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.Poll.displayPollNotification,
            extras: nil)
          var announcement = AnnouncementViewModel()
          announcement.title = L10n.tr("poll.notification.title")
          announcement.body = L10n.tr("poll.notification.message")
          announcement.actionTitle = L10n.tr("new.poll.submit.title")
          announcement.exitTitle = L10n.tr("negative.button")
          announcement.action = {
            var pollModel = PollViewModel()
            pollModel.title = L10n.tr("new.poll.title")
            pollModel.body = L10n.tr("new.poll.description")
            pollModel.actionTitle = L10n.tr("new.poll.submit.title")
            pollModel.exitTitle = L10n.tr("negative.button")
            let firstQuestion = PollQuestionViewModel(questionId: "1",
              title: L10n.tr("new.poll.question.title.1"),
              choices: [
                PollChoiceViewModel(choiceId: "1", title:  L10n.tr("new.poll.question.yes")),
                PollChoiceViewModel(choiceId: "2", title:  L10n.tr("new.poll.question.no"))
              ])

            let sndQuestion = PollQuestionViewModel(questionId: "2",
              title: L10n.tr("new.poll.question.title.2"),
              choices: [
                PollChoiceViewModel(choiceId: "3", title:  L10n.tr("new.poll.question.yes")),
                PollChoiceViewModel(choiceId: "4", title:  L10n.tr("new.poll.question.no"))
              ])
            pollModel.questions = [firstQuestion, sndQuestion]
            let navController = UINavigationController()
            pollModel.action = {
              navController.pushViewController(SuccessPollViewController(), animated: true)
            }
            let pollController = PollViewController(pollModel: pollModel)

            navController.setViewControllers([pollController], animated: false)
            self.rootController.presentViewController(navController, animated: true, completion: nil)

          }
          DeepLinkHelper.displayLocalInAppNotification(announcement, inController: self.rootController)

      })
      return [poll]
    case .DataPush:
      let silentDataPush = NotificationScreenItem(title: L10n.tr("data.push.notification.display.title"),
        description: "",
        color: UIColor(named: UIColor.Name.SecondaryPurple),
        action: { () -> Void in
          AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.DataPush.launchDataPush,
            extras: nil)
          DeepLinkHelper.pushViewController(ProductViewController(productViewType: .DataPush))
      })
      return [silentDataPush]
    }
  }
}


//
//  PollViewModel.swift
//  Engagement
//
//  Created by Microsoft on 23/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import Foundation

/**
 *  Poll Choice ViewModel abstraction
 */
struct PollChoiceViewModel{

  var choiceId: String
  var title: String

  /**
   Create an array of Choice ViewModels from a AZReachPollQuestion object

   - parameter fromQuestion: AEReachPollQuestion object

   - returns: PollChoice View Model
   */
  static func choices(fromQuestion: AEReachPollQuestion) -> [PollChoiceViewModel]{
    var choices = [PollChoiceViewModel]()

    for choice in fromQuestion.choices {
      if let choicePoll = choice as? AEReachPollChoice {
        choices.append(PollChoiceViewModel(choiceId: choicePoll.choiceId, title: choicePoll.title))
      }
    }
    return choices
  }
}

/**
 *  Poll Question ViewModel abstraction
 */
struct PollQuestionViewModel{
  var questionId: String
  var title: String
  var choices = [PollChoiceViewModel]()

  init(questionId: String, title: String, choices: [PollChoiceViewModel]){
    self.questionId = questionId
    self.title = title
    self.choices = choices
  }

  /**
   Create a poll question View model from an AzME AEReachPollQuestion object

   - parameter fromPollQuestion: the AEReachPollQuestion element

   - returns: PollQuestionViewModel object
   */
  init(fromPollQuestion: AEReachPollQuestion){
    self.questionId = fromPollQuestion.questionId
    self.title = fromPollQuestion.title
    self.choices = PollChoiceViewModel.choices(fromPollQuestion)
  }
}

/**
 *  Represent a ReachPoll abstraction
 */
struct PollViewModel {

  var title = ""
  var actionTitle = ""
  var exitTitle = ""
  var body = ""
  var questions = [PollQuestionViewModel]()

  var action: (() -> Void)?

  init(){}

  init(fromPoll reachPoll: AEReachPoll){
    if let titleValue = reachPoll.title {
      self.title = titleValue
    }
    if let actionValue = reachPoll.actionLabel {
      self.actionTitle = actionValue
    }
    if let exitValue = reachPoll.exitLabel {
      self.exitTitle = exitValue
    }
    if let bodyValue = reachPoll.body {
      self.body = bodyValue
    }

    for question in reachPoll.questions {
      if let questionPoll = question as? AEReachPollQuestion {
        self.questions.append(PollQuestionViewModel(fromPollQuestion: questionPoll))
      }
    }
  }
}


//
//  AzMEService.swift
//  Engagement
//
//  Created by Microsoft on 09/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import Foundation
import SWXMLHash
import SwiftyJSON

/**
 *  Service Manager
 */
struct AzMEService{

  /**
   Retrieve all recent AzME recent updates

   - parameter forHome:    true if you just want the last recent update, false by default
   - parameter completion: Closure paramters : a non empty array of RecentUpdate object and an optionnal error
   */
  static func fetchAzMERecentUpdates(forHome forHome: Bool = false, completion : ([RecentUpdate], NSError?) -> Void )
  {
    if let feedURL = NSURL(string: Config.Services.recentUpdates)
    {
      NSURLSession.sharedSession().dataTaskWithURL(feedURL, completionHandler:
        { (data, response, error) -> Void in
          if let data = data where error == nil
          {
            let xml = SWXMLHash.parse(data)

            var parsedUpdates = [RecentUpdate]()

            let channel = xml.children.first?.children.filter({ (element) -> Bool in
              return element.element?.name == "channel"
            })
            let recentUpdates = channel?.first?.children.filter({ (xmlElement) -> Bool in
              return xmlElement.element?.name == "item"
            })
            if let recentUpdates = recentUpdates
            {
              for update in recentUpdates
              {

                parsedUpdates.append(RecentUpdate.parseFromXMLElements(update))
                if forHome == true{
                  break
                }
              }
            }

            dispatch_async(dispatch_get_main_queue(), { () -> Void in
              completion(parsedUpdates, nil)
            })
          }else{
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
              completion([RecentUpdate](), error)
            })
          }
      }).resume()
    }
  }

  /**
   Retrieve all AzME SDK Video presentations

   - parameter completion: Closure parameter : a non empty Video object array and an optionnal service error
   */
  static func fetchAzMEVideoFeed(completion : ([Video], NSError?) -> Void )
  {
    if let feedURL = NSURL(string: Config.Services.azmeMoviesFeed)
    {
      NSURLSession.sharedSession().dataTaskWithURL(feedURL, completionHandler:
        { (data, response, error) -> Void in
          if let data = data
          {
            do
            {
              let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) as! NSDictionary
              let swiftyJSON = JSON(json)

              var videosParsed = [Video]()
              if let videos = swiftyJSON["result"].array
              {
                for video in videos{
                  videosParsed.append(Video.parseFromJSONElement(video))
                }
                videosParsed.insert(Video.defaultVideo(), atIndex: 0)
              }
              dispatch_async(dispatch_get_main_queue(), { () -> Void in
                completion(videosParsed, nil)
              })
            }
            catch {
              let customError = NSError(domain: "azure.microsoft.com",
                code: 600,
                userInfo: [NSLocalizedDescriptionKey : "Error : incorrect response format"])
              dispatch_async(dispatch_get_main_queue(), { () -> Void in
                completion([Video](), customError)
              })

            }
          }
          else{
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
              completion([Video](), error)
            })
          }
      }).resume()
    }
  }
}


//
//  Config.swift
//  Engagement
//
//  Created by Microsoft on 09/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import Foundation

/**
 *  Contain all default data configurations like URLs or default prices
 */
struct Config {

  static let defaultHTMLHowToDir = "html/how_to_send_notification"

  /**
   *  Services Configuration URLs
   */
  struct Services{
    static let azmeMoviesFeed = "https://aka.ms/azmevideosfile"
    static let recentUpdates = "https://aka.ms/azmerssfeed"
  }

  /**
   *  AzME default Web Links
   */
  struct URLs {
    static let helpfulDocumentation = "http://aka.ms/azmedoclanding"
    static let helpfulPricing = "http://aka.ms/azmepricing"
    static let helpfulSLA = "http://aka.ms/azmesla"
    static let helpfulMSDNForum = "http://aka.ms/azmemsdnforum"
    static let helpfulVoiceForum = "http://aka.ms/azmeuservoice"
    static let twitterAccount = "https://twitter.com/AzureMobileEng"
    static let backendDemo = "http://aka.ms/azmeiosdemoapp"
    static let features = "http://aka.ms/azmefeatures"
    static let applicationsLicenses = "http://aka.ms/azmedemoapplicense"
    static let thirdParties = "http://aka.ms/azmedemoappiosnotices"
    static let smartnsoft = "http://www.smartnsoft.com"
    static let github = "http://aka.ms/azmeiosdemoappsource"
  }

  /**
   *  AzMESDK endPoints configurations
   */
  struct AzMESDK {
    #if DEBUG
    static let endPoint =  ""//Your_Development_EndPoint_Here
    #else
    static let endPoint =  ""//Your_Release_EndPoint_Here
    #endif

    struct DeepLink {
      static let recentUpdatesSubPath = "/recent_updates"
      static let recentUpdatesLink = "engagement://demo/recent_updates"
      static let videosSubPath = "/videos"
      static let videosLink = "engagement://demo/videos"
      static let productSubPath = "/product"
      static let productLink = "engagement://demo/product"
    }

    static let interstitialCategory = "INTERSTITIAL"
    static let webAnnouncementCategory = "WEB_ANNOUNCEMENT"
    static let popUpCategory = "POP-UP"
  }

  struct Notifications {
    static let dataPushValuesUpdated = "dataPushValuesUpdated"

    static let shareActionTitle = "Share"
    static let shareIdentifier = "share"

    static let feedbackActionTitle = "Feedback"
    static let feedbackIdentifier = "feedback"
  }

  /**
   *  Default data about Product Coupon features
   */
  struct Product {
    struct DataPush {
      static let isDiscountAvailable = "isDiscountAvailable"
      static let discountRateInPercent = "discountRateInPercent"
    }
    static func defaultReductionRatio() -> Int{
      return 15
    }
    static let defaultPrice = 899
  }
}


//
//  EventMonitor.swift
//  Engagement
//
//  Created by Microsoft on 19/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import Foundation

/**
 *  Default Analytics monitor to sent events, jobs and activities
 Contains default tags values
 */
struct AnalyticsMonitor{

  /**
   Send a AzME Analytics Event

   - parameter name:   Tag Name
   - parameter extras: Extras Informations
   */
  static func sendActivityNamed(name: String, extras: [NSObject : AnyObject]?){
    EngagementAgent.shared()?.sendEvent(name, extras: extras)
  }

  //MARK: Activities Tags
  struct Activities
  {
    //Openning of the screen
    static let Home                       = "home"
    static let Features                   = "features"
    static let Videos                     = "videos"
    static let HelpfulLinks               = "helpful_links"
    static let RecentUpdates              = "recent_updates"
    static let GetDeviceID                = "get_device_id"
    static let OutOfAppNotifications      = "notification_out_of_app"
    static let InAppNotifications         = "notification_in_app"
    static let InAppPopUpNotifications    = "notification_in_app_popup"
    static let ProductCoupon              = "product_coupon"
    static let FullScreenIntersticial     = "notification_full_screen"
    static let Poll                       = "notification_poll"
    static let PollDetail                 = "poll_detail"
    static let DataPushNotification       = "notification_datapush"
    static let About                      = "about"
    static let ProductDiscount            = "product_discount"
    static let ReboundScreen              = "rebound"
    static let HowToSendTheseNotfications = "how_to_send"

    struct ActivitiesExtras {
      static let notificationType = "notificationType"
      static func notificationExtraValueForType(type: ScreenType) -> String {
        switch type {
        case .OutOfApp:
          return "notification_out_of_app"
        case .InApp:
          return "notification_in_app"
        case .InAppPopUp:
          return "notification_in_app_popup"
        case .WebAnnouncement:
          return "notification_web_announcement"
        case .FullScreen:
          return "notification_full_screen"
        case.Poll:
          return "notification_poll"
        case .DataPush:
          return "notification_datapush"
        }
      }
    }
  }

  //MARK: Events Tags
  struct Events
  {
    struct Home {
      static let viewAllUpdates           = "view_all_udpates"
      private static let clickArticleHome = "click_article_home"
      static func clickArticleHome(title: String?, URL: String?){
        if let title = title, URL = URL{
          AnalyticsMonitor.sendActivityNamed(clickArticleHome, extras:
            [AnalyticsMonitor.Events.EventsExtras.title : title,
              AnalyticsMonitor.Events.EventsExtras.URL : URL
            ])
        }
      }
    }

    struct SafariViewController {
      static let twitter            = "menu_twitter"
      static let applicationBackend = "menu_backend_link"
      static let documentation      = "click_documentation_link"
      static let pricing            = "click_pricing_link"
      static let SLA                = "click_sla_link"
      static let MSDNForum          = "click_msdn_link"
      static let clickSuggestFeatures = "click_suggest_product_features_link"
    }

    struct RecentUpdates {
      private static let clickArticle = "click_article"
      static func clickArticle(title: String?, URL: String?){
        if let title = title, URL = URL{
          AnalyticsMonitor.sendActivityNamed(clickArticle, extras:
            [AnalyticsMonitor.Events.EventsExtras.title : title,
              AnalyticsMonitor.Events.EventsExtras.URL : URL
            ])
        }
      }

    }

    struct GetDeviceID {
      static let share = "share_device_id"
      static let copy  = "copy_device_id"
    }

    struct About {
      static let source   = "click_source_link"
      static let licences = "click_3rd_party_notices_link"
    }

    struct OutOfAppNotifications {
      static let displayNotification = "display_out_of_app_notification_only"
      static let displayAnnoucement  = "display_out_of_app_announcement"
    }

    struct TypeOfNotifications {
      static let notificationOnly = "notification_only_title_message"
    }

    struct ReboundScreen {
      static let close   = "close_rebound"
      static let viewAll = "view_all_from_rebound"
    }

    struct InAppNotifications {
      static let displayNotification = "display_in_app_notification_only"
      static let displayAnnouncement = "display_in_app_announcement"
    }

    struct InAppPopUpNotifications {
      static let displayInAppPopUp = "display_in_app_pop_up"
    }

    struct WebAnnouncement {
      static let displayFulLScreenIntersticial = "web_announcement"
    }

    struct FullScreenIntersticial {
      static let displayFulLScreenIntersticial = "display_full_interstitial"
    }

    struct Poll {
      static let displayPollNotification = "display_poll"
    }

    struct PollDetail {
      static let cancel = "cancel_poll_detail"
      static let submit = "submit_poll_answers"
    }

    struct PollDetailThanks {
      static let close = "close_poll_thanks"
    }

    struct DataPush {
      static let launchDataPush = "launch_data_push"
    }

    struct ProductDiscount {
      static let applyDiscount  = "apply_discount"
      static let removeDiscount = "remove_discount"
    }

    struct Video {
      static let play = "play_video"
      private static let stop = "stop_video"
      static func stop(seconds: Int){

      }
    }

    struct EventsExtras {
      static let title = "title"
      static let URL = "URL"
      static let videoLength = "videoLength"
    }
  }

  //MARK: Jobs Tags
  struct Jobs
  {

    struct Video {

      private static let videoTag = "video"

      static func start(title: String?, URL: String?) {
        if let title = title, videoURL = URL{
          print("Start video job with title '", title, "' and url '", URL)
          EngagementAgent.shared()?.startJob(videoTag,
            extras: [
              AnalyticsMonitor.Events.EventsExtras.title : title,
              AnalyticsMonitor.Events.EventsExtras.URL : videoURL
            ])
        }
      }

      static func end() {
        print("End video job")
        EngagementAgent.shared()?.endJob(videoTag)
      }
    }

  }

}


//
//  AzMENotifier.swift
//  Engagement
//
//  Created by Microsoft on 16/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import Foundation
import QuartzCore
/*
AzME AEDefaultNotifier sublcass to bind in-app notification view informations
*/
class AzMENotifier: AEDefaultNotifier{
  override func nibNameForCategory(category: String!) -> String! {
    return "AzMENotificationView"
  }

  /**
   * This function is called when the notification view must be prepared, e.g. change texts,
   * icon etc... based on the specified content. This is the responsibility of this method to
   * associate actions to the buttons. At this point the notification is not yet attached to the
   * view hierarchy, so you can not have access to its superview.
   *
   * The provided custom view must contains the following subviews:
   *
   *  - `UIImageView` with tag 1 to display the notification icon
   *  - `UILabel` with tag 2 to display the notification's title
   *  - `UILabel` with tag 3 to display the notification's message
   *  - `UIImageView` with tag 4 to display the additional notification image
   *  - `UIButton` with tag 5 used when the notification is 'actioned'
   *  - `UIButton` with tag 6 used when the notification is 'exited'
   *
   * params: content Content to be notified.
   * params: view View used to display the notification.
   * - note: Some "dispatch_after" hacks here due to UI force changes failures (layoutIfNeeded/setNeedsLayout), to improve.
   */
  override func prepareNotificationView(view: UIView!, forContent content: AEInteractiveContent!) {

    super.prepareNotificationView(view, forContent: content)

    if let imageView = view.viewWithTag(1) as? UIImageView {
      imageView.contentMode = .ScaleAspectFit
      if let notificationItem = content.notificationImage {
        imageView.image = notificationItem
      } else {
        imageView.image = UIImage(named: "Icon512")?.imageWithInsets(UIEdgeInsetsMake(0, 0, 45, 0))
      }
    }

    if let titleLabel = view.viewWithTag(2) as? UILabel{
      titleLabel.textColor = UIColor(named: UIColor.Name.GeneralText)
      titleLabel.font = UIFont(named: UIFont.AppFont.Medium, size: 18)
      titleLabel.text = content.notificationTitle
      titleLabel.sizeToFit()
    }

    if let messageLabel = view.viewWithTag(3) as? UILabel{
      messageLabel.textColor = UIColor(named: UIColor.Name.SecondaryText)
      messageLabel.font = UIFont(named: UIFont.AppFont.Regular, size: 16)
      messageLabel.text = content.notificationMessage
      // If your label is included in a nib or storyboard as a subview of the view of a ViewController that uses
      // autolayout, then putting your sizeToFit call into viewDidLoad won't work, because autolayout sizes and
      // positions the subviews after viewDidLoad is called and will immediately undo the effects of your
      // sizeToFit call. However, calling sizeToFit from within viewDidLayoutSubviews will work.
      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.05 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
        messageLabel.sizeToFit()
      }
    }

    if let closeButton = view.viewWithTag(6) as? UIButton{
      closeButton.setImage(AzIcon.iconClose(20).imageWithSize(CGSize(width: 20, height: 20)).imageWithRenderingMode(.AlwaysTemplate),
        forState: .Normal)
      closeButton.tintColor = UIColor(named: UIColor.Name.SmallMentions)
    }

    if let contentView = view.viewWithTag(10) {
      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.05 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {

        contentView.layer.cornerRadius = 5
        contentView.layer.shadowRadius = 5
        contentView.layer.shadowOpacity = 1
        contentView.layer.shadowOffset = CGSizeZero
        contentView.layer.shadowColor = UIColor.blackColor().CGColor
        contentView.layer.masksToBounds = false
        contentView.layer.shadowPath = UIBezierPath(rect: contentView.bounds).CGPath
      }
    }

    if content.category != nil{
      // In case of "INTERSTITIAL" category, we remove the in-app notification view and perform the notification action.
      if content.category == Config.AzMESDK.interstitialCategory {
        if let contentView = view.viewWithTag(10) {
          view.hideAndDisable()
          contentView.hideAndDisable()
          dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
            view.superview?.hideAndDisable()
          }
        }
        // We delayed the notification action to be performed after the AzME SDK notification preparation.
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
          content.actionNotification(true)
        }
        // In case of "POP-UP" category, we customize the in-app notification.
      } else if content.category == Config.AzMESDK.popUpCategory{
        AnalyticsMonitor.sendActivityNamed(AnalyticsMonitor.Events.InAppPopUpNotifications.displayInAppPopUp,
          extras: nil)
        let t =  content.notificationTitle ?? ""
        let alertController = UIAlertController(title: t,
          message: content.notificationMessage ?? "",
          preferredStyle: UIAlertControllerStyle.Alert)
        let okAction = UIAlertAction(title: content.actionLabel ?? "Ok", style: UIAlertActionStyle.Default, handler: {
          action in

          content.actionNotification(true)

        })
        let cancel = UIAlertAction(title: content.exitLabel ?? L10n.tr("close.button"), style: UIAlertActionStyle.Cancel, handler: {
          action in
          content.exitNotification()
        })
        alertController.addAction(okAction)
        alertController.addAction(cancel)
        alertController.view.tintColor = UIColor(named: UIColor.Name.PrimaryTheme)
        if let contentView = view.viewWithTag(10) {
          view.hideAndDisable()
          contentView.hideAndDisable()
          dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
            view.superview?.hideAndDisable()
          }
        }
        DeepLinkHelper.rootNavigationViewController()?.presentViewController(alertController, animated: true, completion: nil)
      }
    } else {
      if let contentView = view.viewWithTag(10) {
        view.showAndEnable()
        contentView.showAndEnable()
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
          view.superview?.hideAndDisable()
        }
      }
    }
  }
}

extension UIView {

  func hideAndDisable() {
    self.hidden = true
    self.userInteractionEnabled = false
  }

  func showAndEnable() {
    self.hidden = false
    self.userInteractionEnabled = true
  }

}

extension UIImage {

  func imageWithInsets(insets: UIEdgeInsets) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(
      CGSizeMake(self.size.width + insets.left + insets.right,
        self.size.height + insets.top + insets.bottom), false, self.scale)
    UIGraphicsGetCurrentContext()
    let origin = CGPoint(x: insets.left, y: insets.top)
    self.drawAtPoint(origin)
    let imageWithInsets = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return imageWithInsets
  }

}


//
//  DeepLinkHelper.swift
//  Engagement
//
//  Created by Microsoft on 16/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import Foundation
import MMDrawerController

private let recentUpdatesDeepLink = Config.AzMESDK.DeepLink.recentUpdatesSubPath
private let videosDeepLink = Config.AzMESDK.DeepLink.videosSubPath
/*
Default local notifications type to simulate across the app
*/
enum AzMELocalNotification: String{
  case DeepLink, WebAnnouncement, Poll, Fullscreen

  static let keyNotificationType = "keyNotificationType"
  static let keyNotificationLink = "keyNotificationLink"
  static let keyNotificationContent = "keyNotificationContent"
}

/**
 *  DeepLink Helper for the App. This will manage UILocalNotifications, RemoteNotifications and some controller worflow behaviors
 */
struct DeepLinkHelper{

  /**
   Return true and perform related action according to the received DeepLink URLScheme

   - parameter url: URL Scheme received

   - returns: Return true if any action can be perfomed by the app
   */
  static func canManage(url: NSURL) -> Bool
  {
    if url.scheme == "http"
    {
      let controller = AzMESafariController(URL: url)
      self.rootNavigationViewController()?.presentViewController(controller, animated: true, completion: nil)
    }
    else if url.path == recentUpdatesDeepLink
    {
      self.pushViewController(RecentUpdatesController())
    }
    else if url.path == videosDeepLink
    {
      self.pushViewController(VideosViewController())
    }
    else if url.path == Config.AzMESDK.DeepLink.productSubPath
    {
      self.pushViewController(ProductViewController())
    }

    return false
  }

  /**
   Manage a UILocalNotification to simulate Push & DeepLinking management in local

   - parameter userInfo: The content of the local notification received
   */
  static func manageLocalNotification(userInfo: [NSObject : AnyObject]?)
  {

    if let userInfo = userInfo,
      type = userInfo[AzMELocalNotification.keyNotificationType] as? String,
      notificationType = AzMELocalNotification(rawValue: type)
    {
      switch notificationType
      {
      case .DeepLink:
        if let linkString = userInfo[AzMELocalNotification.keyNotificationLink] as? String,
          let URL = NSURL(string: linkString)
        {
          DeepLinkHelper.canManage(URL)
        }
        break
      case .WebAnnouncement:
        if let content = userInfo[AzMELocalNotification.keyNotificationContent] as? [NSObject : AnyObject]{

          var fakeAnnouncement = AnnouncementViewModel()
          fakeAnnouncement.title = content["title"] as? String
          fakeAnnouncement.actionTitle = content["actionButton"] as? String
          fakeAnnouncement.exitTitle = content["exitButton"] as? String
          fakeAnnouncement.body = content["body"] as? String
          fakeAnnouncement.action =
            {
              if let linkString = userInfo[AzMELocalNotification.keyNotificationLink] as? String,
                let URL = NSURL(string: linkString)
              {
                self.rootNavigationViewController()?.dismissViewControllerAnimated(true,
                  completion: { () -> Void in
                    DeepLinkHelper.canManage(URL)
                })
              }
          }

          let controller = UINavigationController(rootViewController: AnnouncementViewController(announcement: fakeAnnouncement,
            isLocal: true))

          self.rootNavigationViewController()?.presentViewController(controller,
            animated: true,
            completion: nil)

        }
      case .Fullscreen:
        if let content = userInfo[AzMELocalNotification.keyNotificationContent] as? [NSObject : AnyObject]{

          var fakeAnnouncement = AnnouncementViewModel()
          fakeAnnouncement.title = content["title"] as? String
          fakeAnnouncement.actionTitle = content["actionButton"] as? String
          fakeAnnouncement.exitTitle = content["exitButton"] as? String
          fakeAnnouncement.body = content["body"] as? String
          fakeAnnouncement.action =
            {
              if let linkString = userInfo[AzMELocalNotification.keyNotificationLink] as? String,
                let URL = NSURL(string: linkString)
              {
                self.rootNavigationViewController()?.dismissViewControllerAnimated(true,
                  completion: { () -> Void in
                    DeepLinkHelper.canManage(URL)
                })
              }
          }

          let controller = FullscreenInterstitialViewController(announcement: fakeAnnouncement, isLocal: true)
          //                    controller.view.backgroundColor = UIColor.clearColor()
          //                    controller.modalPresentationStyle = UIModalPresentationStyle.CurrentContext

          controller.providesPresentationContextTransitionStyle = true
          controller.definesPresentationContext = true
          controller.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
          controller.view.backgroundColor = UIColor(named: UIColor.Name.PrimaryTheme)
          self.rootNavigationViewController()?.presentViewController(controller,
            animated: true,
            completion: nil)
        }
        break
      case .Poll: break
      }

    }

  }

  /**
   Analyze the announcement view model object an display a fake in-app AzME notification inside a specific controller

   - parameter announcement: The Announcement View Model which contains deep link and notifications informations
   - parameter inController: The controller where the in-app notification view have to be displayed
   */
  static func displayLocalInAppNotification(announcement: AnnouncementViewModel, inController: UIViewController){

    let notificationView = AzMEInAppNotificationView(announcement: announcement)
    notificationView.alpha = 0
    notificationView.translatesAutoresizingMaskIntoConstraints = false
    inController.view.addSubview(notificationView)

    let trailing = "H:|-0-[notificationView]-0-|"
    let vertical = "V:[notificationView(>=55)]-0-|"

    let trailingConstraint = NSLayoutConstraint.constraintsWithVisualFormat(
      trailing,
      options: [],
      metrics: nil,
      views: ["notificationView" : notificationView])

    let toBottomConstraint = NSLayoutConstraint.constraintsWithVisualFormat(
      vertical,
      options: [],
      metrics: nil,
      views: ["notificationView" : notificationView])

    inController.view.addConstraints(trailingConstraint)
    inController.view.addConstraints(toBottomConstraint)

    notificationView.sizeToFit()
    notificationView.setNeedsLayout()
    notificationView.layoutIfNeeded()
    notificationView.applyShadow()

    UIView.animateWithDuration(0.3) { () -> Void in
      notificationView.alpha = 1
    }
  }

  /**
   Push a ViewController according to the actual view navigation hierarchy

   - parameter controller: ViewController to be pushed
   */
  static func pushViewController(controller: UIViewController){
    self.rootNavigationViewController()?.pushViewController(controller, animated: true)
  }

  /**
   Present a ViewController according to the actual view navigation hierarchy

   - parameter controller: ViewController to be modally presented
   */
  static func presentViewController(controller: UIViewController, animated: Bool){
    self.rootNavigationViewController()?.presentViewController(controller, animated: animated, completion: nil)
  }

  /**
   Retrieve and optionnally return the default root UINavigationController

   - returns: Default root UINavigationController
   */
  static func rootNavigationViewController() -> UINavigationController?
  {
    if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate,
      rootController = appDelegate.window?.rootViewController as? UINavigationController,
      drawer = rootController.viewControllers.first as? MMDrawerController,
      rootNav = drawer.centerViewController as? UINavigationController
    {
      return rootNav
    }
    return nil
  }
}


//
//  File.swift
//  Engagement
//
//  Created by Microsoft on 08/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import Foundation

/**
 *  Retrieve localizable strings with a specific key
 */
struct L10n {
  /**
   Return the correct localizable string value via the localizable key

   - parameter key:  localizable key
   - parameter args: format parameters (if needed)

   - returns: Localizable String
   */
  static func tr(key: String, _ args: CVarArgType...) -> String {
    let format = NSLocalizedString(key, comment: "")
    return String(format: format, arguments: args)
  }
}


//
//  AzIcon.swift
//  Engagement
//
//  Created by Microsoft on 10/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import Foundation
import FontAwesomeKit

/*
Font Awesome icon class to generate dynamic images from a Font file SVG icons and targetted sizes
*/
class AzIcon: FAKIcon{
  struct const {
    static let fontName = "AzME_icons"      // Postscript Font File Name.
    static let fontFileName = "AzME_icons"
  }

  // MARK: - Required Overrides -
  override class func initialize () {
    self.registerIconFontWithURL(NSBundle.mainBundle().URLForResource(const.fontFileName, withExtension:"ttf"))
  }

  override class func iconFontWithSize(size: CGFloat) -> UIFont! {
    if let font = UIFont(name:const.fontName, size:size) {
      return font
    }
    fatalError("Unable to find font \"\(const.fontName)\"")
  }

  class func iconMenuAbout(size: Int = 20) -> AzIcon { return AzIcon(code: "A", size: CGFloat(size)) }
  class func iconMenuDataPush(size: Int = 20) -> AzIcon { return AzIcon(code: "B", size: CGFloat(size)) }
  class func iconMenuDemoAppBackend(size: Int = 20) -> AzIcon { return AzIcon(code: "C", size: CGFloat(size)) }
  class func iconMenuFeatures(size: Int = 20) -> AzIcon { return AzIcon(code: "D", size: CGFloat(size)) }
  class func iconMenuFullScreen(size: Int = 20) -> AzIcon { return AzIcon(code: "E", size: CGFloat(size)) }
  class func iconMenGetDeviceID(size: Int = 20) -> AzIcon { return AzIcon(code: "F", size: CGFloat(size)) }
  class func iconMenuHelpfulLinks(size: Int = 20) -> AzIcon { return AzIcon(code: "G", size: CGFloat(size)) }
  class func iconMenuHome(size: Int = 20) -> AzIcon { return AzIcon(code: "H", size: CGFloat(size)) }
  class func iconMenuInApp(size: Int = 20) -> AzIcon { return AzIcon(code: "I", size: CGFloat(size)) }
  class func iconMenuOutApp(size: Int = 20) -> AzIcon { return AzIcon(code: "J", size: CGFloat(size)) }
  class func iconMenuPoll(size: Int = 20) -> AzIcon { return AzIcon(code: "K", size: CGFloat(size)) }
  class func iconMenuPopUp(size: Int = 20) -> AzIcon { return AzIcon(code: "L", size: CGFloat(size)) }
  class func iconMenuRecentUpdates(size: Int = 20) -> AzIcon { return AzIcon(code: "M", size: CGFloat(size)) }
  class func iconMenuTwitter(size: Int = 20) -> AzIcon { return AzIcon(code: "N", size: CGFloat(size)) }
  class func iconMenuVideos(size: Int = 20) -> AzIcon { return AzIcon(code: "O", size: CGFloat(size)) }
  class func iconLogoAzme(size: Int = 20) -> AzIcon { return AzIcon(code: "P", size: CGFloat(size)) }
  class func iconCheck(size: Int = 20) -> AzIcon { return AzIcon(code: "Q", size: CGFloat(size)) }
  class func iconDocumentation(size: Int = 20) -> AzIcon { return AzIcon(code: "R", size: CGFloat(size)) }
  class func iconMSDNForum(size: Int = 20) -> AzIcon { return AzIcon(code: "S", size: CGFloat(size)) }
  class func iconPricing(size: Int = 20) -> AzIcon { return AzIcon(code: "T", size: CGFloat(size)) }
  class func iconSLA(size: Int = 20) -> AzIcon { return AzIcon(code: "U", size: CGFloat(size)) }
  class func iconUserVoiceForum(size: Int = 20) -> AzIcon { return AzIcon(code: "V", size: CGFloat(size)) }
  class func iconMenuArrow(size: Int = 20) -> AzIcon { return AzIcon(code: "W", size: CGFloat(size)) }
  class func iconMenu(size: Int = 20) -> AzIcon { return AzIcon(code: "X", size: CGFloat(size)) }
  class func iconClose(size: Int = 20) -> AzIcon { return AzIcon(code: "Y", size: CGFloat(size)) }

}


//
//  Colors.swift
//  Engagement
//
//  Created by Microsoft on 08/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import Foundation

extension UIColor {
  convenience init(rgbaValue: UInt32) {
    let red   = CGFloat((rgbaValue >> 24) & 0xff) / 255.0
    let green = CGFloat((rgbaValue >> 16) & 0xff) / 255.0
    let blue  = CGFloat((rgbaValue >>  8) & 0xff) / 255.0
    let alpha = CGFloat((rgbaValue      ) & 0xff) / 255.0

    self.init(red: red, green: green, blue: blue, alpha: alpha)
  }
}

extension UIColor {

  convenience init(named name: Name) {
    self.init(rgbaValue: name.rawValue)
  }

  enum Name: UInt32 {
    case PrimaryTheme       = 0x00abecff// #00abec
    case PrimaryThemeLight  = 0x33bcf0ff// #33bcf0
    case PrimaryThemeDark   = 0x0089bdff// #0089bd
    case PrimaryText        = 0xffffffff// #ffffff
    case PrimaryTextPressed = 0xedededff// #ededed
    case GeneralText        = 0x303030ff// #303030
    case SecondaryText      = 0x6a6a6aff// #6a6a6a
    case SmallMentions      = 0xa9a9a9ff// #a9a9a9
    case SecondaryOrange    = 0xff8c00ff// #f8c00
    case SecondaryPurple    = 0x68217aff// #68217a
    case SecondaryGrey      = 0xf6f6f6ff// #f6f6f6
    case LightGrey          = 0xcacbccff// #cacbcc
    case DarkGrey          = 0x9e9e9eff// #9E9E9E
  }

  /**
   Return an UIImage based on an UIColor

   - parameter color: The UIColor to based on
   - parameter size:  the desired size, 20x20 by default

   - returns: an UIImage based on an UIColor
   */
  static func imageWithColor(color: UIColor, size: CGSize = CGSize(width: 20, height: 20)) -> UIImage {
    let rect = CGRectMake(0, 0, size.width, size.height)
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    color.setFill()
    UIRectFill(rect)
    let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
  }

}


//
//  Foundation+Extensions.swift
//  Engagement
//
//  Created by Microsoft on 29/03/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import Foundation

extension String{
  init(HTMLString: String){
    self = "<html> <head> <link rel=\"stylesheet\" type=\"text/css\" href=\"html/styles.css\"/> </head> <body> <p>" + HTMLString + "</p> </body> </html>"
  }
}


//
//  Theme.swift
//  Engagement
//
//  Created by Microsoft on 08/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import Foundation

/**
 *  Configure the UI default styles like navigation bar appearence
 */
struct Theme{

  /**
   Prepare the default style. The method have to be initially call from the app delegate didFinishLauching method
   */
  static func prepareThemeAppearance(){
    UIApplication.setStatusBarStyle(.LightContent)

    //Custom UINavigationBar Appearance
    let navAppearance = UINavigationBar.appearance()
    navAppearance.barTintColor = UIColor(named: UIColor.Name.PrimaryTheme)
    navAppearance.tintColor = .whiteColor()
    navAppearance.titleTextAttributes = [NSForegroundColorAttributeName : UIColor.whiteColor()]
    navAppearance.translucent = false
    navAppearance.setBackgroundImage(UIImage(), forBarPosition: .Any, barMetrics: .Default)
    navAppearance.shadowImage = UIImage()
  }
}


//
//  UIFont.swift
//  Engagement
//
//  Created by Microsoft on 11/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import UIKit

extension UIFont {
  enum AppFont : String {
    case Regular = ".SFUIDisplay-Regular"
    case Medium  = ".SFUIDisplay-Medium"
    case Bold    = ".SFUIDisplay-Bold"
    case Light   = ".SFUIDisplay-Light"
    case Italic  = ".SFUIText-Italic"
  }

  /**
   Create an return a desired default App Font

   - parameter name: The AppFont enum font name
   - parameter size: desired size of your string

   - returns: Custom UIFont
   */
  convenience init(named name: AppFont, size:CGFloat) {
    self.init(name:name.rawValue, size:size)!
  }
}


//
//  UIKit+Extensions.swift
//  Engagement
//
//  Created by Microsoft on 10/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import Foundation
import MMDrawerController

//MARK: UIApplication
extension UIApplication{
  static func showHUD(){
    UIApplication.sharedApplication().networkActivityIndicatorVisible = true
  }
  static func dismissHUD(){
    UIApplication.sharedApplication().networkActivityIndicatorVisible = false
  }

  static func setStatusBarStyle(style: UIStatusBarStyle, animated: Bool = false){
    UIApplication.sharedApplication().setStatusBarStyle(style, animated: animated)
  }

  static func checkStatusBarForDrawer(drawer: MMDrawerController?){
    if let drawer = drawer {
      if drawer.openSide == .Left{
        UIApplication.setStatusBarStyle(.Default)
      }else{
        UIApplication.setStatusBarStyle(.LightContent)
      }
    }
  }
}

//MARK: UIAlertController
extension UIAlertController{
  static func alertControllerPreventNotification(completion : () -> Void) -> UIAlertController {
    let alertController = UIAlertController(title: "A notification is going to be sent",
      message: "The out-of-app can't appear in the notification center if you are still in the application. Please press OK on this popup and then press the home button on your phone.",
      preferredStyle: UIAlertControllerStyle.Alert)
    let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: {
      action in

      completion()

    })
    alertController.addAction(okAction)

    return alertController
  }
}

//MARK: UIViewController
extension UIViewController{
  func closeDrawer () {
    self.mm_drawerController.closeDrawerAnimated(true,
      completion: { [weak self] completed in
        UIApplication.checkStatusBarForDrawer(self?.mm_drawerController)
      })
  }
}

//MARK: UITableView
extension UITableView {
  //set the tableHeaderView so that the required height can be determined, update the header's frame and set it again
  func setAndLayoutTableFooterView(footer: UIView) {
    self.tableFooterView = footer
    footer.setNeedsLayout()
    footer.layoutIfNeeded()
    let height = footer.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
    var frame = footer.frame
    frame.size.height = height
    footer.frame = frame
    self.tableFooterView = footer
  }

  func layoutTableFooterView() {
    if let footer = self.tableFooterView{
      let height = footer.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
      var frame = footer.frame
      frame.size.height = height
      footer.frame = frame
      self.tableFooterView = footer
    }
  }

  func setAndLayoutTableHeaderView(header: UIView) {
    self.tableHeaderView = header
    header.setNeedsLayout()
    header.layoutIfNeeded()
    let height = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
    var frame = header.frame
    frame.size.height = height
    header.frame = frame
    self.tableHeaderView = header
  }

  func layoutTableHeaderView() {
    if let header = self.tableHeaderView{
      let height = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
      var frame = header.frame
      frame.size.height = height
      header.frame = frame
      self.tableHeaderView = header
    }
  }
}


//
//  TextFeedCell.swift
//  Engagement
//
//  Created by Microsoft on 10/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import UIKit

/*
UITableViewCell used by the Home and RecentUpdate screens.
Display informations about SDK news
*/
class TextFeedCell: UITableViewCell {

  @IBOutlet weak var ibSubTitle: UILabel!
  @IBOutlet weak var ibMainTitle: UILabel!
  @IBOutlet weak var ibFeedContentView: UIView!
  @IBOutlet weak var ibDescription: UILabel!

  static let identifier = "TextFeedCell"

  //MARK: Overriding
  override func awakeFromNib() {
    super.awakeFromNib()

    self.ibFeedContentView.layer.borderColor = UIColor(named: UIColor.Name.PrimaryTextPressed).CGColor
    self.ibFeedContentView.layer.borderWidth = 1

    self.ibMainTitle.font = UIFont(named: UIFont.AppFont.Medium, size: 15)
    self.ibMainTitle.textColor = UIColor(named: UIColor.Name.GeneralText)

    self.ibSubTitle.font = UIFont(named: UIFont.AppFont.Regular, size: 13)
    self.ibSubTitle.textColor = UIColor(named: UIColor.Name.SmallMentions)

    self.ibDescription.font = UIFont(named: UIFont.AppFont.Regular, size: 15)
    self.ibDescription.textColor = UIColor(named: UIColor.Name.SecondaryText)

    self.backgroundColor = UIColor(named: UIColor.Name.SecondaryGrey)
  }

  override func setSelected(selected: Bool, animated: Bool) {

    if selected == true{
      self.ibFeedContentView.backgroundColor = UIColor(named: UIColor.Name.SecondaryGrey)
    }else{
      self.ibFeedContentView.backgroundColor = .whiteColor()
    }
  }

  override func setHighlighted(highlighted: Bool, animated: Bool) {
    if highlighted == true{
      self.ibFeedContentView.backgroundColor = UIColor(named: UIColor.Name.SecondaryGrey)
    }else{
      self.ibFeedContentView.backgroundColor = .whiteColor()
    }
  }

  /**
   Update cell content with news titles

   - parameter title:       The news title
   - parameter subTitle:    SubTitle (the date for instance)
   - parameter description: News description
   */
  func updateWith(title: String?, subTitle: String?, description: String?){
    self.ibMainTitle.text = title
    self.ibSubTitle.text  = subTitle
    self.ibDescription.text  = description
  }

}


//
//  HighlightCell.swift
//  Engagement
//
//  Created by Microsoft on 11/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import UIKit

/**
 Displayed into the Home Screen, displayed Check Mark fetaures Highlights of the AzME SDK
 */
class HighlightCell: UITableViewCell {

  @IBOutlet weak var ibTitle: UILabel!
  @IBOutlet weak var ibImage: UIImageView!

  static let identifier = "HighlightCell"

  override func awakeFromNib() {
    super.awakeFromNib()

    self.backgroundColor = UIColor(named: UIColor.Name.SecondaryOrange)

    self.ibTitle.font = UIFont(named: UIFont.AppFont.Medium, size: 14)
    self.ibImage.image = AzIcon.iconCheck(15).imageWithSize(CGSize(width: 15, height: 15)).imageWithRenderingMode(.AlwaysTemplate)
  }

  func updateWith(title: String?){
    self.ibTitle.text = title
  }

}


//
//  ExpandableTableView.swift
//  Engagement
//
//  Created by Jocelyn Girard on 10/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import UIKit

protocol HeaderViewDelegate: NSObjectProtocol {
    func headerViewOpen(section:Int)
    func headerViewClose(section:Int)
}

class UIExpandableTableView : UITableView, HeaderViewDelegate {

    var sectionOpen:Int = NSNotFound

    // MARK: HeaderViewDelegate
    func headerViewOpen(section: Int) {

        if self.sectionOpen != NSNotFound {
            headerViewClose(self.sectionOpen)
        }

        self.sectionOpen = section
        let numberOfRows = self.dataSource?.tableView(self, numberOfRowsInSection: section)
        var indexesPathToInsert:[NSIndexPath] = []

        for var i = 0; i < numberOfRows; i++ {
            indexesPathToInsert.append(NSIndexPath(forRow: i, inSection: section))
        }

        if indexesPathToInsert.count > 0 {
            self.beginUpdates()
            self.insertRowsAtIndexPaths(indexesPathToInsert, withRowAnimation: UITableViewRowAnimation.Automatic)
            self.endUpdates()
        }
    }

    func headerViewClose(section: Int) {

        let numberOfRows = self.dataSource?.tableView(self, numberOfRowsInSection: section)
        var indexesPathToDelete:[NSIndexPath] = []
        self.sectionOpen = NSNotFound

        for var i = 0 ; i < numberOfRows; i++ {
            indexesPathToDelete.append(NSIndexPath(forRow: i, inSection: section))
        }

        if indexesPathToDelete.count > 0 {
            self.beginUpdates()
            self.deleteRowsAtIndexPaths(indexesPathToDelete, withRowAnimation: UITableViewRowAnimation.Top)
            self.endUpdates()
        }
    }
}


//
//  MenuCell.swift
//  Engagement
//
//  Created by Microsoft on 09/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import UIKit

/**
 UITableViewCell displayed into the Menu Left Screen
 */
class MenuCell: UITableViewCell {

  @IBOutlet weak var ibIcon: UIImageView!
  @IBOutlet weak var ibTitle: UILabel!
  @IBOutlet weak var ibExpandIndicator: UIImageView!

  static let identifier = "MenuCell"

  var menuItem: MenuItem? {
    didSet {
      if let item = menuItem {
        self.ibTitle?.text = item.title
        self.ibIcon?.image = item.icon

        if item.isChild == true {
          self.backgroundColor = UIColor(named: UIColor.Name.SecondaryGrey)

        }else{
          self.backgroundColor = .whiteColor()
        }

        if item.selectedCompletion != nil && item.isChild == false {
          self.ibExpandIndicator.hidden = false
        } else {
          self.ibExpandIndicator.hidden = true
        }
      }
    }

  }

  override func awakeFromNib() {
    super.awakeFromNib()
    self.layoutMargins = UIEdgeInsetsZero
    ibTitle.font = UIFont(named: UIFont.AppFont.Medium, size: 15)
  }

  override func setSelected(selected: Bool, animated: Bool) {
    if (menuItem?.isSelectable == true) {
      if selected == true {
        self.ibTitle.textColor = UIColor(named: UIColor.Name.PrimaryTheme)
      } else {
        self.ibTitle.textColor = UIColor(named: UIColor.Name.GeneralText)

      }
    }
    else{
      self.ibTitle.textColor = UIColor(named: UIColor.Name.GeneralText)
      if menuItem?.isChild == true{
        self.ibTitle.textColor = UIColor(named: UIColor.Name.SecondaryText)
      }
    }
    self.ibIcon.tintColor = self.ibTitle.textColor
  }

  //TODO
  func toggleIndicator()
  {
    let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
    rotationAnimation.toValue = M_PI
    rotationAnimation.duration = 1.0

    self.ibExpandIndicator.layer.addAnimation(rotationAnimation, forKey: "rotationAnimation")
  }

}


//
//  MenuSectionCell.swift
//  Engagement
//
//  Created by Jocelyn Girard on 10/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

class HeaderView: UIView {

    var delegate:HeaderViewDelegate?
    var section:Int?
    var tableView:UIExpandableTableView?

    required init(tableView:UIExpandableTableView, section:Int){

        let height = tableView.delegate?.tableView!(tableView, heightForHeaderInSection: section)
        let frame = CGRectMake(0, 0, CGRectGetWidth(tableView.frame), height!)

        super.init(frame: frame)

        self.tableView = tableView
        self.delegate = tableView
        self.section = section
    }

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

    override func layoutSubviews() {
        let toggleButton = UIButton()
        toggleButton.addTarget(self, action: "toggle:", forControlEvents: UIControlEvents.TouchUpInside)
        toggleButton.backgroundColor = UIColor.clearColor()
        toggleButton.frame = CGRectMake(0, 0, self.frame.width, self.frame.height)
        self.addSubview(toggleButton)
    }

    func toggle(sender:AnyObject){

        if self.tableView!.sectionOpen != section! {
            self.delegate?.headerViewOpen(section!)
        } else if self.tableView!.sectionOpen != NSNotFound {
            self.delegate?.headerViewClose(self.tableView!.sectionOpen)
        }
    }
}


//
//  NotifiActionCell.swift
//  Engagement
//
//  Created by Microsoft on 15/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import UIKit

/**
 *  Notify that the embeded UIButton has been "touch up inside"
 */
protocol NotifActionDelegate: class{
  func didTapButton(atIndex: NSIndexPath?)
}

/**
 Notification UI table view cell with an embeded UIButton and text description
 */
class NotifiActionCell: UITableViewCell {

  @IBOutlet weak var ibActionButton: AzButton!
  @IBOutlet weak var ibDescription: UILabel!

  static let identifier = "NotifiActionCell"

  private weak var delegate: NotifActionDelegate?
  private var index: NSIndexPath?

  //MARK: Overriding
  override func awakeFromNib() {
    super.awakeFromNib()

    self.ibDescription.font = UIFont(named: UIFont.AppFont.Italic, size: 13)
    self.ibActionButton.titleLabel?.font = UIFont(named: UIFont.AppFont.Medium, size: 17)
  }

  //MARK: Actions
  @IBAction func didTapActionButton(sender: AnyObject) {
    self.delegate?.didTapButton(self.index)
  }

  /**
   Update the notification cell with content

   - parameter item:     The NotificationScreenItem which contain several information like texts or UI colors
   - parameter index:    The indexPath of the UITableViewCell, used by the NotifActionDelegate (could be evolved with a completion block)
   - parameter delegate: NotifActionDelegate
   */
  func update(item: NotificationScreenItem, index: NSIndexPath, delegate: NotifActionDelegate)
  {
    ibActionButton.setTitle(item.title, forState: .Normal)
    ibActionButton.setBackgroundImage(UIColor.imageWithColor(item.color) , forState: .Normal)
    ibDescription.text = item.description
    self.delegate = delegate
    self.index = index

  }

}


//
//  PollChoiceCell.swift
//  Engagement
//
//  Created by Microsoft on 22/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import UIKit

/**
 Poll Choice UI, with a radio button
 */
class PollChoiceCell: UITableViewCell {

  @IBOutlet weak var ibRadioImage: UIImageView!
  @IBOutlet weak var ibChoiceTitle: UILabel!

  static let identifier = "PollChoiceCell"

  //MARK: Overriding
  override func setSelected(selected: Bool, animated: Bool) {

    self.applyStyleForSelecteState(selected)
  }

  override func setHighlighted(highlighted: Bool, animated: Bool) {
    if highlighted == true{
      ibRadioImage.image = UIImage(named: "radio_button_off_pressed")
    }
    else{
      self.applyStyleForSelecteState(self.selected)
    }
  }

  /**
   Apply the correct selected style for the radio image (like a button)

   - parameter selected: Selected state
   */
  private func applyStyleForSelecteState(selected: Bool){
    if selected == true{
      ibRadioImage.image = UIImage(named: "radio_button_on")
    }
    else{
      ibRadioImage.image = UIImage(named: "radio_button_off")
    }
  }

  /**
   Update the poll cell choice title

   - parameter title: Choice title
   */
  func update(title: String){
    self.ibChoiceTitle.text = title
  }
}


//
//  VideoCell.swift
//  Engagement
//
//  Created by Microsoft on 11/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import UIKit
import AlamofireImage

/**
 UITableViewCell to represent a video model
 */
class VideoCell: UITableViewCell {

  @IBOutlet weak var ibVideoImage: UIImageView!
  @IBOutlet weak var ibVideoTitle: UILabel!
  @IBOutlet weak var ibVideoDescription: UILabel!
  @IBOutlet weak var ibSubContentView: UIView!

  static let identifier = "VideoCell"

  //MARK: Overriding
  override func awakeFromNib()
  {
    super.awakeFromNib()

    ibVideoTitle.font = UIFont(named: UIFont.AppFont.Regular, size: 18)
    ibVideoTitle.textColor = UIColor(named: UIColor.Name.PrimaryTheme)

    ibVideoDescription.font = UIFont(named: UIFont.AppFont.Regular, size: 15)
    ibVideoDescription.textColor = UIColor(named: UIColor.Name.SecondaryText)

    ibSubContentView.layer.borderWidth = 1
    ibSubContentView.layer.borderColor = UIColor(named: UIColor.Name.LightGrey).CGColor
  }

  override func prepareForReuse() {
    super.prepareForReuse()
    self.ibVideoImage.af_cancelImageRequest()
  }

  /**
   Update the video cell with specific datas

   - parameter title:      Video title
   - parameter subTitle:   Video description
   - parameter imageLink:  URL Image to download
   - parameter localImage: true if the URL image is in the App Assets
   */
  func updateWith(title: String?, subTitle: String?, imageLink: String?, localImage: Bool = false)
  {
    self.ibVideoTitle.text = title
    self.ibVideoDescription.text = subTitle
    if let imageName = imageLink where localImage == true
    {
      self.ibVideoImage.image = UIImage(named: imageName)
    }
    else if let link = imageLink, imageURL = NSURL(string: link)
    {
      self.ibVideoImage.af_setImageWithURL(imageURL,
        placeholderImage: nil,
        imageTransition: UIImageView.ImageTransition.CrossDissolve(0.3))
    }
  }

  override func setHighlighted(highlighted: Bool, animated: Bool) {
    super.setHighlighted(highlighted, animated: animated)

    if (highlighted == true)
    {
      self.ibSubContentView.backgroundColor = UIColor.lightGrayColor()
    }
    else
    {
      self.ibSubContentView.backgroundColor = UIColor.whiteColor()
    }
  }

}


//
//  AzButton.swift
//  Engagement
//
//  Created by Microsoft on 12/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

/// AzME Default Button Style
class AzButton : UIButton {

  required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)

    applyTheme()
  }

  override init(frame: CGRect) {
    super.init(frame: frame)

    applyTheme()
  }

  func applyTheme() {
    self.backgroundColor = UIColor(named: UIColor.Name.PrimaryTheme)
    self.layer.cornerRadius = 5
    self.layer.masksToBounds = true
  }
}


//
//  AzMEInAppNotificationView.swift
//  Engagement
//
//  Created by Microsoft on 18/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import UIKit

/// Local Fake InApp AzME notification
class AzMEInAppNotificationView: UIView {

  @IBOutlet var ibRootView: UIView!
  @IBOutlet weak var ibTitleLabel: UILabel!
  @IBOutlet weak var ibMessageLabel: UILabel!
  @IBOutlet weak var ibContentView: UIView!
  @IBOutlet weak var ibCloseButton: UIButton!

  private var announcementVM: AnnouncementViewModel?

  //MARK: Initialization
  override init(frame: CGRect) {
    super.init(frame: frame)
    commonInit()
  }

  required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    commonInit()
  }

  init(announcement: AnnouncementViewModel){
    self.announcementVM = announcement
    super.init(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
    self.commonInit()
  }

  func commonInit() {
    NSBundle.mainBundle().loadNibNamed("AzMEInAppNotificationView", owner: self, options: nil)
    self.frame = self.ibRootView.frame
    self.addSubview(self.ibRootView)

    ibTitleLabel.textColor = UIColor(named: UIColor.Name.GeneralText)
    ibTitleLabel.font = UIFont(named: UIFont.AppFont.Medium, size: 17)

    ibMessageLabel.textColor = UIColor(named: UIColor.Name.SecondaryText)
    ibMessageLabel.font = UIFont(named: UIFont.AppFont.Regular, size: 15)

    self.ibTitleLabel.text = self.announcementVM?.title
    self.ibMessageLabel.text = self.announcementVM?.body

    ibCloseButton.setImage(AzIcon.iconClose(18).imageWithSize(CGSize(width: 18, height: 18)).imageWithRenderingMode(.AlwaysTemplate),
      forState: .Normal)
    ibCloseButton.tintColor = UIColor(named: UIColor.Name.SmallMentions)

  }

  func applyShadow(){
    self.ibContentView.layer.cornerRadius = 5
    self.ibContentView.layer.shadowOpacity = 1
    self.ibContentView.layer.shadowRadius = 5
    self.ibContentView.layer.shadowOffset = CGSizeZero
    self.ibContentView.layer.shadowColor = UIColor.blackColor().CGColor
    self.ibContentView.layer.masksToBounds = false
    self.ibContentView.layer.shadowPath = UIBezierPath(rect: self.ibContentView.bounds).CGPath
  }

  //MARK: Actions
  @IBAction func didTapCloseButton(sender: AnyObject) {
    UIView.animateWithDuration(0.3,
      animations: { () -> Void in
        self.alpha = 0
      }){ (completed) -> Void in
        self.removeFromSuperview()
    }
  }

  @IBAction func didTapActionButton(sender: AnyObject)
  {
    UIView.animateWithDuration(0.3,
      animations: { () -> Void in
        self.alpha = 0
      }){ (completed) -> Void in
        self.announcementVM?.action?()
        self.removeFromSuperview()

    }
  }
}


//
//  FeedHeader.swift
//  Engagement
//
//  Created by Microsoft on 10/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import UIKit

/// FeedHeader
class FeedHeader: UIView {

  @IBOutlet weak var ibRootView: UIView!
  @IBOutlet weak var ibHeaderTitle: UILabel!
  @IBOutlet weak var ibActionButton: UIButton!

  var action: (() -> Void)?

  //MARK: Initialization
  override init(frame: CGRect) {
    super.init(frame: frame)
    commonInit()
  }

  required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    commonInit()
  }

  func commonInit() {
    NSBundle.mainBundle().loadNibNamed("FeedHeader", owner: self, options: nil)
    self.frame = self.ibRootView.frame
    self.addSubview(self.ibRootView)

    self.ibRootView.backgroundColor = UIColor(named: UIColor.Name.PrimaryTextPressed)

    self.ibHeaderTitle.font = UIFont(named: UIFont.AppFont.Regular, size: 18)

    self.ibActionButton.addTarget(self, action: #selector(FeedHeader.didTapButton), forControlEvents: .TouchUpInside)
    self.ibActionButton.titleLabel?.font = UIFont(named: UIFont.AppFont.Regular, size: 13)
  }

  //MARK: Actions
  func didTapButton(){
    self.action?()
  }

  /**
   Update cell with correct UI content

   - parameter title:       Notification title
   - parameter buttonTitle: The title of the right button of section view
   - parameter action:      Target action for the right button of section view
   - parameter bgColor:     section view header background color
   - parameter titleColor:  section title color
   */
  func updateWith(title: String?, buttonTitle: String?, action : (() -> Void)? = nil, bgColor: UIColor?, titleColor: UIColor?){
    self.ibHeaderTitle.text =  title
    self.ibHeaderTitle.textColor = titleColor

    self.ibActionButton.setTitle(buttonTitle?.uppercaseString, forState: .Normal)
    self.action = action
    self.ibRootView.backgroundColor = bgColor
    self.ibActionButton.addTarget(self, action: #selector(FeedHeader.didTapButton), forControlEvents: .TouchUpInside)
  }

}


//
//  NotifTableHeader.swift
//  Engagement
//
//  Created by Microsoft on 15/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import UIKit

/*
Table Header View which didsplay the Notification's scenario description (image + text)
*/
class NotifTableHeader: UIView {

  @IBOutlet var ibRootView: UIView!
  @IBOutlet weak var ibMainTitle: UILabel!
  @IBOutlet weak var ibIcon: UIImageView!

  override init(frame: CGRect) {
    super.init(frame: frame)
    commonInit()
  }

  required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    commonInit()
  }

  func commonInit() {
    NSBundle.mainBundle().loadNibNamed("NotifTableHeader", owner: self, options: nil)
    self.frame = self.ibRootView.frame
    self.addSubview(self.ibRootView)

    self.ibMainTitle.font = UIFont(named: UIFont.AppFont.Regular, size: 22)
  }

  /**
   Update the view with correct description elements

   - parameter image:     Top left image
   - parameter mainTitle: descritpion text, displayed above image
   */
  func update(image: UIImage?, mainTitle: String?){
    self.ibIcon.image = image?.imageWithRenderingMode(.AlwaysTemplate)
    self.ibMainTitle.text = mainTitle
  }
}


//
//  SimpleHeaderLabel.swift
//  Engagement
//
//  Created by Microsoft on 23/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import Foundation

/**
 Header View type to differenciate implementation but with the same layout but different confihuration.
 Particularly, there is different superview margins

 - TableHeader:   For Table View Headers
 - SectionHeader: For Section View headers
 */
enum HeaderViewType{
  case TableHeader, SectionHeader

  func marginProperties() -> UIEdgeInsets{
    switch self{
    case .TableHeader:
      return  UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
    case .SectionHeader:
      return UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
    }
  }
}

/// View with an embeded label with superview inset margins
class SimpleHeaderLabel: UIView{

  @IBOutlet weak var ibTopMargin: NSLayoutConstraint!
  @IBOutlet weak var ibBottomMargin: NSLayoutConstraint!
  @IBOutlet weak var ibLeftMargin: NSLayoutConstraint!
  @IBOutlet weak var ibRightMargin: NSLayoutConstraint!

  @IBOutlet weak var ibTitle: UILabel!
  @IBOutlet var ibRootView: UIView!

  //MARK: Initializations
  override init(frame: CGRect) {
    super.init(frame: frame)
    commonInit()
  }

  required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    commonInit()
  }

  func commonInit() {
    NSBundle.mainBundle().loadNibNamed("SimpleHeaderLabel", owner: self, options: nil)
    self.frame = self.ibRootView.frame
    self.addSubview(self.ibRootView)
  }

  private func updateType(headerType: HeaderViewType){
    self.ibTopMargin.constant = headerType.marginProperties().top
    self.ibBottomMargin.constant = headerType.marginProperties().bottom
    self.ibLeftMargin.constant = headerType.marginProperties().left
    self.ibRightMargin.constant = headerType.marginProperties().right
  }

  /**
   Update the view with text description and style

   - parameter font:       Label font
   - parameter mainTitle:  Label title
   - parameter headerType: Section type configuration
   */
  func update(font: UIFont?, mainTitle: String?, headerType: HeaderViewType){
    self.ibTitle.font = font
    self.ibTitle.text = mainTitle
    self.updateType(headerType)
  }

  func updateAttributed(title: NSAttributedString, headerType: HeaderViewType){
    self.ibTitle.attributedText = title
    self.updateType(headerType)
  }

  /**
   Compute and return the estimated header view height embeded in a specific view width

   - parameter font:        The Label font that will be set to the header
   - parameter forTitle:    The texte title that will be set to the header embeded label
   - parameter insideWidth: The parent container view width inside the header will be displayed
   - parameter headerType:  HeaderType configuration

   - returns: The estimated height of the header (CGFloat)
   */
  static func headerHeight(font: UIFont, forTitle: String, insideWidth: CGFloat, headerType: HeaderViewType) -> CGFloat
  {
    let size = CGSize(width: insideWidth - headerType.marginProperties().left - headerType.marginProperties().right,
      height: CGFloat.infinity)
    let computedTitleRect = forTitle.boundingRectWithSize(size,
      options: .UsesLineFragmentOrigin,
      attributes: [NSFontAttributeName : font],
      context: nil)
    return computedTitleRect.height + headerType.marginProperties().top + headerType.marginProperties().bottom + 5
  }
}


//
//  EngagementTests.swift
//  EngagementTests
//
//  Created by Microsoft on 08/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import XCTest
@testable import Engagement

class EngagementTests: XCTestCase {

    override func setUp() {
        super.setUp()
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }

    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }

    func testExample() {
        // This is an example of a functional test case.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }

    func testPerformanceExample() {
        // This is an example of a performance test case.
        self.measureBlock {
            // Put the code you want to measure the time of here.
        }
    }

}


//
//  EngagementUITests.swift
//  EngagementUITests
//
//  Created by Microsoft on 08/02/2016.
//  Copyright Â© 2016 Microsoft. All rights reserved.
//

import XCTest

class EngagementUITests: XCTestCase {

    override func setUp() {
        super.setUp()

        // Put setup code here. This method is called before the invocation of each test method in the class.

        // In UI tests it is usually best to stop immediately when a failure occurs.
        continueAfterFailure = false
        // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
        XCUIApplication().launch()

        // In UI tests itâ€™s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
    }

    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }

    func testCollapse(){

        let app = XCUIApplication()
        app.navigationBars["Engagement.HomeView"].childrenMatchingType(.Button).elementBoundByIndex(0).tap()

        let tablesQuery = app.tables
        tablesQuery.cells.containingType(.StaticText, identifier:"Helpful links").childrenMatchingType(.StaticText).matchingIdentifier("Helpful links").elementBoundByIndex(0).tap()
        tablesQuery.staticTexts["Helpful links"].tap()

    }

    func testVideos() {
        // Use recording to get started writing UI tests.
        // Use XCTAssert and related functions to verify your tests produce the correct results.

        let app = XCUIApplication()
        app.navigationBars["Engagement.HomeView"].childrenMatchingType(.Button).elementBoundByIndex(0).tap()

        let tablesQuery = app.tables
        tablesQuery.cells.containingType(.StaticText, identifier:"Videos").childrenMatchingType(.StaticText).matchingIdentifier("Videos").elementBoundByIndex(0).tap()
        // Failed to find matching element please file bug (bugreport.apple.com) and provide output from Console.app
        tablesQuery.cells.containingType(.StaticText, identifier:"Capturing Analytics data with Azure Mobile Engagement").childrenMatchingType(.StaticText).matchingIdentifier("Capturing Analytics data with Azure Mobile Engagement").elementBoundByIndex(0).tap()

    }

}