module  OrbitCoreLib
  module Preview
    def self.included(base)

      # base.instance_eval("field :is_preview,type: Boolean,:default => false")
      # base.instance_eval("scope :not_preview,where(:is_preview=>false)")
      base.class_eval ("
        def to_preview
          raise 'Developer,please override to_preview method'  
        end
      ")
    end
  end

  module ObjectDisable
     def self.included(base)

      base.instance_eval("field :disable,type: Boolean,:default => false")
      base.instance_eval("scope :all, where(:disable.in => [false, nil, ''])")
      base.instance_eval("scope :admin_manager_all,find(:all)")
      
      base.define_singleton_method :find do |*args|
        if args ==[:all]
          unscoped
        else
          res = unscoped.find(args) 
          res.count == 1 ? res[0] : res
        end
      end

      base.define_singleton_method :first do |*args|
        all.first
      end

      base.define_singleton_method :last do |*args|
        all.last
      end

    end
  end
  module  ObjectAuthable
    def self.included(base)
      base.instance_eval("has_many :object_auths,as: :obj_authable,dependent: :delete")
      
      base.define_singleton_method :authed_for_user do |user,title = nil|
        sub_role_ids_ary=user.sub_roles.collect{|t| t.id}
        if title.nil?
          auth_object_space = ObjectAuth.where(obj_authable_type: self.to_s)
        else
          auth_object_space = ObjectAuth.where(obj_authable_type: self.to_s,title: title)
        end
        query1 = auth_object_space.any_in({sub_role_ids: sub_role_ids_ary}).excludes(blocked_user_ids: user.id)
        query2 = auth_object_space.any_of({all: true},{privilege_user_ids: user.id}).excludes(blocked_user_ids: user.id)
        # query2 = auth_object_space.any_of({all: true},{privilege_user_ids: user.id},{role_ids: user.role_ids}).excludes(blocked_user_ids: user.id) #save for backup if something went wrong (0626 Matt)

        result = (query1 + query2).uniq
        result.collect{|t| t.obj_authable}.delete_if{|val| val==nil}
      end
        
    end
    
    def cur_user_is_sub_manager_of(title)
       authed_users(title).include?(User.current)
    end 

    def module_app
       ModuleApp.first(conditions: {:title => self.class::APP_NAME} )
    end

    def pp_object
      "Object Auth method 'pp_object' need to be defined for class #{self.class}"
    end
    
    def get_object_auth_by_title(title)
      oa = self.object_auths.where({title: title }).first
      if oa.nil? #&& (self.class::ObjectAuthTitlesOptions.include? title)
        oa =  self.object_auths.create title: title
      end
      oa
    end
    
    def authed_users(title=nil)
      users = []
      users = case title
      when :all
         ary = self.object_auths.collect{|t| t.auth_users}
         ary.flatten!
      when nil
        if self.object_auths.count ==1 
          self.object_auths.first.auth_users_after_block_list rescue []
          else
            logger.info "Warning calling a auth commend without specificed value( has multi-auths ), return empty"
            []
          end
      else
        get_object_auth_by_title(title).auth_users rescue []
      end
      users
    end
    
  end
  module  ObjectTokenUtility
    def self.included(base)
      base.instance_eval("field :s_token")
      base.instance_eval("after_create :generate_token")
    end
    
    def token
      return self.s_token
    end
    
    protected
     def generate_token
       self.s_token = SecureRandom.hex(16)
       self.save!
     end
  end
  
  module PermissionUtility
  private
    def check_permission(type = :use)
      permission_grant =  current_or_guest_user.admin?? true : false
      module_app = @module_app.nil?? find_module_app_by_token(params[:token]) : @module_app
      unless permission_grant
        permission_grant = case type
        when :use
          users_ary = module_app.app_auth.auth_users rescue nil
          users_ary = [] if users_ary.nil?
          (users_ary.include?(current_or_guest_user) || module_app.is_manager?(current_or_guest_user) || module_app.is_sub_manager?(current_or_guest_user))
        when :manager
          module_app.is_manager?(current_or_guest_user)
        when :sub_manager  
          module_app.is_manager?(current_or_guest_user) || module_app.is_sub_manager?(current_or_guest_user)
        end  
      end
      permission_grant
    end
    def find_module_app_by_token(token)
      ModuleApp.first(conditions: {s_token: token})
    end
  end

  module Authorization
    def self.included(base)
      base.class_eval do
        before_filter :can_use
        send :include, InstanceMethods
      end
      base.extend(ClassMethods)
    end

    module ClassMethods
      protected

      def open_for_admin(arg = nil)
        if arg
          key = arg.shift
          prepend_before_filter key[0] => key[1] {|f| f.open_for :admin}
        else
          prepend_before_filter {|f| f.open_for :admin}
        end
      end

      def open_for_manager(arg = nil)
        if arg
          key = arg.shift
          prepend_before_filter key[0] => key[1] {|f| f.open_for :manager}
        else
          prepend_before_filter {|f| f.open_for :manager}
        end
      end

      def open_for_sub_manager(arg = nil)
        if arg
          key = arg.shift
          prepend_before_filter key[0] => key[1] {|f| f.open_for :sub_manager}
        else
          prepend_before_filter {|f| f.open_for :sub_manager}
        end
      end

      def open_for_approver(arg = nil)
        if arg
          key = arg.shift
          prepend_before_filter key[0] => key[1] {|f| f.open_for :approver}
        else
          prepend_before_filter {|f| f.open_for :approver}
        end
      end

      def open_for_user(arg = nil)
        if arg
          key = arg.shift
          prepend_before_filter key[0] => key[1] {|f| f.open_for :user}
        else
          prepend_before_filter {|f| f.open_for :user}
        end
      end

      def open_for_visitor(arg = nil)
        if arg
          key = arg.shift
          prepend_before_filter key[0] => key[1] {|f| f.open_for :visitor}
        else
          prepend_before_filter {|f| f.open_for :visitor}
        end
      end

      def skip_authorization(arg = nil)
        if arg
          key = arg.shift
          prepend_before_filter key[0] => key[1] {|f| f.no_authorization}
        else
          prepend_before_filter {|f| f.no_authorization}
        end
      end

    end

    module InstanceMethods
      protected
      def can_use
        setup_vars
        unless @no_authorization
          if @user_type
            @open = false
            @visitor = false
            @user_type.each do |user_type|
              case user_type
              when :admin
                @open ||= check_admin
              when :manager
                @open ||= check_manager
              when :sub_manager
                @open ||= check_sub_manager
              when :approver
                @open ||= check_approver
              when :user
                @open ||= true
              when :visitor
                set_current_user
                @open ||= true
                @visitor ||= true
              end
            end
            check_backend_openness if @visitor
            authenticate_user! unless @visitor
            redirect_to root_url unless @open
          else
            authenticate_user!
            check_user_can_use
          end
        end
      end

      def check_admin
        current_or_guest_user.admin?
      end

      def check_manager
        check_admin || @module_app.is_manager?(current_or_guest_user)
      end

      def check_sub_manager
        check_admin || check_manager || @module_app.is_sub_manager?(current_or_guest_user)
      end

      def check_approver
        check_admin || check_manager || @module_app.can_approve?(current_or_guest_user)
      end

      def open_for(var)
        @user_type ||= []
        @user_type << var
      end

      def no_authorization
        @no_authorization = true
      end

      def check_user_can_use
        unless current_or_guest_user.admin? || (@module_app.is_manager?(current_or_guest_user) if @module_app.present?) || (@module_app.is_sub_manager?(current_or_guest_user) if @module_app.present?) || (@module_app.can_approve?(current_or_guest_user) if @module_app.present?)
          redirect_to admin_dashboards_url
        end
      end

      def setup_vars
        @app_title ||= controller_path.split('/')[1].singularize rescue nil
        @module_app ||= ModuleApp.first(conditions: {:key => @app_title} ) rescue nil
      end
    end
  end

end
