# Copyright (C) 2005 FishGrove Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# $Id: FriendManager.pm,v 1.20 2006/03/07 14:39:11 slash5234 Exp $

package Affelio::SNS::FriendManager;
{
    use strict;

    use lib("../../../extlib");    
    use DBI;
    use lib("../../");
    use Affelio;
    use Affelio::misc::CGIError;
    use Affelio::misc::Debug qw(debug_print);
    use Affelio::misc::Time;
    use Affelio::misc::DBroutines qw(db_value_replace);
    use Affelio::exception::DBException;

    ########################################################################
    #Constructor
    ########################################################################
    sub new{
	my $class = shift;
	my $af = shift;

	debug_print("FriendManager::new: start.");
	
	my $self = {af => $af
		    };
	
	bless $self, $class;
	
	debug_print("FriendManager::new: end.");
	return $self;
    }
    
    ########################################################################
    #get_F1_count
    ########################################################################
    sub get_F1_count{
	my $self = shift;
	my $af = $self->{af};

	##############################
	#retrieve all friend records from DB
	my $query = "SELECT count(*) FROM $af->{site__dbtbl_prefix}_CORE_friends"; #
	my $sth;
	eval{
	    $sth = $af->getDB->prepare($query);
	    $sth->execute();
	};
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}

	my @row = $sth->fetchrow_array;
	return($row[0]);
    }

    ########################################################################
    #get_F2_count
    ########################################################################
    sub get_F2_count{
	my $self = shift;
	my $af = $self->{af};

	##############################
	#retrieve all friend records from DB
	my $query = "SELECT count(*) FROM $af->{site__dbtbl_prefix}_CORE_friendsfriends"; #
	my $sth;
	eval{
	    $sth = $af->getDB->prepare($query);
	    $sth->execute();
	};
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}

	my @row = $sth->fetchrow_array;
	return($row[0]);
    }


    ########################################################################
    #add_friend
    ########################################################################
    sub add_friend{                  #returns uid (int)
	my $self = shift;
	my $af_id = shift;           #arg(1) af_id     (string)
	my $nickname = shift;        #arg(2) nickname  (string)
	my $timestamp = shift;       #arg(3) timestamp (int)
	my $password = shift;        #arg(4) password  (string)

	Affelio::misc::Debug::debug_print("FM::add_friend: ($af_id $nickname $timestamp $password)");
	
	my $af = $self->{af};
	my $sth;
	my $query;
	my @row;
	my $maxid;
	my $newid;
	my $old_uid_in_f2tbl="";
	my $old_f1list_in_f2tbl=",";

	##############################
	#Is ($af_id) already in my F1 table?
	#If so, we DO NOT ignore him. 
	#We have to update his information.
	#
	$query = "SELECT uid FROM $af->{site__dbtbl_prefix}_CORE_friends WHERE af_id = '$af_id'";
	eval{
	    $sth = $af->getDB->prepare($query);
	    $sth->execute();
	};
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}

	@row = $sth->fetchrow_array;
	if(@row && @row!=() ){

	    Affelio::misc::Debug::debug_print("FM::add_friend: Already my friend!");
	      
	      $query = "update $af->{site__dbtbl_prefix}_CORE_friends set timestamp = '$timestamp', password = '$password' where af_id = '$af_id'";
	      eval{
		  $sth = $af->getDB->prepare($query);
		  $sth->execute();
	      };
	      if($@){
		  throw Affelio::exception::DBException($af->getDB->errstr);
	      }
	      Affelio::misc::Debug::debug_print("FM::add_friend:\tUpdated an existing friend.");
	      Affelio::misc::Debug::debug_print("FM::add_friend: end($row[0]).");		  
	      ################
	      #Return
	      return $row[0]; #return uid.
	}

	##############################
	#Get existing max ID
	$query = "SELECT max(uid) FROM $af->{site__dbtbl_prefix}_CORE_friends";
	eval{
	    $sth = $af->getDB->prepare($query);
	    $sth->execute();
	};
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}
	@row = $sth->fetchrow_array;
	$maxid = $row[0];
	if(defined($row[0])){
	    $maxid = $row[0];
	}else{
	    $maxid = 0;
	}
	$newid = $maxid + 1;
	Affelio::misc::Debug::debug_print("FM::add_friend: new_ID= [$newid]");

	##############################
	#Is $af_id already in F2 table?
	#If so, we have to move it from F2 table to F1 table.
	$query = "SELECT * FROM $af->{site__dbtbl_prefix}_CORE_friendsfriends WHERE af_id = '$af_id'";
	eval{
	    $sth = $af->getDB->prepare($query);
	    $sth->execute();
	}; 
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}

	@row = $sth->fetchrow_array;
	if(@row && @row !=() ){
	    ############################################
	    #I found the record in F2 table.
	    #Let's move it to the F1 table.
	    Affelio::misnc::Debug::debug_print("FM::add_friend:\t [@row]");
	    Affelio::misc::Debug::debug_print("FM::add_friend:\tHe is my friends' friend.");
	    Affelio::misc::Debug::debug_print("FM::add_friend:\tLet's move him.");
	      
	    #Backup data
	    $old_uid_in_f2tbl = $row[0];
	    $old_f1list_in_f2tbl = $row[4];

	    #Delete the record in the F2 table.
	    $query = "DELETE FROM $af->{site__dbtbl_prefix}_CORE_friendsfriends WHERE uid = $old_uid_in_f2tbl";
	    eval{
		$sth = $af->getDB->prepare($query);
		$sth->execute();
	    };
	    if($@){
		throw Affelio::exception::DBException($af->getDB->errstr);
	    }
	    Affelio::misc::Debug::debug_print("FM::add_friend:\tRecord($old_uid_in_f2tbl) in F2 tbl deleted.");

	    #Update all other F1 and F2 entries' "flist" column
	    # from $old_uid_in_f2tbl  to  $newid
	    #   update sample set data=translate(data,'b','z')
	    db_value_replace($af->getDB,
			     "$af->{site__dbtbl_prefix}_CORE_friendsfriends",
			     "uid",
			     "f1list",
			     ",$old_uid_in_f2tbl," ,
			     ",$newid," , 
			     );

	    db_value_replace($af->getDB,
			     "$af->{site__dbtbl_prefix}_CORE_friends",
			     "uid",
			     "f2list",
			     ",$old_uid_in_f2tbl," ,
			     ",$newid," , 
			     );

	    Affelio::misc::Debug::debug_print("FM::add_friend:\tOverwritten id($old_uid_in_f2tbl) -> id($newid)");
	}


	##############################
	#Insert a new record into my F1 list.
	$query = "insert into $af->{site__dbtbl_prefix}_CORE_friends(uid, af_id, nickname, timestamp, password, intro, option_pid,lastupdated,f2list) values ($newid, '$af_id', '$nickname', $timestamp, '$password', ' ', -1, 0, '$old_f1list_in_f2tbl')";
	eval{
	    $sth = $af->getDB->prepare($query);
	    $sth->execute();
	};
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}

	Affelio::misc::Debug::debug_print("FM::add_friend:\tInserted a new record.");
	Affelio::misc::Debug::debug_print("FM::add_friend: end($newid).");
	return($newid);
    }


    ########################################################################
    #remove_friend
    ########################################################################
    sub remove_friend{               #void
	my $self = shift;
	my $uid = shift;           #arg(1) uid (int)
	my $af = $self->{af};

	Affelio::misc::Debug::debug_print("FM::remove_friend:start.");

	#Remove entry(uid) from AFuser_CORE_friends
	my $q1 = "DELETE FROM $af->{site__dbtbl_prefix}_CORE_friends WHERE uid = $uid";
	my $s1;
	eval{
	    $s1 = $af->getDB->prepare($q1);
	    $s1->execute();
	};
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}
	undef($q1);
	undef($s1);
	Affelio::misc::Debug::debug_print("FM::remove_friend:\t removed entry($uid) from F1 DB");
	
	#Remove uid from friends of others in AFuser_CORE_friends
	db_value_replace($af->getDB,
			 "$af->{site__dbtbl_prefix}_CORE_friends",
			 "uid",
			 "f2list",
			 ",$uid," ,
			 ",," , 
			 );
	Affelio::misc::Debug::debug_print("FM::remove_friend:\t removed entry($uid) from other's F2list in F1 DB");

	#Remove uid from friends of others in AFuser_CORE_friendsfriends
	db_value_replace($af->getDB,
			 "$af->{site__dbtbl_prefix}_CORE_friendsfriends",
			 "uid",
			 "f1list",
			 ",$uid," ,
			 ",," , 
			 );
	Affelio::misc::Debug::debug_print("FM::remove_friend:\t removed entry($uid) from other's F1list in F2 DB");
    }


    ########################################################################
    #save_F2List
    ########################################################################
    # We retrieve "friend list" from my friends.
    # That "friend list" is my "F2 list" (through the friend).
    # Then, save_F2list is invoked when the retrieved F2 list gets stored.
    sub save_F2List{
	my $self = shift;
	my $datain = shift;     #arg(1) data input
	my $f1_af_id = shift;   #arg(2) f1_af_id
	my $af = $self->{af};
	
	Affelio::misc::Debug::debug_print("FM::save_F2List: start.");  
	
	# Data format:
	#
	# [ADD|DEL] $timestamp $af_id\n
	#
	my @datalist = split("\n", $datain);
	
	my $latest_timestamp =0;
	
	#While (each line)
	foreach my $thisdata (@datalist){
	    my ($timestamp, $method, $f2_af_id, $nickname) 
		= split(" ", $thisdata);
	    
	    #If the AF_ID is mine, ignore it.
	    if($f2_af_id eq $af->{site__user_afid}){
		next;
	    }
	    
	    if($timestamp > $latest_timestamp){
		$latest_timestamp = $timestamp;
	    }
	    
	    Affelio::misc::Debug::debug_print("FM::save_F2List: [$method][$f2_af_id]");  
	    
	    if($method eq "ADD"){
		#######################
		#ADD 
		#######################
		my $sth; 
		my $query;
		my @row_in_f1table;
		my @row_in_f2table;
		
		my @row;
		my $f1_uid ="";
		my $f1_f2list="";
		
		my $f2_uid ="";
		my $f2_f1list="";
		
		my $new_f1_f2list="";
		my $new_f2_f1list="";
		
		#Get F1's info
		$f1_uid = Affelio::SNS::FriendManager::get_attribute_by_afid($self, $f1_af_id, "uid");
		$f1_f2list = Affelio::SNS::FriendManager::get_attribute_by_afid($self, $f1_af_id, "f2list");
		Affelio::misc::Debug::debug_print("FM::save_F2list: F1's F2list = [$f1_f2list]");
		
		#The guy with F2_AF_ID is in the Friend table?
		$query = "SELECT uid, f2list  FROM $af->{site__dbtbl_prefix}_CORE_friends WHERE af_id = '$f2_af_id'";
		eval{
		    $sth = $af->getDB->prepare($query);
		    $sth->execute();
		};
		if($@){
		    throw Affelio::exception::DBException($af->getDB->errstr);
		}

		@row_in_f1table = $sth->fetchrow_array;
		undef($sth);
		undef($query);
		
		if(@row_in_f1table && @row_in_f1table !=()){
		    ###############################################
		    #This $f2_af_id has been FOUND in our Friend DB.
		    ###############################################
		    Affelio::misc::Debug::debug_print("FM::save_F2List: \tF2 person is found in our F1 table");  
		      my $query2="";
		      my $sth2="";

		      $f2_uid = $row_in_f1table[0];
		      $f2_f1list = $row_in_f1table[1];
		      Affelio::misc::Debug::debug_print("FM::save_F2list: F2's F1list = [$f2_f1list]");
		      
		      #Modify "Friend" table
		      #Add $f2_uid into $f1_af_id's F2list
		      $new_f1_f2list = $f1_f2list . $f2_uid . ",";
		      Affelio::misc::Debug::debug_print("FM::save_F2List: \tnew_f1_f2list=[$new_f1_f2list]");
		      $query2 = "update $af->{site__dbtbl_prefix}_CORE_friends set f2list = '$new_f1_f2list' where uid = '$f1_uid'";
		      eval{
			  $sth2 = $af->getDB->prepare($query2);
			  $sth2->execute();
		      };
		      if($@){
			  throw Affelio::exception::DBException($af->getDB->errstr);
		      }

		      Affelio::misc::Debug::debug_print("FM::save_F2list: New F1($f1_uid)'s F2list = [$new_f1_f2list]");
		      
		      #Modify "Friend" table
		      #Add $f1_af_id into $f2_uid's F1list
		      $new_f2_f1list = $f2_f1list . $f1_uid . ",";
		      Affelio::misc::Debug::debug_print("FM::save_F2List: \tnew_f2_f1list=[$new_f2_f1list]");
		      $query2 = "update $af->{site__dbtbl_prefix}_CORE_friends set f2list = '$new_f2_f1list' where uid = $f2_uid";
		      eval{
			  $sth2 = $af->getDB->prepare($query2);
			  $sth2->execute();
		      };
		      if($@){
			  throw Affelio::exception::DBException($af->getDB->errstr);
		      }
		      Affelio::misc::Debug::debug_print("FM::save_F2list: New F2($f2_uid)'s F1list = [$new_f2_f1list]");
		      
		  }else{
		      my $query2="";
		      my $sth2="";

		      #The guy with F2_AF_ID is in the FriendsFriends table?
		      $query2 = "SELECT * FROM $af->{site__dbtbl_prefix}_CORE_friendsfriends WHERE af_id = '$f2_af_id'";
		      eval{
			  $sth2 = $af->getDB->prepare($query2);
			  $sth2->execute();
		      };
		      if($@){
			  throw Affelio::exception::DBException($af->getDB->errstr);
		      }

		      @row_in_f2table = $sth2->fetchrow_array;
		      
		      if(!@row_in_f2table || @row_in_f2table==()){
			  ###############################################
			  #This $f2_af_id has NOT been FOUND anywhere
			  ###############################################
			  Affelio::misc::Debug::debug_print("FM::save_F2List:\t F2 person is NOT Found anywhere. Brand new!");  
			    my $query3="";
			    my $sth3="";
			    
			    ##############################
			    #Get existing min ID
			    $query3 = "SELECT min(uid) FROM $af->{site__dbtbl_prefix}_CORE_friendsfriends";
			    eval{
				$sth3 = $af->getDB->prepare($query3);
				$sth3->execute();
			    };
			    if($@){
				throw Affelio::exception::DBException($af->getDB->errstr);
			    }

			    @row = $sth3->fetchrow_array;
			    my $minid = $row[0];
			    if(defined($row[0])){
				$minid = $row[0];
			    }else{
				$minid = -1;
			    }    
			    
			    ##############################
			    #Insert a new record
			    my $tmpnewid = $minid-1;
			    $query3 = "insert into $af->{site__dbtbl_prefix}_CORE_friendsfriends (uid, af_id, nickname, timestamp, f1list) values ('$tmpnewid', '$f2_af_id', '$nickname', $timestamp, ',')";
			    eval{
				$sth3 = $af->getDB->prepare($query3);
				$sth3->execute();
			    };
			    if($@){
				throw Affelio::exception::DBException($af->getDB->errstr);
			    }

			    $f2_uid = $minid - 1;  #F2 UID is negative!
			    $f2_f1list = ",";
			    Affelio::misc::Debug::debug_print("FM::save_F2List:\tCreated F2 entry id=$f2_uid");
			}else{
			    ###############################################
			    #This $f2_af_id has been FOUND in FriendsFriends DB.
			    ###############################################
			    $f2_uid = $row_in_f2table[0];
			    $f2_f1list = $row_in_f2table[4];
			    Affelio::misc::Debug::debug_print("FM::save_F2List:\t F2 person is FOUND in our F2 table.");  
			    Affelio::misc::Debug::debug_print("FM::save_F2List:\t F2uid  = [$f2_uid]");
			    Affelio::misc::Debug::debug_print("FM::save_F2List:\t F1List = [$f2_f1list]");
			}
		      
		      #Modify "Friend" table
		      #Add $f2_uid into $f1_af_id's F2list
		      $new_f1_f2list = $f1_f2list . $f2_uid . ",";
		      Affelio::misc::Debug::debug_print("FM::save_F2List:\tnew_f1_f2list=[$new_f1_f2list]");
		      $query2 = "update $af->{site__dbtbl_prefix}_CORE_friends set f2list = '$new_f1_f2list' where uid = $f1_uid";
		      eval{
			  $sth2 = $af->getDB->prepare($query2); 
			  $sth2->execute();
		      };
		      if($@){
			  throw Affelio::exception::DBException($af->getDB->errstr);
		      }
		      
		      #Modify "FriendsFriends" table
		      #Add $f1_af_id into $f2_uid's F1list
		      $new_f2_f1list = $f2_f1list . $f1_uid . ",";
		      Affelio::misc::Debug::debug_print("FM::save_F2List:\tnew_f2_f1list=[$new_f2_f1list]");
		      $query2 = "update $af->{site__dbtbl_prefix}_CORE_friendsfriends set f1list = '$new_f2_f1list' where uid = $f2_uid";
		      eval{
			  $sth2 = $af->getDB->prepare($query2);
			  $sth2->execute();
		      };
		      if($@){
			  throw Affelio::exception::DBException($af->getDB->errstr);
		      }
		      
		  }#if
		      Affelio::misc::Debug::debug_print("FM::save_F2List: [$method] DONE.");
		
	    }elsif($method eq "DEL"){
		#######################
		#DEL
		#######################
		#XXX Not implemented
		
	    }elsif($method eq "MOV"){
		#######################
		#MOV
		#######################
		#XXX Not implemented

	    }#if(method)

	}#foreach

	Affelio::misc::Debug::debug_print("FM::save_F2List: Latest timestamp=[$latest_timestamp]");
	#Updating "lastupdated" attribute of this friend...
	my $f1_uid = get_attribute_by_afid($self, $f1_af_id, "uid");

	set_attribute_by_id($self, $f1_uid, "lastupdated", $latest_timestamp);
    }


    ########################################################################
    #get_updated_friends
    ########################################################################
    sub get_updated_friends{          #return string result
	my $self = shift;
	my $req_timestamp = shift;    #arg(1) timestamp
	my $af = $self->{af};

	##############################
	#retrieve a friend record from DB
	my $query = "SELECT af_id, timestamp, nickname FROM $af->{site__dbtbl_prefix}_CORE_friends WHERE timestamp > " . $req_timestamp;
	my $sth;
	eval{
	    $sth = $af->getDB->prepare($query); 
	    $sth->execute();
	};
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}

	my $retmsg="";
	my @row=();
	my $af_id="";
	my $timestamp="";
	my $nickname="";
	while( ($af_id, $timestamp, $nickname) = $sth->fetchrow_array){
	    $retmsg .= "$timestamp ADD $af_id $nickname\n";
	}

	##############################
	#retrieve erased friend record from DB
	#XXX Not implemented

	##############################
	#Sort by time
	#XXX Not implemented

	debug_print("FM::get_updated_friends: ret=[$retmsg]");
	return($retmsg);
    }


    ########################################################################
    #get_all_friend_list
    ########################################################################
    sub get_all_friend_list{          #return SQL_result
	my $self = shift;
	my %param = @_;

	my $af = $self->{af};
	my $where = $param{where};
	my $where_block ="";
	if($where ne ""){ $where_block = "WHERE $where";}
	my $sort = $param{sort};
	if($sort eq ""){ $sort = "uid";}
	my $order = $param{order};
	if($order eq ""){ $order = "asc";}

	##############################
	#retrieve all friend records from DB
	my $query = "SELECT uid, af_id, nickname, timestamp, password, intro, option_pid, lastupdated, f2list, last_news_in, last_news_out FROM $af->{site__dbtbl_prefix}_CORE_friends  $where_block  order by $sort $order";
	debug_print("FM::get_all_friend_list: query=[$query]");
	my $sth;
	eval{
	    $sth = $af->getDB->prepare($query);
	    $sth->execute();
	};
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}

	return($sth);
    }


    ########################################################################
    #get_friend_by_uid
    #  arg(1) uid
    #  returns array(0uid, 1af_id, 2nickname, 3timestamp, 
    #                4password, 5intro, 6option_pid)
    ########################################################################
    sub get_friend_by_uid{                #return an SQL array
	my $self = shift;
	my $uid = shift;                  #arg(1) uid    (int)
	
	my $af = $self->{af};

	##############################
	#retrieve a friend record from DB
	my $query = "SELECT uid, af_id, nickname, timestamp, password, intro, option_pid, lastupdated, f2list, last_news_in, last_news_out FROM $af->{site__dbtbl_prefix}_CORE_friends WHERE uid = $uid";
	my $sth;
	eval{
	    $sth = $af->getDB->prepare($query);
	    $sth->execute();
	};
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}
	my @row = $sth->fetchrow_array;
	if(@row==()) {undef @row};
	return(@row);
    }


    ########################################################################
    #get_friend_by_afid
    #  arg(1) afid
    #  returns array(0uid, 1af_id, 2nickname, 3timestamp, 
    #                4password, 5intro, 6option_pid
    ########################################################################
    sub get_friend_by_afid{             #return an SQL array
	my $self = shift;
	my $af_id = shift;              #arg(1) afid    (string)
	
	my $af = $self->{af};

	##############################
	#retrieve a friend record from DB
	my $query = "SELECT uid, af_id, nickname, timestamp, password, intro, option_pid, lastupdated, f2list, last_news_in, last_news_out FROM $af->{site__dbtbl_prefix}_CORE_friends WHERE af_id = '$af_id'";
	my $sth;
	eval{
	    $sth = $af->getDB->prepare($query);
	    $sth->execute();
	};
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}

	my @row = $sth->fetchrow_array;
	if(@row==()) {undef @row};
	return(@row);
    }
    

    ########################################################################
    #get_attribute_by_uid
    ########################################################################
    sub get_attribute_by_uid{            #return a value
	my $self = shift;
	my $uid = shift;                 #arg(1) uid  (int)
	my $attr = shift;                #arg(2) attr (string)
	
	my $af = $self->{af};

	##############################
	#retrieve a friend record from DB
	Affelio::misc::Debug::debug_print("FM::get_attr_by_uid(uid=$uid, attr=$attr)");
	my $query = "SELECT $attr FROM $af->{site__dbtbl_prefix}_CORE_friends WHERE uid = '$uid'";
	my $sth;
	eval{
	    $sth = $af->getDB->prepare($query);
	    $sth->execute();
	};
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}

	my @row = $sth->fetchrow_array;
	return($row[0]);
    }


    ########################################################################
    #F2_get_attribute_by_uid
    ########################################################################
    sub F2_get_attribute_by_uid{            #return a value
	my $self = shift;
	my $uid = shift;                 #arg(1) uid  (int)
	my $attr = shift;                #arg(2) attr (string)
	
	my $af = $self->{af};

	##############################
	#retrieve a friend record from DB
	my $query = "SELECT $attr FROM $af->{site__dbtbl_prefix}_CORE_friendsfriends WHERE uid = $uid";
	my $sth;
	eval{
	    $sth = $af->getDB->prepare($query);
	    $sth->execute();
	};
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}
	my @row = $sth->fetchrow_array;
	return($row[0]);
    }

    ########################################################################
    #get_attribute_by_afid
    ########################################################################
    sub get_attribute_by_afid{           #return a value
	my $self = shift;
	my $af_id = shift;               #arg(1) afid (string) 
	my $attr = shift;                #arg(2) attr (string)

	my $af = $self->{af};
	$af_id = $af->getDB->quote($af_id . '%');
	
	##############################
	#retrieve a friend record from DB
	my $query = "SELECT $attr FROM $af->{site__dbtbl_prefix}_CORE_friends WHERE af_id like $af_id";
	debug_print("FriendManager::get_atr_by_afid: [$query]");

	my $sth;
	my @row = ();
	my $size = 0;
	eval{
	    $sth = $af->getDB->prepare($query);
	    $sth->execute;
	    debug_print("FriendManager::get_atr_by_afid: DBaccess done.");
	    @row = $sth->fetchrow_array;
	    $size = @row;
	};
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}

	debug_print("FriendManager::get_atr_by_afid: done.");
	return($row[0]);
    }

    ########################################################################
    #set_attribute_by_afid
    ########################################################################
    sub set_attribute_by_afid{
	my $self = shift;
	my $af_id = shift;            #arg(1) uid (string) 
	my $attr = shift;           #arg(2) attr (string)
	my $value = shift;          #arg(3) value (string)
	
	my $af = $self->{af};
	$af_id = $af->getDB->quote($af_id . '%');
	if(($attr eq "password") 
	   || ($attr eq "apps") 
	   || ($attr eq "nickname") 
	   || ($attr eq "intro") ){
	    $value = $af->getDB->quote($value);
	}

	##############################
	#set value into DB
	my $query = "update $af->{site__dbtbl_prefix}_CORE_friends set $attr = $value where af_id like $af_id";
	my $sth;
	eval{
	    $sth = $af->getDB->prepare($query);
	    $sth->execute;
	}; 
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}
    }

    ########################################################################
    #incr_attribute_by_afid
    ########################################################################
    sub incr_attribute_by_afid{
	my $self = shift;
	my $af_id = shift;            #arg(1) uid (string) 
	my $attr = shift;           #arg(2) attr (string)
	
	my $af = $self->{af};
	$af_id = $af->getDB->quote($af_id . '%');

	##############################
	#set value into DB
	my $query = "update $af->{site__dbtbl_prefix}_CORE_friends set $attr = $attr + 1 where af_id like $af_id";
	my $sth;
	eval{
	    $sth = $af->getDB->prepare($query);
	    $sth->execute;
	}; 
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}
    }

    ########################################################################
    #set_attribute_by_id
    ########################################################################
    sub set_attribute_by_id{        #void
	my $self = shift;
	my $uid = shift;            #arg(1) uid (string) 
	my $attr = shift;           #arg(2) attr (string)
	my $value = shift;          #arg(3) value (string)

	my $af = $self->{af};
	if(($attr eq "password") 
	   || ($attr eq "af_id") 
	   || ($attr eq "nickname") 
	   || ($attr eq "intro") ){
	    $value = $af->getDB->quote($value);
	}

	##############################
	#set value into DB
	my $query = "update $af->{site__dbtbl_prefix}_CORE_friends set $attr = $value where uid = $uid";
	my $sth;
	eval{
	    $sth = $af->getDB->prepare($query);
	    $sth->execute;
	}; 
	if($@){
	    throw Affelio::exception::DBException($af->getDB->errstr);
	}

    }



    ########################################################################

}#package
1;

