#!/usr/local/rib/rib-1.0/bin/perl
use lib '/usr/local/rib/rib-1.0/lib';
# NHSE Repository in a Box (RIB)
#
# The authors of this software are Paul McMahan and Jeff Horner.
# Copyright (c) 1997 by the University of Tennessee.
# Permission to use, copy, modify, and distribute this software for any
# purpose without fee is hereby granted, provided that this entire notice
# is included in all copies of any software which is or includes a copy
# or modification of this software and in all copies of the supporting
# documentation for such software.
# THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
# WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR UNIVERSITY OF TENNESSEE
# MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
# MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
#
# $Id: create_object.pl,v 1.3 1998/02/24 22:56:57 rib Exp $
#
# $Log: create_object.pl,v $
# Revision 1.3  1998/02/24 22:56:57  rib
# changed the button which updates the form (after clicking "add a field
# or "delete a field") to say "Update form" instead of just "Update".
# A button which just said "Update" was misleading, especially when used
# in edit_object.pl
#
# Revision 1.2  1998/01/22 02:50:07  rib
# added the upload and mirroring feature to RIB.  This required
# the addition of several new scripts and the modification of
# admin_repository.
#
# also, removed any use of <a target=whatever href=...>
# from the RIB scripts because this was working out very
# well.
#
# Revision 1.1.1.1  1997/12/10 15:59:31  jhorner
# RIB pre 1.0
#
# Revision 1.1  1997/05/06 18:15:49  jhorner
# Initial revision
#


use RIB::Util ();
use RIB::ConfigParser ();
use RIB::DomainParser ();
use HTML::Entities ();

my $util = RIB::Util->new();
$util->PrintHeader();
my %in = $util->ReadParse();

$repository = $util->GetRepoName();
if (!$repository) {
  $util->ErrorMessage("repository was not specifed in your input.");
} elsif (!$in{class}) {
  $util->ErrorMessage("class was not specifed in your input.");
}

my $filepath = $util->GetRibDir() . "/repositories/" . $repository;
my $urlpath  = $util->GetRibUrl() . "/repositories/" . $repository;

$back_to_top = $util->BackToTop($repository);

my $cp = RIB::ConfigParser->new();
$cp->load_config($filepath."/conf/BIDM.conf");
my $object = $cp->InstanceOf('',$in{class});

# get a list of all of the fieldnames that were in
# this repository's config file
my @allfields = $object->Fields();

# sort inputs from the %in variable into arrays.
foreach $key (keys %in) {
  next unless $key =~ /^\d+(\S+)/;
  my $field = $1;
  $object->AddEntry($field, $in{$key});
}

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

print "<head>";
print "<title>$in{class} ";
print "creation for &quot;$repository&quot;</title>\n";
print "</head>\n";
print "<body bgcolor=#FFFFF0>\n";
print "<center>\n";
print "<h1>$in{class} creation for ";
print "&quot;$repository&quot;</h1>\n";
print "</center>\n";
print "<p><hr><p>\n";
print "[<i><a href=", $util->GetRibUrl(), "/help/help.html#create_form>";
print "help</a> on using this form</i>]\n<p>\n";

if ($in{create}) {
  my $filename = $in{filename};
  my $overwrite = $in{overwrite};

  my $errors = '';
  $filename =~ s/^\s+//;
  $filename =~ s/\.html\s*$//ig;
  
  # check out the filename
  if (!$filename) {
    push (@errors, "<a href=#filename>Filename</a> needs an input");
  }
  elsif ($filename!~/^[0-9a-zA-Z_\-\.]+$/) {
    push (@errors,"The <a href=#filename>Filename</a> that you entered "
                . "contained at least one "
               .  "space or other illegal character.");
  }
  elsif ($filename =~ /\.\.\//) {
    push (@errors,"The <a href=#filename>Filename</a> that you entered "
                . "contained '../' which an illegal sequence for "
               .  "the filename");
  }
  elsif (-e "$filepath/objects/$in{class}/$filename.html" && !$overwrite) {
    push (@errors,"The <a href=#filename>Filename</a> that "
                . "you specified is already in use in the "
                . "<a href=browse_objects.pl?"
                . "class=$in{class}>"
                . "$in{class} directory</a>.<br>Please "
                . "choose a different filename for this "
                . "$in{class}.  If you want to replace the current file "
                . "then you need to "
                . "make sure that the "
                . "that the &quot;Overwrite&quot; checkbox is depressed "
                . "(next to the <a href=#filename>filename</a> box).");
  }

  foreach $field (sort @allfields) {
    if ($object->IsRequired($field) && !$object->NumRealEntries($field)) {
      push (@errors, "<a href=#$field>$field</a> needs an input");
    }
    if ($object->IsRelationship($field)) {
      foreach $link ($object->ListEntries($field)) {
        next unless $link;
        if ($link !~ /^(http|ftp|gopher|news):\/\//) {
          my ($target, $tmp);
          $target = $object->Destination($field);
          ($tmp=$link) =~ s/\.html$//;
          if (!(-f "$filepath/objects/$target/${tmp}.html")) {
            push (@errors,"The value specified for the "
                         ."<a href=#$field>$field</a> field "
                         ."(&quot;$link&quot;) is neither "
                         ."a valid url nor the name of a file that exists "
                         ."in this repository's <a "
                         ."href=browse_objects.pl?class=$target>"
                         ."$target "
                         ."directory</a>.");
          } else {
            my $oldlink = $link;
            $link = $link.".html" unless $link =~ /\.html$/;
            my $newlink = $urlpath . "/objects/$target/$link";
            $object->ReplaceEntry($field, $oldlink, $newlink);
          }
        }
      }
    }
  }

  if (!@errors) {
    umask 002;
    # now write the file
    unless (open (NEWOBJECT, ">$filepath/objects/$in{class}/$filename.html")) {
      $util->ErrorMessage("Couldn't write to the file "
       . "$filepath/objects/$in{class}/$filename.html"
       . "<br>Reason : $!<p>This $in{class} description file cannot be saved"
       . " until this problem is resolved.");
    }
    select NEWOBJECT;
  
    my @names = $object->ListEntries("Name");
    print "<head><title>$names[0]</title>\n";
    foreach $field (sort @allfields) {
      foreach $entry ($object->ListEntries($field)) {
        next unless $entry =~ /\S/m;
        $entry =~ s/\n+/ /sg;
        if ($object->IsAttribute($field)) {
          print "<META name=\"BIDM.$in{class}.$field\" ";
          print "content=\"" . HTML::Entities::encode($entry) . "\">\n";
        } else {
          print "<LINK rel=\"BIDM.$in{class}.$field."
              . $object->Destination($field) . "\" ";
          print "href=\"" . HTML::Entities::encode($entry) . "\">\n";
        }
      }
    }
    print "</head><body>";
    print "<h1>$in{class} description file for $names[0]";
    print "</h1><p><hr><p>\n";
    print "<strong>Contents of this $in{class} file:</strong><p>\n";
    print "<center>\n";
    print "<table border=1>\n";
    print "<tr>\n";
    print "<th>Field Name</th>\n";
    print "<th>Value</th>\n";
    print "<th>HTML Tag Type</th>\n";
    print "</tr>\n";
    foreach $field (sort @allfields) {
      foreach $entry ($object->ListEntries($field)) {
        next unless $entry =~ /\S/m;
        print "<tr>\n";
        print "<td>BIDM.$in{class}.$field";
        if ($object->IsRelationship($field)) {
          print "." , $object->Destination($field);
        }
        print "</td>\n";
        print "<td>";
        $entry =~ s/\n/ /gm;
        my $encoded = HTML::Entities::encode($entry);
        if ($object->IsAttribute($field)) {
          if ($object->DataType($field) eq 'email') {
            print "<a href=\"mailto:$entry\">$encoded</a>";
          }
          elsif ($object->DataType($field) eq 'url') {
            print "<a href=\"$entry\">$encoded</a>";
          }
          else {
            print $encoded;
          }
        } else {
          print "<a href=\"$entry\">$encoded</a>";
        }
        print "</td>\n";
        if ($object->IsAttribute($field)) {
          print "<td align=center>META</td>\n";
        } else {
          print "<td align=center>LINK</td>\n";
        }
        print "</tr>\n";
      }
    }
    print "</table></center></body>\n";
    close (NEWOBJECT);
    select (STDOUT);

    # Create the catalog description as well
    #
    my $buf;
    if(!$object->AsHtml(\$buf,$repository,"$filename.html",$cp)){
	$util->ErrorMessage("There were problems creating the catalog"
	. "description file for $filename."
	. "<br>Reason : ". $object->ErrorMsg 
	. "<p>This $in{class} description file cannot be saved"
	. " until this problem is resolved.");

    } else {
        my $pagepath = $util->GetRibDir."/repositories/$repository/catalog/$in{class}/$filename.html";
        unless (open (PAGE,">$pagepath")) {
	    $util->ErrorMessage("Couldn't write to the file "
	    . "$filepath/objects/$in{class}/$filename.html"
	    . "<br>Reason : $!<p>This $in{class} description file cannot "
	    . "be saved until this problem is resolved.");
        }
        print PAGE $util->ClassHeader($in{class});
        print PAGE $buf;
        print PAGE $util->ClassFooter($in{class});
        close(PAGE);
    }
    $buf = '';

    select (STDOUT);
    print "The $in{class} description file named <strong>$filename</strong> ";
    print " was successfully ";
    $overwrite ? print "updated.\n" : print "created.\n";
    if ($in{class} eq 'Asset' && -f "$filepath/catalog/index.html") {
      print "<p>Note that this new Asset will not appear in this\n";
      print "repository's <a href=\"", $util->GetRibUrl(),
            "/repositories/$repository/catalog/index.html\">",
            "software catalog</a> until it has been regenerated.<p>\n";
      print "Click <a href=\"generate_catalog.pl\">here</a> to update the software ";
      print "catalog for this repository.\n";
    }
    print $back_to_top;
    print "<a href=\"create_object_choices.pl?class=$in{class}\">\n";
    print "<p>Create another new $in{class} for this repository</a>\n";
    print "</body>\n";
    exit;
  }
}

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


if (@errors) {
  print "Please correct the following error(s) :\n";
  print "<ul>\n";
  foreach $error (@errors) {
    print "<li>$error\n";
  }
  print "</ul>\n";
  print "After making these changes in the form below please try your ";
  print "submission again.\n<p><hr><p>\n";
}
else {
  print "To create a new $in{class} description file please ";
  print "fill out this form and press the button at the bottom ";
  print "this page.\n";
  print "<p><hr><p>\n";
}


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

if (!$in{create}) {  # if they botched a submission then don't do this
  # if they wanted to add or delete a field then do it here
  foreach $key (keys %in) {
    next if $key eq "filename";
    next if $key eq "repository";
    next if $key eq "class";
    if ($in{$key} eq "delete") {
      $object->RemoveLastEntry($key);
      print "<a href=#$key>Deleted a field from $key</a><br>\n";
    } elsif ($in{$key} eq "add") {
      $object->AddEntry($key,"");
      print "<a href=#$key>Added a field for $key</a><br>\n";
    }
  }
}

# make a dummy entry for fields that are required
# and that are currently empty
foreach $field (@allfields) {
  #if ($object->IsRequired($field) && !$object->NumEntries($field)) {
  if (!$object->NumEntries($field)) {
    $object->AddEntry($field,"");
  }
}

print "<center>\n";
print "<form method=post action=create_object.pl>\n";
print "<input type=hidden name=class value=$in{class}>\n";

foreach $field (sort @allfields) {

  $radio_flag = 0;

  print "<a name=$field></a>";
  print "<table border=5 width=100%>\n";
  print "<tr bgcolor=#FFFFFF>\n";
  print "<td colspan=4 align=center>";
  print "<strong><font size=+2>";
  print "<a href=describe_field.pl?";
  print "field=$field&class=$in{class}>";
  print "$field";
  if ($object->IsRelationship($field)) {
    print " ", $object->Destination($field);
  }
  print "</a></font></strong>";

  if ($object->IsRequired($field)) {
    print " <strong>(required ";
  } else {
    print " <strong>(optional ";
  }
  if ($object->IsRelationship($field)) {
    print "relationship)</strong>";
  } else {
    print "attribute)</strong>";
  }
  print "</td>\n";
  print "</tr>\n";
  if ($object->IsRelationship($field)) {
    my $target = $object->Destination($field);
    print "<tr bgcolor=#FFFFFF>";
    print "<td align=center colspan=2>\n";
    print "<a href=browse_objects.pl?class=$target>";
    print "Browse</a>\n";
    print "</td>\n";
    print "<td align=center colspan=2>\n";
    print " <a href=create_object_choices.pl?class=$target>";
    print "Create</a> ";
    print "</td>\n";
    print "</tr>\n";
  }

  print "<tr bgcolor=#FFFFFF>";
  print "<td align=center>&nbsp;";
  ### allow addtion of an input box when the field is multiple
  ### or (not xor) when field is currently empty and not required
  if (     $object->IsMultiple($field)
      || (!$object->NumEntries($field) && !$object->IsRequired($field)) ) {
    print "<input type=radio name=$field value=add> Add a Field\n";
    $radio_flag = 1;
  }
  print "</td>";

  print "<td align=center>&nbsp;";
  ### allow the last box on the current form to be deleted when
  ### the field already has more than one entry or (not xor)
  ### when the field is optional and cueently empty
  if (  ($object->NumEntries($field) > 1)
     || (!$object->IsRequired($field) && $object->NumEntries($field) > 1) ) {
    print "<input type=radio name=$field value=delete> Delete last Field\n";
    $radio_flag = 1;
  }
  print "</td>";

  ### print a radio button which can be used to deselect the
  ### other radio buttons.  This is a hack to get around the
  ### the fact that with Netscape you can't deselect a clicked
  ### radio button
  print "<td align=center>&nbsp;";
  if ($radio_flag) {
    print "<input type=radio name=$field value=> Cancel\n";
  }
  print "</td>";

  ### return this button only if needed
  print "<td align=center>&nbsp;";
  if ($radio_flag) {
    print "<input type=submit value=\"Update form\">\n";
  }
  print "</td>";
  print "</tr>\n";

  ### print input boxes for existing fields
  foreach $entry ($object->ListEntries($field)) {
    print "<tr bgcolor=#FFFFFF>\n";
    print "<td colspan=4 align=center>\n";
    print HtmlInputBox($repository,$object,$field,$entry);

    print "</td>\n";
    print "</tr>\n";
  }

  print "</table>\n";
  print "<p><br><p>\n";
}
print "<p><hr><p>\n";
print "The filename for this $in{class} description file\n";
print "should contain only alphanumeric (0-9, A-Z, a-z), dash ( - ),\n";
print "underscore ( _ ), and dot ( . )  characters and should not \n";
print "contain any spaces.  If the filename already exists in \n";
print "<a href=browse_objects.pl?class=$in{class}>";
print "this repository's $in{class} directory</a> then that file\n";
print "will not be overwritten unless the &quot;Overwrite&quot; checkbox ";
print "is  checked.\n<p>";
print "<a name=filename></a>\n";
print "<strong><font size=+2>Filename:</font></strong>\n";
print "<input size=30 name=filename value=$in{filename}>";
print "<input type=checkbox name=overwrite ";
if ($in{overwrite} && $in{filename}) { 
  print "checked";
}
print " value=1>Overwrite<p>\n";
print "<p><i>Note: the filename that you specify will be automatically "
      . "appended with the extension &quot;.html&quot; when RIB saves "
      . "the file in its objects directory</i>.";


print "<hr><p>\n";
# next checkbox MUST be reset between every submission.  if it wasn't
# then trying to update the form would cause the form to be submitted
# for creation
print "<table><tr>\n";
print "<td><input type=checkbox name=create value=1></td> ";
print "<td align=left><input type=submit value=\"&lt;--Check that box and then click here ";
print "to create this $in{class} description file\"></td>";
print "</tr></table>\n";
print "</form>\n";
print "</center>\n";

print $back_to_top;

# return a string containing the html for an input box.
# the type of box depends on the data type of the field.
# if the field is a domain then present a list of choices
# for that field
sub HtmlInputBox {
  my $repository = shift;
  my $object = shift;
  my $field = shift;
  my $value = shift;

  # in order to allow fields to have more than one
  # entry in the html form, the name of the field must
  # be prepended with a sequence number.  this keeps
  # fields with multiple entries from trying to use
  # the same variable name to describe all of their fields.
  # For example,
  # if there are two "Domain" fields for this object
  # then the html form would need to call the first
  # "1Domain" and the second "2Domain".
  # Of course this means that the config file for this
  # site can't attempt to start attribute or relationship
  # names with a digit.
  $fieldcount{$field}++;

  # if the field is 'Domain' then present a list of choices from
  # the repository's domains.html file, if possible
  if ($field eq 'Domain') {
    local ($options);
    #cache this repository's domains in @domains (must remain global)
    unless (@domains) {
      # try to use the repository's domains.html file to present
      # a list of choices for this field.
      my $file = RIB::Util::GetRibDir() . "/repositories/" . $repository
               . "/conf/domains.html";
      my $p = RIB::DomainParser->new();
      eval { $p->parse_file($file) };
      @domains = $p->list() unless $@;
    }
    foreach $entry (@domains) {
      $options .= "<option";
      if ($entry eq $value) {
        $options .= " selected";
      }
      $options .= ">$entry\n";
    }
    # if domains were successfully gotten then return, else proceed
    if ($options) {
      return "<select name=$fieldcount{$field}Domain>\n"
           . $options . "</select><br>\n";
    }
  } elsif ($field eq 'DateOfInformation' && !$value) {
    my $date = $util->Date();
    return "<input size=30 name=$fieldcount{$field}$field "
         . "value=\"$date\">";
  } elsif ($object->DataType($field) eq 'string'
            or $object->DataType($field) eq 'url'
            or $object->DataType($field) eq 'email') {
    return "<input size=60 name=$fieldcount{$field}$field "
         . "value=\"$value\">";
  } elsif ($object->DataType($field) eq 'date') {
    return "<input size=30 name=$fieldcount{$field}$field "
         . "value=\"$value\">";
  } elsif ($object->IsRelationship($field)) {
    return "<input size=70 name=$fieldcount{$field}$field "
         . "value=\"$value\">";
  } else {
    return "<textarea cols=60 rows=8 " .
           "name=$fieldcount{$field}$field>$value</textarea>";
  }
}
