package ACIS::Web::Affiliations;

use strict;


use Data::Dumper;

use Encode;
use Carp::Assert;

use ACIS::Common;


sub load_institution {
  my $app = shift;
  my $handle = shift;

  my $sql = $app -> sql_object;
  my $metadata_db = $app -> config( 'metadata-db-name' );

  my $statement   = "select * from $metadata_db.institutions where handle=?";
  
  $sql -> prepare ( $statement );
  my $sql_res = $sql -> execute ( $handle );
  
  if ( not $sql_res ) {
    $app -> errlog( "database error in Affiliations::load_institution: no result of execute" );
    $app -> error ( 'db-error' );
    # debug "error while processing request: " . $sql -> error;
    debug "database query error";
    return undef;
  }
  
  my $search_results = $sql_res -> {rows};
  
  debug "found $search_results";
  
  if ( $search_results ) {  
    my $institution = $sql_res -> {row};
    
    foreach ( keys %$institution ) {
      my $value = $institution ->{$_};
      $institution ->{$_} = Encode::decode_utf8( $value );
    }

    return $institution;
  }
}



sub prepare {   ### XXX here is a great place for optimization in
                ### terms of unloading the server, and making the
                ### service work quicker

  my $app = shift;
  
  debug "preparing affiliations - copying unfolded and resolving handles into institutions";
  
  my $config  = $app -> config;
  my $session = $app -> session;
  
  my $affiliations = $session -> current_record -> {affiliations};
  my @handles = ();


  my $unfolded = [];
  
  return
   unless defined $affiliations and scalar @$affiliations;

   
  foreach ( @$affiliations ) {

    if (ref $_ eq 'HASH') {
      push @$unfolded, $_;

    } else {
      my $institution =  &load_institution( $app, $_ );
      push @$unfolded, $institution;
      
    }
  }
  
 
  $app -> variables -> {affiliations} =
    $session -> {affiliations} = $unfolded;
}






sub add {
  my $app = shift;
  
  my $config      = $app -> config;
  my $metadata_db = $config->{'metadata-db-name'};

  my $handle  = $app -> get_form_value ('handle');
  my $action  = $app -> get_form_value ('action');
  
  debug 'try to add an affiliation';
  
  my $session = $app -> session;
  my $search_rec   = $session -> {'institution-search'} ;
  my $search_items = $search_rec -> {items};

  my $record  = $session -> current_record;


  $record -> {affiliations} = []
   unless defined $record -> {affiliations};
  
  my $affiliations = $record  ->{affiliations};
  
  $session -> {affiliations} = []
   unless defined $session -> {affiliations};
  
  my $unfolded     = $session ->{affiliations};
  


  # xslt uses handles
  if( $action eq 'add' ) {  ### XXX submit.string
    debug 'adding institution: $handle';
    $app -> userlog( "affil: add an item, h: $handle" );
    
    foreach ( @$unfolded ) {

      if ( defined $_ -> {handle}
	   and $_ -> {handle} eq $handle ) {
#	$app -> error ( 'adding-affiliation-duplicate' ); ### XXX ignore
#	$app -> clear_process_queue;
	return;
      }
    }
    
    my $institution;
  
    my $counter = 0;
    foreach ( @$search_items ) {

      if ( $_ -> {handle} eq $handle ) {
	$institution = 'found';
	last;
      }
      $counter++; 
    }
    
    if ( $institution ) {
      $institution = splice @$search_items, $counter, 1;
      $search_rec -> {results} --;
      
    } else {
      $institution = load_institution( $app, $handle );
    } 

    push @$unfolded,     $institution;
    push @$affiliations, $handle;


  } else {
    debug "should not be here, because..." 

  } ### if not just the institution handle

}



sub remove {
  my $app = shift;
  
  my $session = $app -> session;

  my $affiliations = $session -> current_record -> {affiliations};
  my $unfolded     = $session -> {affiliations};
  
  return 
    unless defined $affiliations and scalar @$affiliations;

  my $handle = $app -> get_form_value ( 'handle' );
  my $name   = $app -> get_form_value ( 'name'   );
  
  debug "remove institution h: $handle, n: $name";

  $app -> userlog( "affil: request to remove an item, h: $handle, n: $name" );

  my @old_affs = @$affiliations;
  my @old_unfolded = @$unfolded;
  @$affiliations = ();
  @$unfolded = ();

  debug "copying affiliations, skipping removed";

  foreach my $institution ( @old_affs ) {
    my $unfolded_i = shift @old_unfolded;

    if ( ref $institution ) {
      debug "checking $institution->{name}";
      if( $institution -> {handle} 
	  and $institution -> {handle} eq $handle ) {
	debug "skipped";
	next;
      }

      if( $institution -> {name} eq $name ) {  
	debug "skipped";
	next;
      }
      
    } else {
      debug "checking $institution";
      if( $institution eq $handle ) {
	debug "skipped";
	next;
      }
    }
    
    push @$affiliations, $institution;
    push @$unfolded,     $unfolded_i;
  }
  
  if( scalar @$affiliations < scalar @old_affs ) {
    $app -> userlog( "affil: removing success" );

  } else {
    $app -> userlog( "affil: removing didn't work" );
  }
} 
  



sub search {

  my $app = shift;
  
  my $cgi  = $app -> request -> {CGI};
  my $sql  = $app -> sql_object;
  my $session = $app -> session;

  my $config  = $app -> config;
  my $metadata_db = $config->{'metadata-db-name'};


  my $key = $cgi->param( 'search-what' ) ;

  my $what = '%' . $key . '%';
  my $type = $cgi -> param ('search-by');

  $type =~ s/[^a-z]//g;

  $app -> userlog( "affil: search: by $type, key: '$key'", );

  
  my $statement = '';
  my @handles   = ();
  my $affiliations = $session -> {'affiliations'};

  if ( defined $affiliations and scalar @$affiliations ) {

    foreach (@$affiliations) {
      next unless $_ -> {'handle'};
      $statement .= ' and handle!=?';
      push @handles, $_ -> {'handle'};
    }
  }
      
  return
   unless ($type =~ /^(location|name)$/);
      
  $sql -> prepare ( "select * from $metadata_db.institutions where $type like ? $statement limit 51");
  my $sql_res = $sql -> execute ( $what, @handles );
      
  unless (defined $sql_res)
   {
    $app -> error ('db-select-error');
    return;
   }
      
  my $search_results = $sql_res -> {rows};
      
  if ($search_results > 50)
   {
    $app -> error ('db-select-too-many-results');
   }
      
  my $search = {};
  $search -> {'results'} = $sql_res -> {rows};
      
  # name, email, postal, phone, fax, homepage, location

  my $items = $search -> {items} = [];
    
  while ( $search_results-- ) {  

    my $institution = $sql_res -> {row};
    
    foreach ( keys %$institution ) {  ### XXX this piece is repeated
      my $value = $institution ->{$_};
      $institution ->{$_} = Encode::decode_utf8( $value );
    }
      
    push @$items, $institution;
    
    $sql_res -> next;
  }

#  $sql_res -> next;
      
  $app -> variables -> {'institution-search'} = $search;
  $session -> {'institution-search'} = $search;

 }



sub make_it_visible {
  my $app = shift;
  
  my $session = $app -> session;

  my $search = $session -> {'institution-search'};
  $app -> variables -> {'institution-search'} = $search
    if defined $search 
      and ref( $search->{items} ) 
      and scalar @{ $search -> {items} };
  
  my $affiliations = $session -> {'affiliations'};
  $app -> variables -> {'affiliations'} = $affiliations
    if defined $affiliations 
      and scalar @$affiliations;
}


sub general_handler {
  my $app   = shift;
  
  debug "running affiliation service screen";
  
  my $session = $app -> session;
  my $cgi     = $app -> request -> {CGI};

  my $action = $app -> get_form_value ('action');
   
  ### XXX submit.strings
  ### XXX I18N dependency on presenter:
  if ($action =~ m/continue/i ) { 

     if( $session -> type eq 'new-user' ) {
       $app -> redirect_to_screen ('new-user/complete');

     } else {
       $app  -> message( "data-saved" );
       $app -> redirect_to_screen ('welcome');
     }

   } else {
     
     ### XXX submit.strings
     if ( $action eq 'add'    ) { add( $app );    }
     if ( $action eq 'remove' ) { remove( $app ); }
     if ( $action eq 'search' ) { search( $app ); }

   }

  make_it_visible( $app );

}




sub submit_institution {

  my $app = shift;

  my $session = $app -> session;
  my $institution = {};

  my $input = $app -> request ->{params};

  my $name    = $input -> {name};
  my $oldname = $input -> {oldname};
  my $id      = $input -> {handle};
  
  debug "submit: name: $name";
  debug "submit:  old: $oldname";
  debug "submit: id  : $id";
 

  foreach ( qw( name name-english location homepage 
		email phone fax   postal   note handle 
	        add-to-profile ) ) {
    if( defined $input->{$_} ) {
      $institution -> {$_} = $input->{$_};
    }
  }

  $institution -> {'submitted-by'} = $session -> owner -> {login};


  if( $session -> {'submitted-institutions'} ) {

    ### append or replace an institution in the submitted list
    my $list = $session -> {'submitted-institutions'};
    my $replace;
    my $counter = 0;

    foreach ( @$list ) {
      if( $_ -> {name} eq $name 
	  or $_ -> {name} eq $oldname   ### this is when user wants to edit an institution
	  or ( $_->{handle} and ( $_ -> {handle} eq $id ) )  ) {
	$replace = $counter; last;
      }
      $counter ++;
    }

    if( defined $replace ) {
      $list ->[$replace] = $institution;
    } else {
      push @$list, $institution;
      debug "submit: added to the submitted list";
    }

  } else {
    ### create the submitted institutions list
    $session -> {'submitted-institutions'} = [ $institution ];
  }



  # adding an institution to the profile
  

  if( $input -> {'add-to-profile'} ) {

    debug "adding a submitted institution ($name) to the record";
    $app -> userlog( "affil: add a submited institution, name: $name", $id ? " h: $id" : '' );
  

    my $record  = $session -> current_record;

    assert( $record->{type} eq 'person' );

    $record -> {affiliations} = []
      if not defined $record -> {affiliations};

    $session -> {affiliations} = []
      if not defined $session -> {affiliations};
  
    my $affiliations = $record  ->{affiliations};
    my $unfolded     = $session ->{affiliations};
  
    ### additional check
    my $replace;
    my $counter = 0;
    foreach ( @$unfolded ) {

      if (  
	  ( $_ -> {name} eq $name ) 
	  or ( $_ -> {name} eq $oldname ) 
	  or (
	      defined $_ -> {handle} 
	      and ( $_ -> {handle} eq $id ) 
	     )
	 ) {
	### there is already such an institution...
	$replace = $counter;
	last;
      }
      $counter++;
    }
    
    if( defined $replace ) {
      debug "replacing item no $replace";
      $$affiliations[$replace] = $institution;
      $$unfolded[$replace]     = $institution;
      
    } else {
      debug "adding new item";
      push @$affiliations, $institution;
      push @$unfolded,     $institution;
    }
  
  } # if "add-to-profile" 
  else {
    
    debug "not needed to add";

    $app -> userlog( "affil: submited an institution, but asked not to add it, name: $name", $id ? " h: $id" : '' );
  }


  $app  -> message( "institution-submission-accepted" );

  if( $session -> type eq 'new-user' ) {
    $app -> redirect_to_screen ('new-user/affiliation');
    
  } else {
    $app -> redirect_to_screen ( 'affiliation' );
  }


}



1; 
