module ProMotion
  module ScreenModule
    include ProMotion::Support
    include ProMotion::ScreenNavigation
    include ProMotion::Styling
    include ProMotion::NavBarModule
    include ProMotion::Tabs
    include ProMotion::SplitScreen if UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad || (UIDevice.currentDevice.systemVersion.to_i >= 8 )

    attr_reader :parent_screen
    attr_accessor :first_screen, :modal, :split_screen

    def screen_init(args = {})
      @screen_options = args
      check_ancestry
      resolve_title
      apply_properties(args)
      add_nav_bar(args)
      add_nav_bar_buttons
      tab_bar_setup
      try :on_init
      try :screen_setup
      mp "In #{self.class.to_s}, #on_create has been deprecated and removed. Use #screen_init instead.", force_color: :yellow if respond_to?(:on_create)
    end

    def modal?
      self.modal == true
    end

    def parent_screen=(parent)
      @parent_screen = WeakRef.new(parent)
    end

    def first_screen?
      self.first_screen == true
    end

    def view_did_load
      self.send(:on_load) if self.respond_to?(:on_load)
    end

    def view_will_appear(animated)
      super
      resolve_status_bar
      self.will_appear

      self.will_present if isMovingToParentViewController
    end
    def will_appear; end
    def will_present; end

    def view_did_appear(animated)
      self.on_appear

      self.on_present if isMovingToParentViewController
    end
    def on_appear; end
    def on_present; end

    def view_will_disappear(animated)
      self.will_disappear

      self.will_dismiss if isMovingFromParentViewController
    end
    def will_disappear; end
    def will_dismiss; end

    def view_did_disappear(animated)
      self.on_disappear

      self.on_dismiss if isMovingFromParentViewController
    end
    def on_disappear; end
    def on_dismiss; end

    def did_receive_memory_warning
      self.on_memory_warning
    end
    def on_memory_warning
      mp "Received memory warning in #{self.inspect}. You should implement on_memory_warning in your secreen.", force_color: :red
    end

    def on_live_reload
      self.view.subviews.each(&:removeFromSuperview)
      on_load
    end

    def should_rotate(orientation)
      case orientation
      when UIInterfaceOrientationPortrait
        return supported_orientation?("UIInterfaceOrientationPortrait")
      when UIInterfaceOrientationLandscapeLeft
        return supported_orientation?("UIInterfaceOrientationLandscapeLeft")
      when UIInterfaceOrientationLandscapeRight
        return supported_orientation?("UIInterfaceOrientationLandscapeRight")
      when UIInterfaceOrientationPortraitUpsideDown
        return supported_orientation?("UIInterfaceOrientationPortraitUpsideDown")
      else
        false
      end
    end

    def will_rotate(orientation, duration)
    end

    def should_autorotate
      true
    end

    def on_rotate
    end

    def supported_orientations
      orientations = 0
      NSBundle.mainBundle.infoDictionary["UISupportedInterfaceOrientations"].each do |ori|
        case ori
        when "UIInterfaceOrientationPortrait"
          orientations |= UIInterfaceOrientationMaskPortrait
        when "UIInterfaceOrientationLandscapeLeft"
          orientations |= UIInterfaceOrientationMaskLandscapeLeft
        when "UIInterfaceOrientationLandscapeRight"
          orientations |= UIInterfaceOrientationMaskLandscapeRight
        when "UIInterfaceOrientationPortraitUpsideDown"
          orientations |= UIInterfaceOrientationMaskPortraitUpsideDown
        end
      end
      orientations
    end

    def supported_orientation?(orientation)
      NSBundle.mainBundle.infoDictionary["UISupportedInterfaceOrientations"].include?(orientation)
    end

    def supported_device_families
      NSBundle.mainBundle.infoDictionary["UIDeviceFamily"].map do |m|
        {
          "1" => :iphone,
          "2" => :ipad
        }[m] || :unknown_device
      end
    end

    def supported_device_family?(family)
      supported_device_families.include?(family)
    end

    def bounds
      return self.view_or_self.bounds
    end

    def frame
      return self.view_or_self.frame
    end

    def add_child_screen(screen)
      screen = screen.new if screen.respond_to?(:new)
      addChildViewController(screen)
      screen.parent_screen = self
      screen.didMoveToParentViewController(self) # Required
      screen
    end

    def remove_child_screen(screen)
      screen.parent_screen = nil
      screen.willMoveToParentViewController(nil) # Required
      screen.removeFromParentViewController
      screen
    end

  private

    def resolve_title
      case self.class.title_type
      when :text then self.title = self.class.title
      when :view then self.navigationItem.titleView = self.class.title
      when :image then self.navigationItem.titleView = UIImageView.alloc.initWithImage(self.class.title)
      else
        mp("title expects string, UIView, or UIImage, but #{self.class.title.class.to_s} given.", force_color: :yellow)
      end
    end

    def resolve_status_bar
      case self.class.status_bar_type
      when :none
        status_bar_hidden true
      when :light
        status_bar_hidden false
        status_bar_style UIStatusBarStyleLightContent
      when :dark
        status_bar_hidden false
        status_bar_style UIStatusBarStyleDefault
      else
        return status_bar_hidden true if UIApplication.sharedApplication.isStatusBarHidden
        status_bar_hidden false
        global_style = NSBundle.mainBundle.objectForInfoDictionaryKey("UIStatusBarStyle")
        status_bar_style global_style ? Object.const_get(global_style) : UIStatusBarStyleDefault
      end
    end

    def add_nav_bar_buttons
      self.class.get_nav_bar_button.each do |button_args|
        set_nav_bar_button(button_args[:side], button_args)
      end
    end

    def status_bar_hidden(hidden)
      UIApplication.sharedApplication.setStatusBarHidden(hidden, withAnimation:self.class.status_bar_animation)
    end

    def status_bar_style(style)
      UIApplication.sharedApplication.setStatusBarStyle(style)
    end

    def apply_properties(args)
      reserved_args = [ :nav_bar, :hide_nav_bar, :hide_tab_bar, :animated, :close_all, :in_tab, :in_detail, :in_master, :to_screen, :toolbar ]
      set_attributes self, args.dup.delete_if { |k,v| reserved_args.include?(k) }
    end

    def tab_bar_setup
      self.tab_bar_item = self.class.send(:get_tab_bar_item)
      self.refresh_tab_bar_item if self.tab_bar_item
    end

    def check_ancestry
      unless self.is_a?(UIViewController)
        raise StandardError.new("ERROR: Screens must extend UIViewController or a subclass of UIViewController.")
      end
    end

    # Class methods
    module ClassMethods
      def title(t=nil)
        if t && t.is_a?(String) == false
          mp "You're trying to set the title of #{self.to_s} to an instance of #{t.class.to_s}. In ProMotion 2+, you must use `title_image` or `title_view` instead.", force_color: :yellow
          return raise StandardError
        end
        @title = t if t
        @title_type = :text if t
        @title
      end

      def title_type
        @title_type || :text
      end

      def title_image(t)
        @title = t.is_a?(UIImage) ? t : UIImage.imageNamed(t)
        @title_type = :image
      end

      def title_view(t)
        @title = t
        @title_type = :view
      end

      def status_bar(style=nil, args={})
        if NSBundle.mainBundle.objectForInfoDictionaryKey('UIViewControllerBasedStatusBarAppearance').nil?
          mp "status_bar will have no effect unless you set 'UIViewControllerBasedStatusBarAppearance' to false in your info.plist", force_color: :yellow
        end
        @status_bar_style = style
        @status_bar_animation = args[:animation] if args[:animation]
      end

      def status_bar_type
        @status_bar_style || :default
      end

      def status_bar_animation
        @status_bar_animation || UIStatusBarAnimationSlide
      end

      def nav_bar(enabled, args={})
        @nav_bar_args = ({ nav_bar: enabled }).merge(args)
      end

      def get_nav_bar
        @nav_bar_args ||= { nav_bar: false }
      end

      def nav_bar_button(side, args={})
        button_args = args.merge(:side => side)

        @nav_bar_button_args ||= []
        @nav_bar_button_args << button_args
      end

      def get_nav_bar_button
        @nav_bar_button_args ||= []
      end
    end

    def self.included(base)
      base.extend(ClassMethods)
      base.extend(TabClassMethods) # TODO: Is there a better way?
    end
  end
end