package Database;

my $comp;

# This is the client->server interface, so when we say "send_foo", we
# mean, send a foo from the client (openimpetus.pl or admin.pl, etc)
# to Server.pl.

# In general, sending stuff is *identical* to serializing it to the
# database logfile.

# This is theoretically used when we have multiple comps being hosted.
# So we'le setting what $comp is.  Not sure that this works.
sub register_comp {
  $comp=$_[0];
} # register_comp

# Send a scalar.  This is a primitive.
sub send_scalar {
#  print "sending: '".length($_[0])."'\n";
  send(main::SOCK, length($_[0]), 0);
#  print "sending: '!'\n";
  send(main::SOCK, "!", 0);
#  print "sending: '$_[0]'\n";
  send(main::SOCK, $_[0], 0);
}

# Send the dispatch code.  Since it's the first thing we send, we
# special-case it to make sure we're actually *talking* to someone.
sub send_dispatch {
  print STDERR "dispatch: '$_[0]'\n";
  print STDERR "comp: '$comp'\n";
  
  if (!$main::server_connection_open) {
    main::connect_to_server();
  }
  send(main::SOCK, $_[0], 0);
  send_scalar($comp);
}

# Send a couple.  Not surprisingly, we just invoke send_competitor twice.
sub send_couple {
#  print "sending leader...\n";
  send_competitor($_[0]->getLeader());
#  print "sending follower...\n";
  send_competitor($_[0]->getFollower());
#  print "done.\n";
}

# Schools are just a scalar.
sub send_school {
  send_scalar($_[0]);
}

# When we send a dance over, the first thing we send is an integer,
# which says how many dances we're sending over: 1 for Single, 2+ for
# Multi.
sub send_dance {
  my ($i, $numDances, $this, $dance);
  $this=$_[0];
  $numDances=$this->getNumDances();
  send_scalar($numDances);
  if ($numDances==1) {
    send_scalar($this->getLevel());
    send_scalar($this->getContinent());
    send_scalar($this->getConstantsName());
  } else {
    for ($i=1;$i<=$numDances;$i++) {
      $dance=$this->getDance($i);
      send_scalar($dance->getLevel());
      send_scalar($dance->getContinent());
      send_scalar($dance->getConstantsName());
    }
  }
}

# Yay.
sub send_competitor {
  send_scalar($_[0]->getLName());
  send_scalar($_[0]->getFName());
  send_scalar($_[0]->getSchool());
  send_scalar($_[0]->getEmail());
  send_scalar($_[0]->doesEmailExist());
  send_scalar($_[0]->getNumber());
  send_scalar($_[0]->getTBA());
}

# Receive a vector *of scalars*.
sub recv_vector {
  my @vec;
  print "recv_vector: start\n";
  while(<main::SOCK>) {
    chop;
    print "recv: '$_'\n";
    last if /^$/;
    push(@vec, $_);
  }
  print "recv_vector: returning: '@vec'\n";
  return(\@vec);
}

# Receive a vector of non-scalars.  We need the dispatch code to know
# what we're receiving: e.g., if we say GetNameSortedCompetitorsByDance,
# we're getting a vector of Competitors.
sub recv_vector_of_stuff {
  my @vec;
  my $dispatch=$_[0];
  my $ret;

  if ($dispatch==10 or $dispatch==11 or $dispatch==12) {
    while ($ret=recv_competitor()) {
      push(@vec, $ret);
    }
  } elsif ($dispatch==15) { # 13 and 14 recv_scalar
    while ($ret=recv_dance()) {
      push(@vec, $ret);
    }
# Why don't we say recv_vector?  Hmm, maybe to just be consistent.
  } elsif ($dispatch==16) {
    while ($ret=recv_scalar()) {
      push(@vec, $ret);
    }
  } elsif ($dispatch==17 or $dispatch==18) {
    while ($ret=recv_competitor()) {
      push(@vec, $ret);
    }
  } elsif ($dispatch>=19 and $dispatch<=22) {
    while ($ret=recv_couple()) {
      push(@vec, $ret);
    }
# Why don't we say recv_vector?  Hmm, maybe to just be consistent.
  } elsif ($dispatch==23 or $dispatch==24) {
    while (defined($ret=recv_scalar())) {
      push(@vec, $ret);
    }
  }

# # Debugging info.
#  print "vec: '@vec'\n";
#  for (my $i=0;$i<=$#vec;$i++) {
#    print "vec[$i]: ".$vec[$i]->getAbbrev()."\n";
#  }
#  print "recv_vector_of_stuff: returning vector sizeof=$#vec\n";
  return(\@vec);
}

# Receive a single scalar.
sub recv_scalar {
  $_=<main::SOCK>;
#  print "got: '$_'\n";
  chop;
  if ($_ eq '') {return(undef);}
  return($_);
}

# The Server always sends a return status.  Usually it's irrelevant,
# of course, but it's still good form to check.
sub check_return_status {
  my $ret=&recv_scalar;
#  print "return status: $ret\n";
  return if ($ret eq "SUCCESS");
  if ($ret eq "AlreadyRegistered") {
    Error::AlreadyRegistered(&recv_scalar);
  } else {
    Error::Croak("Unknown server error dispatch: '$ret'\n");
  }
}

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

sub addCouple {
  my ($coup, $school, $dance)=@_;
  send_dispatch("01");
  send_couple($coup);
  send_school($school);
  send_dance($dance);
  &check_return_status;
}

sub addCoupleToDance {
  my ($dance, $coup)=@_;
  send_dispatch("02");
  send_dance($dance);
  send_couple($coup);
  &check_return_status;
}

sub addCoupleToSchools {
  my $coup=$_[0];
  send_dispatch("03");
  send_couple($coup);
  &check_return_status;
}

sub removeCouple {
  my $coup=$_[0];
  send_dispatch("04");
  send_couple($coup);
  &check_return_status;
}

sub removeCoupleFromDance {
  my ($dance, $coup)=@_;
  send_dispatch("05");
  send_dance($dance);
  send_couple($coup);
  &check_return_status;
}

####

sub getCompetitorsBySchool {
  my $school=$_[0];
  send_dispatch("10");
  send_school($school);
  return(recv_vector_of_stuff(10));
}

sub getFollowers {
  my $leader=$_[0];
  send_dispatch("11");
  send_competitor($leader);
  return(recv_vector_of_stuff(11));
}

sub getLeaders {
  my $follower=$_[0];
  send_dispatch("12");
  send_competitor($follower);
  return(recv_vector_of_stuff(12));
}

sub getNumberOfCompetitors {
  send_dispatch("13");
  return(recv_scalar());
}

sub getNumberOfCouplesInDance {
  send_dispatch("14");
  send_dance($_[0]);
  return(recv_scalar());
}

sub getDancesByCouple {
  send_dispatch("15");
  my $couple=$_[0];
  send_couple($_[0]);
  return(recv_vector_of_stuff(15));
}

sub getEmailAddresses {
  send_dispatch("16");
  return(recv_vector_of_stuff(16));
}

sub getNameSortedCompetitors {
  send_dispatch("17");
  return(recv_vector_of_stuff(17));
}

sub getNameSortedCompetitorsBySchool {
  send_dispatch("18");
  send_school($_[0]);
  return(recv_vector_of_stuff(18));
}

sub getNameSortedCouples {
  send_dispatch("19");
  return(recv_vector_of_stuff(19));
}

sub getNumberSortedCouples {
  send_dispatch("20");
  return(recv_vector_of_stuff(20));
}

sub getNameSortedCouplesByDance {
  send_dispatch("21");
  send_dance($_[0]);
  return(recv_vector_of_stuff(21));
}

sub getNumberSortedCouplesByDance {
  send_dispatch("22");
  send_dance($_[0]);
  return(recv_vector_of_stuff(22));
}

sub getSchoolAbbrev {
  $_=$_[0];
  if (/\(/) {
    ($crap, $_)=split('\(', $_);
    ($_, $crap)=split('\)', $_);
  } elsif ($_==-1) {
    return("<i>".Constants::get("HTML_MSG30")."</i>");
  }
  return($_);
}

sub getSchools {
  send_dispatch("23");
  return(recv_vector_of_stuff(23));
}

sub getSortedSchools {
  send_dispatch("24");
  return(recv_vector_of_stuff(24));
}

sub isLeader {
  send_dispatch("25");
  send_competitor($_[0]);
  $ret=recv_scalar();
  return($ret);
}

sub isFollower {
  send_dispatch("26");
  send_competitor($_[0]);
  return(recv_scalar());
}

sub do_stats {
  send_dispatch("90");
  return(1);
}

sub scrub_db {
  send_dispatch("91");
}

sub loadComp {
  send_dispatch("92");
  send_scalar($_[0]);
}

sub close_connection {
  print STDERR "closing connection\n";
  send_dispatch("97");
}

sub exit {
  send_dispatch("98");
}

sub quit {
  send_dispatch("99");
}

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

# package Network, which due to scoping, can't be split off for now
# (well, we can put it all in main::, but then that means that main::recv_foo
# just points to Database::recv_foo, which isn't very optimal.  Maybe perl
# optimizes this, but I doubt it.

sub recv_couple {
  my ($leader, $follower);
  $leader=recv_competitor();
  $follower=recv_competitor();
  
#  return(Couple->new($leader, $follower));
  
  my $couple=Couple->new($leader, $follower);
#  print "leader name: ".$couple->getLeader()->getName()."\n";
#  print "follower name: ".$couple->getFollower()->getName()."\n";
  return($couple);
}

sub recv_school {
  return(recv_scalar());
}

sub recv_dance {
  my ($dance, $numDances, @dances, $level, $continent, $cons_name, $i);
  $numDances=recv_scalar();
  if (!$numDances) {
    return(undef);
  }
  $level=recv_scalar();
  $continent=recv_scalar();
  $cons_name=recv_scalar();
  $dance=SingleDance->new($level, $continent, $cons_name);
  if ($numDances==1) {
#    print "RETURNING SINGLE DANCE: $level, $continent, $cons_name\n";
    return($dance);
  } else {
    @dances=(0, 0, 0, 0, 0, 0);
    $dances[1]=$dance;
    for ($i=2;$i<=$numDances;$i++) {
      $level=recv_scalar();
      $continent=recv_scalar();
      $cons_name=recv_scalar();
      $dance=SingleDance->new($level, $continent, $cons_name);
      $dances[$i]=$dance;
    }
    return(MultiDance->new($dances[1], $dances[2], $dances[3], $dances[4],
			   $dances[5], $numDances));
  }
}

sub recv_competitor {
  my ($lname, $fname, $school, $email, $email_exists, $number, $tba);

  $lname=recv_scalar();
  if (!$lname) {
    return(undef);
  }
  $fname=recv_scalar();
  $school=recv_scalar();
  $email=recv_scalar();
  $email_exists=recv_scalar();
  $number=recv_scalar();
  $tba=recv_scalar();
  return(Competitor->new2($lname, $fname, $school, $email, $email_exists,
			  $number, $tba));
}

1;
