###################################################################
# Copyright (C) 2006 RoyaltyShare, Inc.  All Rights Reserved
# $Id$
###################################################################

package Common::Preference;

#
# Common::Preference
#
# This class provides accessor methods to user preferences as well
# as the base class the preference object.  Preference results
# need to overload the set and get methods. A preference is a key
# value pair which is either stored in a cookie or in the database.
#
# There are several types of preferences we can store, session
# cookie, persistent cookie, client specific, and common.  However
# all preferences are per user.
#
# When calling the Get static method, we search for the preferences
# hierarchically.  The first key that matches the passed in
# preference name will be returned.  The search order is:
#
# Session Cookie - An http cookie that will only last for the
#                  current web session.
#
# Persistent Cookie - An http cookie that will span sessions and
#                     won't expire for at lease 1 year.
#
# Client DB - Stored in the client database meaning the preference
#             is only readable on a single client's site.
#
# Common DB - Stored in the common database and is avaliable (and
#             shared ) per user over all clients.
#
# Usage:
#
# Static Methods:
#
#   StoreCookies();
#
#   my $pref = Get( 'pref_name' );
#
#   $pref = SetSessionCookie( 'pref_name' => 'value' );
#   $pref = SetPersistentCookie( 'pref_name' => 'value' );
#   $pref = SetClientDB( 'pref_name' => 'value' );
#   $pref = SetCommonDB( 'pref_name' => 'value' );
#
# Member Methods:
#
#   print "Cookie: " . $pref->name . " = " . $pref->value if( $pref->found() );
#

use strict;
use warnings;
use Carp;
use Date::Format;

use lib '/app/tools/common/lib';
use Common::Assert;

use Common::Preference::Session;
use Common::Preference::Cookie;
use Common::Preference::Client;
use Common::Preference::Common;

use overload ( '""' => 'stringify' );

sub stringify {
    my $self = shift;
    return $self->value();
}

my @SOURCE_ORDER = qw(_getFromSessionCookie _getFromPersistentCookie _getFromClientDB _getFromCommonDB);

###
#  Static Methods
###
sub StoreCookies {
    my $session_cookie    = Common::RSApp::GetSessionPreferenceCookie();
    my $persistent_cookie = Common::RSApp::GetPersistentPreferenceCookie();

    $session_cookie->store()    if ($session_cookie);
    $persistent_cookie->store() if ($persistent_cookie);
}

sub GetValue {
    my $pref_name = shift;
    my $pref      = Get($pref_name);

    return defined $pref ? $pref->value : undef;
}

sub Get {
    my $pref_name = shift;
    assert($pref_name);

    foreach my $source (@SOURCE_ORDER) {
        my $pref = __PACKAGE__->$source($pref_name);
        return $pref
          if ( defined($pref) && $pref->found );
    }

    return undef;
}

sub SetSessionCookie {
    my ( $key, $value ) = @_;
    assert($key);

    return new Common::Preference::Session( name => $key, value => $value );
}

sub SetPersistentCookie {
    my ( $key, $value ) = @_;
    assert($key);

    return new Common::Preference::Cookie( name => $key, value => $value );
}

sub SetClientDB {
    my ( $key, $value ) = @_;
    assert($key);

    return new Common::Preference::Client( name => $key, value => $value );
}

sub SetCommonDB {
    my ( $key, $value ) = @_;
    assert($key);

    return new Common::Preference::Common( name => $key, value => $value );
}

###
#  Class Methods
###
sub new {
    my ( $class, %args ) = @_;
    my $self = bless {}, $class;

    return $self->_init(%args);
}

sub _init {
    my ( $self, %args ) = @_;

    assert( $args{name}, "preference name required" );

    $self->{_name} = $args{name};

    $self->get();
    $self->set( $args{value} ) if ( defined( $args{value} ) );

    return $self;
}

sub found { shift->{_found}; }
sub value { shift->{_value}; }
sub name  { shift->{_name}; }

###
#  Helper functions
###
sub _getFromSessionCookie {
    my $class     = shift;
    my $pref_name = shift;
    assert($pref_name);

    my $pref = new Common::Preference::Session( name => $pref_name );
    return $pref->found() ? $pref : undef;
}

sub _getFromPersistentCookie {
    my $class     = shift;
    my $pref_name = shift;
    assert($pref_name);

    #Common::Log::Debug( "Get Persistant cookie: $pref_name" );
    my $pref = new Common::Preference::Cookie( name => $pref_name );
    return $pref->found() ? $pref : undef;
}

sub _getFromClientDB {
    my $class     = shift;
    my $pref_name = shift;
    assert($pref_name);

    my $pref = new Common::Preference::Client( name => $pref_name );
    return $pref->found() ? $pref : undef;
}

sub _getFromCommonDB {
    my $class     = shift;
    my $pref_name = shift;
    assert($pref_name);

    my $pref = new Common::Preference::Common( name => $pref_name );
    return $pref->found() ? $pref : undef;
}

1;
