module AuthenticatedSystem
  protected
  def logged_in?
    current_user && current_user.registered? && !current_user.guest?
  end

  # accesses the current user from the session.
  # overwrite this to set how the current user is retrieved from the session.
  # To store just the whole user model in the session:
  #
  #   def current_user
  #     session[:user]
  #   end
  # 
  def current_user
    # @current_user ||= (session[:user] && User.find_by_id(session[:user])) || login_by_token || create_a_guest_account
    if(session[:user])
      @current_user ||= User.find_by_id(session[:user])
    else
      @current_user ||= login_by_token || guest_account
    end
  end

  # store the given user in the session.  overwrite this to set how
  # users are stored in the session.  To store the whole user model, do:
  #
  #   def current_user=(new_user)
  #     session[:user] = new_user
  #   end
  # 
  def current_user=(new_user)
    session[:user] = new_user && new_user.id
    @current_user = new_user
  end

  # overwrite this if you want to restrict access to only a few actions
  # or if you want to check if the user has the correct rights  
  # example:
  #
  #  # only allow nonbobs
  #  def authorize?(user)
  #    user.login != "bob"
  #  end
  def authorized?(user)
     true
  end
  
  # Load the previous Guest account, if a guest_id cookie is found, otherwise
  # create a new guest account for this session.
  #
  # Sets a guest_id cookie.
  def guest_account
    return unless ApplicationPolicy::guests_allowed?
    guest_account      = load_previous_guest_account || create_a_guest_account
    cookies[:guest_id] = { :value => guest_account.id.to_s, :expires => Time.now.utc+1.year } 
    self.current_user  = guest_account
  end

  def create_a_guest_account
    Guest.create
  end
  
  def load_previous_guest_account
    Guest.find(cookies[:guest_id]) if cookies[:guest_id] rescue nil
  end
  
  # overwrite this method if you only want to protect certain actions of the controller
  # example:
  # 
  #  # don't protect the login and the about method
  #  def protect?(action)
  #    if ['action', 'about'].include?(action)
  #       return false
  #    else
  #       return true
  #    end
  #  end
  def protect?(action)
    true
  end

  # To require logins, use:
  #
  #   before_filter :login_required                            # restrict all actions
  #   before_filter :login_required, :only => [:edit, :update] # only restrict these actions
  # 
  # To skip this in a subclassed controller:
  #
  #   skip_before_filter :login_required
  # 
  def login_required   
    # skip login check if action is not protected
    return true unless protect?(action_name)

    # return true if user is logged in (Guests don't count)
    return true if self.logged_in?
    
    return true if ApplicationPolicy::guests_allowed?
    
    # store current location so that we can 
    # come back after the user logged in
    store_location

    # call overwriteable reaction to unauthorized access
    access_denied and return false
  end
  
  def login_by_token
    if cookies[:login_token] && session[:user].nil? # dont call logged_in? due to logged_in? -> current_user -> login_token loop
        id, login_key = cookies[:login_token].split(";")
        self.current_user = User.find(:first, :conditions => ['id = ? AND login_key = ? and suspended = ?', id, login_key, 0]) 
    end
  end

  # overwrite if you want to have special behavior in case the user is not authorized
  # to access the current operation. 
  # the default action is to redirect to the login screen
  # example use :
  # a popup window might just close itself for instance
  def access_denied
    redirect_to :controller=>"/account", :action =>"login"
  end  

  # store current uri in  the session.
  # we can return to this location by calling return_location
  def store_location
    session[:return_to] = request.request_uri
  end

  # move to the last store_location call or to the passed default one
  def redirect_back_or_default(default)
    session[:return_to] ? redirect_to_url(session[:return_to]) : redirect_to(default)
    session[:return_to] = nil
  end

  # adds ActionView helper methods
  def self.included(base)
    base.send :helper_method, :current_user, :logged_in?
  end
end
