package WebGUI::Account::Profile;

use strict;

use WebGUI::Exception;
use WebGUI::International;
use WebGUI::Pluggable;
use WebGUI::ProfileCategory;
use WebGUI::ProfileField;
use WebGUI::Utility;
use base qw/WebGUI::Account/;

=head1 NAME

Package WebGUI::Account::Profile

=head1 DESCRIPTION

This is the class which is used to display a users's profile information

=head1 SYNOPSIS

 use WebGUI::Account::Profile;

=head1 METHODS

These subroutines are available from this package:

=cut

#-------------------------------------------------------------------

=head2 appendCategoryVars ( var, category [,fields, errors] )

Appends cateogry variables to the hash ref passed in

=head3 var

The hash reference to append template variables to

=head3 category

WebGUI::ProfileCategory object to append variables for

=head3 fields

Optional array ref of fields in this category

=head3 errors

Optional array ref of errors to attach to the category loop

=cut

sub appendCategoryVars {
    my $self     = shift;
    my $var      = shift || {};
    my $category = shift;
    my $fields   = shift;
    my $errors   = shift;
    my $selected = $self->store->{selected} || $self->session->form->get("selected");
    
    my $categoryId         = $category->getId;
    my $categoryLabel      = $category->getLabel;
    my $shortCategoryLabel = $category->getShortLabel;
    my $isActive           = $categoryId eq $selected;

    my $index  = scalar(@{$var->{'profile_category_loop'}}) + 1;

    push(@{ $var->{'profile_category_loop'} }, {
        'profile_category_id'              => $categoryId,
        'profile_category_isActive'        => $isActive,
        'profile_category_is_'.$categoryId => "true",  #Test so users can tell what category they are at in the loop
        'profile_category_label'           => $categoryLabel,
        'profile_category_shortLabel'      => $shortCategoryLabel,
        'profile_category_index'           => $index,
        'profile_fields_loop'              => $fields,
        'profile_errors'                   => $errors,
    });

    $var->{'profile_category_'.$categoryId."_isActive"  } = $isActive; 
    $var->{'profile_category_'.$categoryId."_label"     } = $categoryLabel;
    $var->{'profile_category_'.$categoryId."_shortLabel"} = $shortCategoryLabel;
    $var->{'profile_category_'.$categoryId."_index"     } = $index;
    $var->{'profile_category_'.$categoryId."_fields"    } = $fields;

    $var->{'can_edit_profile'  } = $self->uid eq $self->session->user->userId;

    #Update the isActive flag to determine the default active tab
    $self->store->{hasActiveTab} = ($self->store->{hasActiveTab} || $isActive);

    #return $index;
}

#-------------------------------------------------------------------

=head2 appendCommonVars ( var )

Appends common template variables that all profile templates use

=head3 var

The hash reference to append template variables to

=cut

sub appendCommonVars {
    my $self          = shift;
    my $var           = shift;
    my $session       = $self->session;
    my $user          = $self->getUser;
    my $pageUrl       = $session->url->page;

    $self->SUPER::appendCommonVars($var);

    $var->{'edit_profile_url'     } = $self->getUrl("module=profile;do=edit");
    $var->{'invitations_enabled'  } = $user->profileField('ableToBeFriend');
    $var->{'profile_category_loop'} = [];

    #Append the categories
    my $categories = WebGUI::ProfileCategory->getCategories($session, { editable=>1 } );
    map { $self->appendCategoryVars($var,$_) } @ { $categories };
    unless ($self->store->{hasActiveTab}) {
        $var->{'profile_category_loop'}->[0]->{'profile_category_isActive'} = 1;
    }    

    #Append the form submit if it's in edit mode
    if($self->method eq "edit" || $self->uid eq "") {
        $var->{'is_edit'      } = "true";
        $var->{'form_header'  } = WebGUI::Form::formHeader($session,{
            action => $self->getUrl("module=profile;do=editSave")
        });
        $var->{'form_footer'  } = WebGUI::Form::formFooter($session);
    }
}

#-------------------------------------------------------------------

=head2 editSettingsForm ( )

Creates form elements for user settings page custom to this account module

=cut

sub editSettingsForm {
    my $self    = shift;
    my $session = $self->session;
    my $setting = $session->setting;
    my $i18n    = WebGUI::International->new($session,'Account_Profile');
    my $f       = WebGUI::HTMLForm->new($session);

	$f->template(
		name      => "profileStyleTemplateId",
		value     => $self->getStyleTemplateId,
		namespace => "style",
		label     => $i18n->get("profile style template label"),
        hoverHelp => $i18n->get("profile style template hoverHelp")
	);
	$f->template(
		name      => "profileLayoutTemplateId",
		value     => $self->getLayoutTemplateId,
		namespace => "Account/Layout",
		label     => $i18n->get("profile layout template label"),
        hoverHelp => $i18n->get("profile layout template hoverHelp")
	);
	$f->template(
        name      => "profileEditTemplateId",
        value     => $self->getEditTemplateId,
        namespace => "Account/Profile/Edit",
        label     => $i18n->get("profile edit template label"),
        hoverHelp => $i18n->get("profile edit template hoverHelp")
	);
    $f->template(
        name      => "profileViewTemplateId",
        value     => $self->getViewTemplateId,
        namespace => "Account/Profile/View",
        label     => $i18n->get("profile view template label"),
        hoverHelp => $i18n->get("profile view template hoverHelp")
	);
    $f->template(
        name      => "profileErrorTemplateId",
        value     => $self->getErrorTemplateId,
        namespace => "Account/Profile/Error",
        label     => $i18n->get("profile error template label"),
        hoverHelp => $i18n->get("profile error template hoverHelp")
	);


    return $f->printRowsOnly;
}


#-------------------------------------------------------------------

=head2 editSettingsFormSave ( )

Creates form elements for user settings page custom to this account module

=cut

sub editSettingsFormSave {
    my $self    = shift;
    my $session = $self->session;
    my $setting = $session->setting;
    my $form    = $session->form;

    $setting->set("profileStyleTemplateId", $form->process("profileStyleTemplateId","template"));
    $setting->set("profileLayoutTemplateId", $form->process("profileLayoutTemplateId","template"));
    $setting->set("profileDisplayLayoutTemplateId", $form->process("profileDisplayLayoutTemplateId","template"));
    $setting->set("profileEditTemplateId", $form->process("profileEditTemplateId","template"));
    $setting->set("profileViewTemplateId", $form->process("profileViewTemplateId","template"));
    $setting->set("profileErrorTemplateId",$form->process("profileErrorTemplateId","template"));

}

#-------------------------------------------------------------------

=head2 getExtrasStyle ( field, fieldErrors, fieldValue )

This method returns the proper field to display for required fields.

=head3 field

field to check

=head3 fieldErrors

errors returned as a result of validation (see $self->validateProfileFields)

=head3 fieldValue

Value of the field to use when returning the style

=cut

sub getExtrasStyle {
    my $self        = shift;
    my $field       = shift;
    my $fieldErrors = shift;
    my $fieldValue  = shift;

    my $requiredStyleOff = q{class="profilefield_required_off"}; 
    my $requiredStyle    = q{class="profilefield_required"};
    my $errorStyle       = q{class="profilefield_error"};     #Required Field Not Filled In and Error Returend

    return $errorStyle if(WebGUI::Utility::isIn($field->getId,@{$fieldErrors}));
    return "" unless ($field->isRequired);
    return $requiredStyle unless($self->session->user->profileField($field->getId) || $fieldValue);
    return $requiredStyleOff;
}

#-------------------------------------------------------------------

=head2 getEditTemplateId ( )

This method returns the template ID for the edit profile page.

=cut

sub getEditTemplateId {
    my $self = shift;
    return $self->session->setting->get("profileEditTemplateId") || "75CmQgpcCSkdsL-oawdn3Q";
}

#-------------------------------------------------------------------

=head2 getErrorTemplateId ( )

This method returns the template ID used to display the error page.

=cut

sub getErrorTemplateId {
    my $self = shift;
    return $self->session->setting->get("profileErrorTemplateId") || "MBmWlA_YEA2I6D29OMGtRg";
}


#-------------------------------------------------------------------

=head2 getLayoutTemplateId ( )

This method returns the template ID for the account layout.

=cut

sub getLayoutTemplateId {
    my $self    = shift;
    return $self->session->setting->get("profileLayoutTemplateId") || "FJbUTvZ2nUTn65LpW6gjsA";
}

#-------------------------------------------------------------------

=head2 getStyleTemplateId ( )

This method returns the template ID for the main style.

=cut

sub getStyleTemplateId {
    my $self = shift;
    return $self->session->setting->get("profileStyleTemplateId") || $self->SUPER::getStyleTemplateId;
}

#-------------------------------------------------------------------

=head2 getViewTemplateId ( )

This method returns the template ID for the view profile page.

=cut

sub getViewTemplateId {
    my $self = shift;
    return $self->session->setting->get("profileViewTemplateId") || "2CS-BErrjMmESOtGT90qOg";
}

#-------------------------------------------------------------------

=head2 www_edit ( )

The edit page for the user's profile.

=cut

sub www_edit {
    my $self        = shift;
    my $errors      = shift || {};
    my $session     = $self->session;
    my $user        = $session->user;
    my $var         = {};

    #Handle errors
    my @errorFields          = ();
    $var->{'profile_errors'} = [];

    if( scalar(keys %{$errors}) ) {
        #Warnings and errors are the same here - set the fields so we can tell which fields errored
        @errorFields = (@{$errors->{errorFields}},@{$errors->{warningFields}});
        #Build the error message loop
        map {
            push( @{$var->{'profile_errors'}},{ error_message => $_ })
        }  @{$errors->{errors}};
    }

    my $count = 0;

    #Set the active flag to the default.  We'll know more later 
    $self->store->{hasActiveTab} = 0;    
    
    #Initialize the category template loop which gets filled inside the loop
    $var->{'profile_category_loop'}  = [];

    #Cache the privacy settings
    my $privacySettingsHash = WebGUI::ProfileField->getPrivacyOptions($session);
    #Get the editable categories
    my $categories = WebGUI::ProfileCategory->getCategories($session, { editable => 1 } );
	foreach my $category (@{ $categories } ) {
        my @fields = ();
        foreach my $field (@{ $category->getFields( { editable => 1 } ) }) {
            my $fieldId             = $field->getId;
            my $fieldLabel          = $field->getLabel;
            my $fieldForm           = $field->formField({ extras=>$self->getExtrasStyle($field,\@errorFields,$user->profileField($fieldId)) });
            my $fieldRequired       = $field->isRequired;
            my $fieldExtras         = $field->getExtras;
            my $fieldViewable       = $field->isViewable;
            my $rawPrivacySetting   = $user->getProfileFieldPrivacySetting($fieldId);
            my $fieldPrivacySetting = $privacySettingsHash->{$rawPrivacySetting};
            
            my $fieldPrivacy = WebGUI::Form::selectBox($session,{
                name    => "privacy_$fieldId",
                options => $privacySettingsHash,
                value   => $rawPrivacySetting,
                extras  => (!$fieldViewable) ? " disabled" : ""
            });

            #Create a seperate template var for each field
            my $fieldBase = 'profile_field_'.$fieldId;
            $var->{$fieldBase.'_form'                           } = $fieldForm;
            $var->{$fieldBase.'_label'                          } = $fieldLabel;
            $var->{$fieldBase.'_required'                       } = $fieldRequired;
            $var->{$fieldBase.'_extras'                         } = $fieldExtras;
            $var->{$fieldBase.'_privacy_form'                   } = $fieldPrivacy;
            $var->{$fieldBase.'_field_viewable'                 } = $fieldViewable;
            $var->{$fieldBase.'_privacy_setting'                } = $fieldPrivacySetting;
            $var->{$fieldBase.'_privacy_is_'.$rawPrivacySetting } = $rawPrivacySetting;
            
            push(@fields, {
                'profile_field_id'                             => $fieldId,
				'profile_field_form'                           => $fieldForm,
				'profile_field_label'                          => $fieldLabel,
				'profile_field_required'                       => $fieldRequired,
                'profile_field_extras'                         => $fieldExtras,
                'profile_field_viewable'                       => $fieldViewable,
                'profile_field_privacy_form'                   => $fieldPrivacy,
                'profile_field_privacy_setting'                => $fieldPrivacySetting,
                'profile_field_privacy_is_'.$rawPrivacySetting => $rawPrivacySetting,
			});
        }

        #Append the category variables
        $self->appendCategoryVars($var,$category,\@fields,$var->{'profile_errors'});
    }
 
    #If not category is selected, set the first category as the active one
    unless ($self->store->{hasActiveTab}) {
        $var->{'profile_category_loop'}->[0]->{'profile_category_isActive'} = 1;
    }

    #Call the superclass common vars method cause we don't need to build the categories again
    $self->SUPER::appendCommonVars($var);

    return $self->processTemplate($var,$self->getEditTemplateId);
}


#-------------------------------------------------------------------

=head2 www_editSave ( )

The page which saves the user's profile and returns them to their profile view.

=cut

sub www_editSave {
    my $self       = shift;
    my $session    = $self->session;

    my $fields     = WebGUI::ProfileField->getEditableFields($session);
    my $retHash    = $session->user->validateProfileDataFromForm($fields);
	push (@{$retHash->{errors}},@{$retHash->{warnings}});

    unless(scalar(@{$retHash->{errors}})) {
        my $profile  = $retHash->{profile};

        my $privacy  = {};
        $session->user->update($profile);

        my $address          = {};
        my $address_mappings = WebGUI::Shop::AddressBook->getProfileAddressMappings;
        foreach my $fieldName (keys %{$profile}) {
            #set the shop address fields
            my $address_key          = $address_mappings->{$fieldName};
            $address->{$address_key} = $profile->{ $fieldName } if ($address_key);

            #set the privacy settings
            my $privacySetting     = $session->form->get("privacy_".$fieldName);
            next unless $privacySetting;
            $privacy->{$fieldName} = $privacySetting;
        }

        $session->user->setProfileFieldPrivacySetting($privacy);

        #Update or create and update the shop address
        if ( keys %$address ) {
            $address->{'isProfile'        } = 1;

            #Get the address book for the user (one is created if it does not exist)
            my $addressBook     = WebGUI::Shop::AddressBook->newByUserId($session,$self->uid);
            my $profileAddress = eval { $addressBook->getProfileAddress() };

            my $e;
            if($e = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound')) {
                #Get home address only mappings to avoid creating addresses with just firstName, lastName, email
                my %home_address_map = %{$address_mappings};
                foreach my $exclude ( qw{ firstName lastName email } ) {
                    delete $home_address_map{$exclude};
                }
                #Add the profile address for the user if there are homeAddress fields
                if( grep { $address->{$_} } values %home_address_map ) {
                    $address->{label} = "Profile Address";
                    my $new_address = $addressBook->addAddress($address);
                    #Set this as the default address if one doesn't already exist
                    my $defaultAddress = eval{ $addressBook->getDefaultAddress };
                    if(WebGUI::Error->caught('WebGUI::Error::ObjectNotFound')) {
                        $addressBook->update( {
                            defaultAddressId => $new_address->getId
                        } );
                    }
                }
            }
            elsif ($e = WebGUI::Error->caught) {
                #Bad stuff happened - log an error but don't fail since this isn't a vital function
                $session->log->error(
                    q{Could not update Shop Profile Address for user }
                        .$self->username.q{ : }.$e->error
                );
            }
            else {
                #Update the profile address for the user
                $profileAddress->update($address);
            }
        }
    }

    #Store the category the error occurred in the object for reference
    $self->store->{selected} = $retHash->{errorCategory};

    return $self->www_edit($retHash);
}

#-------------------------------------------------------------------

=head2 www_view ( )

The display page of the .

=cut

sub www_view {
    my $self     = shift;
    my $session  = $self->session;
    my $var      = {};
    my $uid      = $self->uid;
    my $selected = $session->form->get("selected"); #Allow users to template tabs or other category dividers

    my $active      = 0; #Whether or not a category is selected
    my $counter     = 1; #Count the number of categories being displayed

    #Ensure uid is passed in if they want to view a profile.  This controls the tab state.
    return $self->www_edit unless ($uid);

    my $user     = WebGUI::User->new($session,$uid);

    $self->appendCommonVars($var);

    my $privacySetting = $user->profileField('publicProfile') || 'none';
    $var->{"profile_privacy_$privacySetting"} = "true";

    $var->{'acceptsPrivateMessages'} 
        = $user->acceptsPrivateMessages($session->user->userId);

    $var->{'acceptsFriendsRequests'} 
        = $user->acceptsFriendsRequests($session->user);

    #Check user privileges
    unless ($user->profileIsViewable($session->user)) {
        my $i18n = WebGUI::International->new($session,'Account_Profile');
        $var->{'notViewable'}   = 1;
        $var->{'error_message'} = $i18n->get("profile not public error");
        return $self->processTemplate($var,$self->getViewTemplateId);
    }

    #Cache the privacy settings
    my $privacySettingsHash = WebGUI::ProfileField->getPrivacyOptions($session);
    $var->{'profile_category_loop' } = [];
	foreach my $category (@{WebGUI::ProfileCategory->getCategories($session,{ visible => 1})}) {
        my @fields = ();
        foreach my $field (@{$category->getFields({ visible => 1 })}) {
            next unless ($user->canViewField($field->getId,$session->user));
            my $rawPrivacySetting  = $user->getProfileFieldPrivacySetting($field->getId);
            my $privacySetting     = $privacySettingsHash->{$rawPrivacySetting};
            my $fieldId            = $field->getId;
            my $fieldLabel         = $field->getLabel;
            my $fieldValue         = $field->formField(undef,2,$user);
            my $fieldRaw           = $user->profileField($fieldId);;
            #Create a seperate template var for each field
            my $fieldBase = 'profile_field_'.$fieldId;
            $var->{$fieldBase.'_label'                          } = $fieldLabel;
            $var->{$fieldBase.'_value'                          } = $fieldValue;
            $var->{$fieldBase.'_raw'                            } = $fieldRaw;
            $var->{$fieldBase.'_privacySetting'                 } = $privacySetting;
            $var->{$fieldBase.'_privacy_is_'.$rawPrivacySetting } = "true";
            push(@fields, {
                'profile_field_id'                             => $fieldId,
                'profile_field_is_'.$fieldId                   => "true",
				'profile_field_label'                          => $fieldLabel,
                'profile_field_value'                          => $fieldValue,
                'profile_field_raw'                            => $fieldRaw,
                'profile_field_privacySetting'                 => $privacySetting,
                'profile_field_privacy_is_'.$rawPrivacySetting => "true",
			});
        }
        #Don't bother displaying the category if there's nothing in it.
        next unless (scalar(@fields));
        #Append the category variables
        $self->appendCategoryVars($var,$category,\@fields);
    }

    #If not category is selected, set the first category as the active one
    unless ($self->store->{hasActiveTab}) {
        $var->{'profile_category_loop'}->[0]->{'profile_category_isActive'} = 1;
    }

    return $self->processTemplate($var,$self->getViewTemplateId);
}

1;
